-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(codex-ui): popup and confirm implementation #254
base: main
Are you sure you want to change the base?
Changes from 18 commits
0eaaafd
030c3a0
7db5988
8a17f3e
524df3c
c7a1a82
36c01de
246848f
56a0795
3e3d8c3
243279a
aa750f4
9ab7986
8ed65a1
3b27cf0
bdd791c
0aea846
74d557f
e5efa9a
baea337
382694b
1a8764f
01a94ee
3f2bb38
1da8277
9698e0a
87fac03
6d1fcba
8ef117c
c85ec65
bffc40a
7e49c70
97dae48
ee91e7c
28bd1c3
fb7215f
34ef9e1
84d5273
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<template> | ||
<PageHeader> | ||
Popup | ||
<template #description> | ||
A component that appears on top of other components. Can include any other component. | ||
</template> | ||
</PageHeader> | ||
<Button | ||
secondary | ||
data-dimensions="large" | ||
@click="show()" | ||
> | ||
Press here to open popup | ||
</Button> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import PageHeader from '../../components/PageHeader.vue'; | ||
import { Button, Confirm, usePopup } from '../../../src/vue'; | ||
|
||
function onCancelFunction(): void { | ||
// eslint-disable-next-line no-console | ||
console.log('The cancel button was pressed'); | ||
} | ||
|
||
function onConfirmFunction(): void { | ||
// eslint-disable-next-line no-console | ||
console.log('The confirm button was pressed'); | ||
} | ||
|
||
const { showPopup } = usePopup(); | ||
|
||
function show() { | ||
showPopup({ | ||
component: Confirm, | ||
props: { | ||
title: 'CodeX', | ||
body: 'Are you sure you want to delete the page?', | ||
onCancel: onCancelFunction, | ||
onConfirm: onConfirmFunction, | ||
}, | ||
}); | ||
} | ||
|
||
</script> | ||
|
||
<style scoped> | ||
</style> |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,93 @@ | ||||||
<template> | ||||||
<div | ||||||
:class="$style['confirm']" | ||||||
data-dimensions="large" | ||||||
> | ||||||
<div :class="['text-ui-base-bold']"> | ||||||
TatianaFomina marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
{{ title }} | ||||||
</div> | ||||||
<div :class="[$style['confirm__body'], 'text-ui-base-medium']"> | ||||||
{{ body }} | ||||||
</div> | ||||||
<div :class="$style['confirm__controls']"> | ||||||
<Button | ||||||
secondary | ||||||
@click="onCancel" | ||||||
> | ||||||
<div :class="$style['confirm__button-inner']"> | ||||||
Cancel | ||||||
TatianaFomina marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
</div> | ||||||
</Button> | ||||||
<Button | ||||||
primary | ||||||
@click="onConfirm" | ||||||
neSpecc marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
> | ||||||
<div :class="$style['confirm__button-inner']"> | ||||||
{{ confirmButton }} | ||||||
</div> | ||||||
</Button> | ||||||
</div> | ||||||
</div> | ||||||
</template> | ||||||
|
||||||
<script setup lang="ts"> | ||||||
import Button from '../button/Button.vue'; | ||||||
|
||||||
withDefaults( | ||||||
defineProps<{ | ||||||
/** | ||||||
* Text that will be displayed at the top of comfirm container | ||||||
*/ | ||||||
title: string; | ||||||
|
||||||
/** | ||||||
* Text that will be displayed in the middle part of the confirm container | ||||||
*/ | ||||||
body: string; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
/** | ||||||
* Text that will be displayed in the confirm button | ||||||
*/ | ||||||
confirmButton?: string; | ||||||
neSpecc marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
/** | ||||||
* The function that is called when click on the cancel button | ||||||
*/ | ||||||
onCancel: () => void; | ||||||
|
||||||
/** | ||||||
* The function that is called when click on the confirm button | ||||||
*/ | ||||||
onConfirm: () => void; | ||||||
}>(), | ||||||
{ | ||||||
confirmButton: 'Confirm', | ||||||
} | ||||||
); | ||||||
</script> | ||||||
|
||||||
<style module> | ||||||
.confirm { | ||||||
display: flex; | ||||||
flex-direction: column; | ||||||
gap: var(--v-padding); | ||||||
text-align: center; | ||||||
width: min-content; | ||||||
|
||||||
&__body { | ||||||
padding: 0 var(--spacing-ml) 0 var(--spacing-ml); | ||||||
word-wrap: break-word; | ||||||
} | ||||||
|
||||||
&__controls { | ||||||
display: flex; | ||||||
padding: var(--v-padding) 0 0 0; | ||||||
gap: var(--spacing-m); | ||||||
} | ||||||
|
||||||
&__button-inner { | ||||||
width: 84px; | ||||||
} | ||||||
} | ||||||
|
||||||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import type { Component } from 'vue'; | ||
|
||
export interface PopupContent { | ||
/** | ||
* Component to render in the popup | ||
*/ | ||
component: Component; | ||
|
||
/** | ||
* Props to pass to the component | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
props: Record<string, any>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
<template> | ||
<div | ||
v-show="isActive" | ||
:class="$style['popup']" | ||
> | ||
neSpecc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<div :class="$style['popup__container']"> | ||
<component | ||
:is="content.component" | ||
v-if="content" | ||
v-bind="content.props" | ||
/> | ||
</div> | ||
<Icon | ||
v-if="hasCloseButton" | ||
:class="$style['popup__icon']" | ||
name="Cross" | ||
@click="hidePopup" | ||
/> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import Icon from '../icon/Icon.vue'; | ||
import { usePopup } from './usePopup'; | ||
|
||
const { | ||
isActive, | ||
hidePopup, | ||
content, | ||
} = usePopup(); | ||
|
||
withDefaults( | ||
defineProps<{ | ||
/** | ||
* If true, a button to close the popup appears | ||
*/ | ||
hasCloseButton?: boolean; | ||
}>(), | ||
{ | ||
hasCloseButton: true, | ||
} | ||
); | ||
|
||
</script> | ||
|
||
<style module> | ||
|
||
.popup { | ||
z-index: var(--z-popover); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets a separate variable in |
||
inset: 0; | ||
display: grid; | ||
grid-template-columns: auto auto; | ||
position: fixed; | ||
align-content: center; | ||
gap: var(--spacing-l); | ||
justify-content: center; | ||
align-items: start; | ||
background-color: rgba(0, 0, 0, 0.49); | ||
align-items: baseline; | ||
color: var(--base--text); | ||
|
||
&__container { | ||
gap: var(--spacing-ml); | ||
padding: var(--spacing-l); | ||
border-radius: var(--radius-ml); | ||
background-color: var(--base--bg-primary); | ||
box-shadow: inset 0 0 0 var(--delimiter-height) var(--base--border); | ||
} | ||
|
||
&__icon { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, please add hover to it. (Making icon and border color of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
cursor: pointer; | ||
color: var(--base--text-secondary); | ||
padding: var(--spacing-very-x); | ||
box-shadow: inset 0 0 0 var(--delimiter-height); | ||
border-radius: var(--radius-l); | ||
} | ||
} | ||
|
||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Popup from './Popup.vue'; | ||
import Confirm from './Confirm.vue'; | ||
export * from './usePopup'; | ||
export * from './Popup.types'; | ||
|
||
export { Popup, Confirm }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { createSharedComposable } from '@vueuse/core'; | ||
import { ref, shallowRef } from 'vue'; | ||
import type { PopupContent } from './Popup.types'; | ||
|
||
export const usePopup = createSharedComposable(() => { | ||
/** | ||
* Popup active state | ||
*/ | ||
const isActive = ref(false); | ||
neSpecc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Popup content: component and props | ||
*/ | ||
const content = shallowRef<PopupContent | null>(null); | ||
|
||
/** | ||
* Method for attaching a component to the popup | ||
* @param component - component to attach | ||
* @param props - props to pass to the component | ||
*/ | ||
function mountComponent(component: PopupContent['component'], props: PopupContent['props']): void { | ||
content.value = { | ||
component, | ||
props, | ||
}; | ||
} | ||
|
||
/** | ||
* Show popup | ||
*/ | ||
function show(): void { | ||
isActive.value = true; | ||
} | ||
|
||
/** | ||
* Mount component into popup and show it | ||
* @param params - popup showing configuration | ||
*/ | ||
function showPopup(params: PopupContent): void { | ||
mountComponent(params.component, params.props); | ||
show(); | ||
} | ||
|
||
/** | ||
* Сlear the content inside the popup and hide popup | ||
*/ | ||
function hidePopup(): void { | ||
content.value = null; | ||
isActive.value = false; | ||
} | ||
|
||
return { | ||
isActive, | ||
showPopup, | ||
hidePopup, | ||
content, | ||
}; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also create a
useConfirm()
composable? It will be a preset using Popup + Confirm. It will simplify end usage.Also, it is useful if "confirm" will return a promise.
Example: