diff --git a/new-client/package.json b/new-client/package.json
index 8844c1a..36da842 100644
--- a/new-client/package.json
+++ b/new-client/package.json
@@ -20,6 +20,7 @@
"@vueuse/core": "^14.3.0",
"@zag-js/avatar": "^1.40.0",
"@zag-js/collapsible": "^1.40.0",
+ "@zag-js/dialog": "^1.41.1",
"@zag-js/file-upload": "^1.41.0",
"@zag-js/file-utils": "^1.40.0",
"@zag-js/password-input": "^1.40.0",
diff --git a/new-client/src/app/App.vue b/new-client/src/app/App.vue
index dd6b837..bc71cd1 100644
--- a/new-client/src/app/App.vue
+++ b/new-client/src/app/App.vue
@@ -2,9 +2,12 @@
+
+
diff --git a/new-client/src/shared/components/ui/Button.vue b/new-client/src/shared/components/ui/Button.vue
index f648ff3..aaf7147 100644
--- a/new-client/src/shared/components/ui/Button.vue
+++ b/new-client/src/shared/components/ui/Button.vue
@@ -3,6 +3,7 @@
:class="[
bem.b(),
bem.exp(!!type, bem.m(type!)),
+ bem.is('icon-only', iconOnly),
bem.is('loading', loading),
bem.is('disabled', disabled),
bem.is('full', full),
@@ -26,12 +27,13 @@
import type { Component } from 'vue'
import ChadSpinner from '@shared/components/ui/Spinner.vue'
import useBem from '@shared/composables/use-bem.ts'
+import { computed, useSlots } from 'vue'
defineOptions({
name: 'ChadButton',
})
-withDefaults(
+const props = withDefaults(
defineProps(),
{
nativeType: 'button',
@@ -47,7 +49,12 @@ export interface ChadButtonProps {
full?: boolean
}
+const slots = useSlots()
const bem = useBem('chad-button')
+
+const iconOnly = computed(() => {
+ return !slots.default && props.icon
+})
diff --git a/new-client/src/shared/components/ui/DialogContainer.vue b/new-client/src/shared/components/ui/DialogContainer.vue
new file mode 100644
index 0000000..89f3d4d
--- /dev/null
+++ b/new-client/src/shared/components/ui/DialogContainer.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/new-client/src/shared/composables/use-dialog.ts b/new-client/src/shared/composables/use-dialog.ts
new file mode 100644
index 0000000..f2f185b
--- /dev/null
+++ b/new-client/src/shared/composables/use-dialog.ts
@@ -0,0 +1,69 @@
+import type { Component, ComponentInternalInstance } from 'vue'
+import { createGlobalState } from '@vueuse/core'
+import { mergeProps, shallowReactive } from 'vue'
+
+type ComponentAttrs = Record
+
+export interface UseDialogOptions {
+ id: string
+ component: Component
+ attrs?: ComponentAttrs
+ slots?: Record
+}
+
+export const useDialogManager = createGlobalState(() => {
+ const dialogs = shallowReactive([])
+ const instances = shallowReactive([])
+
+ function close(id: UseDialogOptions['id']) {
+ const instance = instances.find(instance => instance.props.id === id)
+
+ if (!instance?.exposed?.close || typeof instance.exposed.close !== 'function')
+ return
+
+ instance.exposed.close()
+ }
+
+ function closeAll() {
+ for (const dialog of dialogs) {
+ close(dialog.id)
+ }
+ }
+
+ return {
+ dialogs,
+ instances,
+ close,
+ closeAll,
+ }
+})
+
+export function useDialog(options: UseDialogOptions) {
+ const manager = useDialogManager()
+
+ const initialAttrs = mergeProps(options.attrs ?? {}, {
+ onClosed: () => {
+ const index = manager.dialogs.findIndex(dialog => options.id === dialog.id)
+
+ if (index === -1)
+ return
+
+ manager.dialogs.splice(index, 1)
+ },
+ })
+
+ function open(openAttrs?: ComponentAttrs) {
+ const attrs = mergeProps(initialAttrs, openAttrs ?? {})
+
+ manager.dialogs.push({ ...options, attrs })
+ }
+
+ function close() {
+ manager.close(options.id)
+ }
+
+ return {
+ open,
+ close,
+ }
+}
diff --git a/new-client/src/shared/layouts/Default.vue b/new-client/src/shared/layouts/Default.vue
index 9822d22..3baee23 100644
--- a/new-client/src/shared/layouts/Default.vue
+++ b/new-client/src/shared/layouts/Default.vue
@@ -36,6 +36,10 @@
+
+
+ Create channel
+
@@ -46,12 +50,15 @@