diff --git a/codex-ui/dev/Playground.vue b/codex-ui/dev/Playground.vue index 5c4d86d6..ef54a664 100644 --- a/codex-ui/dev/Playground.vue +++ b/codex-ui/dev/Playground.vue @@ -30,6 +30,7 @@ + @@ -38,8 +39,10 @@ import { computed } from 'vue'; import { VerticalMenu, Tabbar, - Popover + Popover, + AlertContainer } from '../src/vue'; + import { useTheme } from '../src/vue/composables/useTheme'; import { useRouter, useRoute } from 'vue-router'; @@ -197,6 +200,12 @@ const pages = computed(() => [ onActivate: () => router.push('/components/editor'), isActive: route.path === '/components/editor', }, + + { + title: 'Alert', + onActivate: () => router.push('/components/alert'), + isActive: route.path === '/components/alert', + }, ], }, ]); @@ -206,7 +215,7 @@ const pages = computed(() => [ .playground { background-color: var(--base--bg-primary); color: var(--base--text); - min-height: 100%; + min-height: 100vh; } .header { display: grid; diff --git a/codex-ui/dev/pages/components/Alert.vue b/codex-ui/dev/pages/components/Alert.vue new file mode 100644 index 00000000..d404ec41 --- /dev/null +++ b/codex-ui/dev/pages/components/Alert.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/codex-ui/dev/routes.ts b/codex-ui/dev/routes.ts index 0ab61454..af8dfbf0 100644 --- a/codex-ui/dev/routes.ts +++ b/codex-ui/dev/routes.ts @@ -28,6 +28,7 @@ import VerticalMenu from './pages/components/VerticalMenu.vue'; import ContextMenu from './pages/components/ContextMenu.vue'; import Editor from './pages/components/Editor.vue'; import ThemePreview from './pages/components/ThemePreview.vue'; +import Alert from './pages/components/Alert.vue'; /** * Vue router routes list @@ -145,6 +146,11 @@ const routes: RouteRecordRaw[] = [ path: '/components/theme-preview', component: ThemePreview as Component, }, + + { + path: '/components/alert', + component: Alert as Component, + }, ]; export default routes; diff --git a/codex-ui/src/styles/z-axis.pcss b/codex-ui/src/styles/z-axis.pcss index 0e7ac9c8..19998842 100644 --- a/codex-ui/src/styles/z-axis.pcss +++ b/codex-ui/src/styles/z-axis.pcss @@ -1,3 +1,4 @@ :root { --z-popover: 3; + --z-alert: calc(var(--z-popover) + 1) } diff --git a/codex-ui/src/vue/components/alert/Alert.types.ts b/codex-ui/src/vue/components/alert/Alert.types.ts new file mode 100644 index 00000000..ba388ecc --- /dev/null +++ b/codex-ui/src/vue/components/alert/Alert.types.ts @@ -0,0 +1,35 @@ +/** + * Various alert type + */ +export type AlerType = 'success' | 'error' | 'warning' | 'info' | 'default'; + +/** + * alert configuration + */ +export interface AlertOptions { + /** unique alert id */ + id?: string; + + /** + * Custom icon class to be used. + * + */ + icon?: string; + + /** + * content to be rendered + */ + message: string; + + /** + * Type of the alert. + * + * Can be any of `(success, error, default, info, warning)` + */ + type?: AlerType; + + /** + * How many milliseconds for the alert to be auto dismissed + */ + timeout?: number; +} diff --git a/codex-ui/src/vue/components/alert/Alert.vue b/codex-ui/src/vue/components/alert/Alert.vue new file mode 100644 index 00000000..7e7d3822 --- /dev/null +++ b/codex-ui/src/vue/components/alert/Alert.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/codex-ui/src/vue/components/alert/AlertContainer.vue b/codex-ui/src/vue/components/alert/AlertContainer.vue new file mode 100644 index 00000000..486c0706 --- /dev/null +++ b/codex-ui/src/vue/components/alert/AlertContainer.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/codex-ui/src/vue/components/alert/AlertTransition.vue b/codex-ui/src/vue/components/alert/AlertTransition.vue new file mode 100644 index 00000000..532283e0 --- /dev/null +++ b/codex-ui/src/vue/components/alert/AlertTransition.vue @@ -0,0 +1,25 @@ + + + diff --git a/codex-ui/src/vue/components/alert/index.ts b/codex-ui/src/vue/components/alert/index.ts new file mode 100644 index 00000000..fa424b41 --- /dev/null +++ b/codex-ui/src/vue/components/alert/index.ts @@ -0,0 +1,5 @@ +import { useAlert } from './useAlert'; +import AlertContainer from './AlertContainer.vue'; + +export * from './Alert.types.js'; +export { AlertContainer, useAlert }; diff --git a/codex-ui/src/vue/components/alert/useAlert.ts b/codex-ui/src/vue/components/alert/useAlert.ts new file mode 100644 index 00000000..03be127a --- /dev/null +++ b/codex-ui/src/vue/components/alert/useAlert.ts @@ -0,0 +1,77 @@ +import type { Ref } from 'vue'; +import { ref } from 'vue'; +import { createSharedComposable } from '@vueuse/core'; +import type { AlertOptions, AlerType } from './Alert.types'; + +/** + * Return values of useAlert composable + */ +export interface UseAlertComposableState { + + /** + * Iterated store of alerts + */ + alerts: Ref; + + /** + * trigger success alert + * @param opt - alert options + */ + success: (opt: Pick) => void; + + /** + * trigger error alert + * @param opt - alert options + */ + error: (opt: Pick) => void; + + /** + * trigger warning alert + * @param opt - alert options + */ + warning: (opt: Pick) => void; + + /** + * trigger info alert + * @param opt - alert options + */ + info: (opt: Pick) => void; + + /** + * trigger default alert + * @param opt - alert options + */ + alert: (opt: Pick) => void; +} + +/** + * Alert service composable hook + */ +export const useAlert = createSharedComposable((): UseAlertComposableState => { + const alerts = ref([]); + + /** + * Trigger alert component + * @param type alert type (success, error, warning, info and default) + * @param opt alert options(timeout, message and icon) + */ + function triggerAlert(type: AlerType, opt: AlertOptions): void { + let alertIndex = alerts.value.findIndex((idx: AlertOptions) => idx.id === opt.id); + + alerts.value.push({ type, + ...opt }); + + setTimeout(() => { + alerts.value.splice(alertIndex, alerts.value.shift() as unknown as number); + }, opt?.timeout); + } + + return { + alerts, + success: (opt: Omit) => triggerAlert('success', opt), + error: (opt: Omit) => triggerAlert('error', opt), + warning: (opt: Omit) => triggerAlert('warning', opt), + info: (opt: Omit) => triggerAlert('info', opt), + alert: (opt: Omit) => triggerAlert('default', opt), + }; +}); diff --git a/codex-ui/src/vue/components/button/Button.vue b/codex-ui/src/vue/components/button/Button.vue index 82e88d02..3c9a142b 100644 --- a/codex-ui/src/vue/components/button/Button.vue +++ b/codex-ui/src/vue/components/button/Button.vue @@ -34,7 +34,7 @@ const props = withDefaults( secondary?: boolean; /** - * Pass this attribue for negative actions + * Pass this attribute for negative actions */ destructive?: boolean; diff --git a/codex-ui/src/vue/index.ts b/codex-ui/src/vue/index.ts index 64ae4d4c..a097f258 100644 --- a/codex-ui/src/vue/index.ts +++ b/codex-ui/src/vue/index.ts @@ -1,3 +1,4 @@ +export * from './components/alert'; export * from './components/button'; export * from './components/form'; export * from './components/heading';