модалочки оп-оп
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
"@vueuse/core": "^14.3.0",
|
"@vueuse/core": "^14.3.0",
|
||||||
"@zag-js/avatar": "^1.40.0",
|
"@zag-js/avatar": "^1.40.0",
|
||||||
"@zag-js/collapsible": "^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-upload": "^1.41.0",
|
||||||
"@zag-js/file-utils": "^1.40.0",
|
"@zag-js/file-utils": "^1.40.0",
|
||||||
"@zag-js/password-input": "^1.40.0",
|
"@zag-js/password-input": "^1.40.0",
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
<Component :is="layoutComponent">
|
<Component :is="layoutComponent">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</Component>
|
</Component>
|
||||||
|
|
||||||
|
<ChadDialogContainer />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import ChadDialogContainer from '@shared/components/ui/DialogContainer.vue'
|
||||||
import DefaultLayout from '@shared/layouts/Default.vue'
|
import DefaultLayout from '@shared/layouts/Default.vue'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|||||||
19
new-client/src/entities/channel/api/mCreateChannel.ts
Normal file
19
new-client/src/entities/channel/api/mCreateChannel.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import type { Channel, CreateChannelPayload, ResponseError } from '@shared/api/generated-chad-api'
|
||||||
|
import api from '@shared/api/client'
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/vue-query'
|
||||||
|
|
||||||
|
export function mCreateChannel() {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return useMutation<Channel, ResponseError, CreateChannelPayload, Channel>({
|
||||||
|
mutationFn: async (payload) => {
|
||||||
|
const response = await api.chad.channelCreate(payload)
|
||||||
|
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuccess: async () => {
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ['channel-list'] })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
44
new-client/src/entities/channel/ui/CreateChannelDialog.vue
Normal file
44
new-client/src/entities/channel/ui/CreateChannelDialog.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<ChadDialog :id="DIALOG_ID" title="Create channel">
|
||||||
|
<ChadInput v-model="name" label="Name" />
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<ChadButton style="grid-column: 2" :disabled="!valid" :loading="submitting" @click="submit()">
|
||||||
|
Create
|
||||||
|
</ChadButton>
|
||||||
|
</template>
|
||||||
|
</ChadDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ChadButton from '@shared/components/ui/Button.vue'
|
||||||
|
import ChadDialog from '@shared/components/ui/Dialog.vue'
|
||||||
|
import ChadInput from '@shared/components/ui/Input.vue'
|
||||||
|
import { useDialogManager } from '@shared/composables/use-dialog.ts'
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { mCreateChannel } from '@/entities/channel/api/mCreateChannel.ts'
|
||||||
|
|
||||||
|
const DIALOG_ID = 'create-channel'
|
||||||
|
|
||||||
|
const dialogManager = useDialogManager()
|
||||||
|
|
||||||
|
const { mutateAsync: createChannel, isPending: submitting } = mCreateChannel()
|
||||||
|
|
||||||
|
const name = ref('')
|
||||||
|
|
||||||
|
const valid = computed(() => {
|
||||||
|
return name.value.trim().length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
if (!valid.value)
|
||||||
|
return
|
||||||
|
|
||||||
|
await createChannel({
|
||||||
|
name: name.value,
|
||||||
|
persistent: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
dialogManager.close(DIALOG_ID)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
:class="[
|
:class="[
|
||||||
bem.b(),
|
bem.b(),
|
||||||
bem.exp(!!type, bem.m(type!)),
|
bem.exp(!!type, bem.m(type!)),
|
||||||
|
bem.is('icon-only', iconOnly),
|
||||||
bem.is('loading', loading),
|
bem.is('loading', loading),
|
||||||
bem.is('disabled', disabled),
|
bem.is('disabled', disabled),
|
||||||
bem.is('full', full),
|
bem.is('full', full),
|
||||||
@@ -26,12 +27,13 @@
|
|||||||
import type { Component } from 'vue'
|
import type { Component } from 'vue'
|
||||||
import ChadSpinner from '@shared/components/ui/Spinner.vue'
|
import ChadSpinner from '@shared/components/ui/Spinner.vue'
|
||||||
import useBem from '@shared/composables/use-bem.ts'
|
import useBem from '@shared/composables/use-bem.ts'
|
||||||
|
import { computed, useSlots } from 'vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'ChadButton',
|
name: 'ChadButton',
|
||||||
})
|
})
|
||||||
|
|
||||||
withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<ChadButtonProps>(),
|
defineProps<ChadButtonProps>(),
|
||||||
{
|
{
|
||||||
nativeType: 'button',
|
nativeType: 'button',
|
||||||
@@ -47,7 +49,12 @@ export interface ChadButtonProps {
|
|||||||
full?: boolean
|
full?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const slots = useSlots()
|
||||||
const bem = useBem('chad-button')
|
const bem = useBem('chad-button')
|
||||||
|
|
||||||
|
const iconOnly = computed(() => {
|
||||||
|
return !slots.default && props.icon
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -66,10 +73,15 @@ const bem = useBem('chad-button')
|
|||||||
outline: var(--border-w) solid var(--ink);
|
outline: var(--border-w) solid var(--ink);
|
||||||
outline-offset: calc(var(--border-w) * -1);
|
outline-offset: calc(var(--border-w) * -1);
|
||||||
|
|
||||||
&.is-full {
|
&.is-full:not(.is-icon-only) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-icon-only {
|
||||||
|
padding: 0;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: var(--yellow-deep);
|
background-color: var(--yellow-deep);
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<Component :is="as" class="chad-card">
|
<Component :is="as" class="chad-card">
|
||||||
<p v-if="title" class="chad-card__title">
|
<div v-if="title || description" class="chad-card__header">
|
||||||
{{ title }}
|
<p v-if="title" class="chad-card__title">
|
||||||
</p>
|
{{ title }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p v-if="description" class="chad-card__description">
|
||||||
|
{{ description }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="chad-card__content">
|
<div class="chad-card__content">
|
||||||
<slot />
|
<slot />
|
||||||
@@ -39,6 +45,7 @@ const slots = defineSlots<{
|
|||||||
interface Props {
|
interface Props {
|
||||||
as?: string
|
as?: string
|
||||||
title?: string
|
title?: string
|
||||||
|
description?: string
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -51,13 +58,23 @@ interface Props {
|
|||||||
outline-offset: calc(var(--border-w) * -1);
|
outline-offset: calc(var(--border-w) * -1);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
|
|
||||||
&__title {
|
&__header {
|
||||||
@include font-display-22;
|
|
||||||
|
|
||||||
margin-bottom: var(--space-6);
|
margin-bottom: var(--space-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
@include font-display-22;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
margin-top: var(--space-2);
|
||||||
|
color: var(--grey-3);
|
||||||
|
}
|
||||||
|
|
||||||
&__actions {
|
&__actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: var(--space-3);
|
||||||
margin-top: var(--space-6);
|
margin-top: var(--space-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
169
new-client/src/shared/components/ui/Dialog.vue
Normal file
169
new-client/src/shared/components/ui/Dialog.vue
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<div :class="[bem.b()]">
|
||||||
|
<Transition name="chad-dialog-overlay" appear>
|
||||||
|
<div v-if="api.open" :class="bem.e('overlay')" v-bind="api.getBackdropProps()" />
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
name="chad-dialog-content"
|
||||||
|
appear
|
||||||
|
@after-enter="emit('opened')"
|
||||||
|
@before-leave="emit('beforeClose')"
|
||||||
|
@after-leave="emit('closed')"
|
||||||
|
>
|
||||||
|
<div v-if="api.open" :class="bem.e('positioner')" v-bind="api.getPositionerProps()">
|
||||||
|
<ChadCard
|
||||||
|
:class="bem.e('content')"
|
||||||
|
v-bind="api.getContentProps()"
|
||||||
|
:title="title"
|
||||||
|
:description="description"
|
||||||
|
>
|
||||||
|
<slot v-bind="{ close }" />
|
||||||
|
|
||||||
|
<template v-if="$slots.actions" #actions>
|
||||||
|
<slot name="actions" v-bind="{ close }" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="$slots.bottom" #bottom>
|
||||||
|
<slot name="bottom" v-bind="{ close }" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<ChadButton v-bind="api.getCloseTriggerProps()" :icon="XIcon" :class="bem.e('close')" type="secondary" />
|
||||||
|
</ChadCard>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Props as DialogProps } from '@zag-js/dialog'
|
||||||
|
import { XIcon } from '@lucide/vue'
|
||||||
|
import ChadButton from '@shared/components/ui/Button.vue'
|
||||||
|
import ChadCard from '@shared/components/ui/Card.vue'
|
||||||
|
import useBem from '@shared/composables/use-bem.ts'
|
||||||
|
import { useDialogManager } from '@shared/composables/use-dialog.ts'
|
||||||
|
import { connect, machine } from '@zag-js/dialog'
|
||||||
|
import { normalizeProps, useMachine } from '@zag-js/vue'
|
||||||
|
import { computed, getCurrentInstance, onBeforeUnmount, onMounted } from 'vue'
|
||||||
|
|
||||||
|
export interface ChadDialogProps {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
description?: string
|
||||||
|
closeOnEscape?: boolean
|
||||||
|
closeOnInteractOutside?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'ChadDialog',
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<ChadDialogProps>(),
|
||||||
|
{
|
||||||
|
closeOnEscape: true,
|
||||||
|
closeOnInteractOutside: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
opened: []
|
||||||
|
beforeClose: []
|
||||||
|
closed: []
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const bem = useBem('chad-dialog')
|
||||||
|
|
||||||
|
const service = useMachine(machine, computed(() => {
|
||||||
|
return {
|
||||||
|
id: props.id,
|
||||||
|
defaultOpen: true,
|
||||||
|
closeOnEscape: props.closeOnEscape,
|
||||||
|
closeOnInteractOutside: props.closeOnInteractOutside,
|
||||||
|
} as DialogProps
|
||||||
|
}))
|
||||||
|
const api = computed(() => connect(service, normalizeProps))
|
||||||
|
|
||||||
|
const instance = getCurrentInstance()
|
||||||
|
const manager = useDialogManager()
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
api.value.setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!instance)
|
||||||
|
return
|
||||||
|
|
||||||
|
manager.instances.push(instance)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const index = manager.instances.findIndex(_instance => _instance === instance)
|
||||||
|
|
||||||
|
if (index === -1)
|
||||||
|
return
|
||||||
|
|
||||||
|
manager.instances.splice(index, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
close,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.chad-dialog {
|
||||||
|
&__overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background-color: color-mix(in srgb, var(--ink) 60%, transparent);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__positioner {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
padding: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
width: 560px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close {
|
||||||
|
position: absolute;
|
||||||
|
bottom: calc(100% + var(--space-2));
|
||||||
|
right: 0;
|
||||||
|
//right: var(--space-6);
|
||||||
|
//top: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-overlay-enter-active,
|
||||||
|
&-overlay-leave-active {
|
||||||
|
transition: opacity 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-overlay-enter-from,
|
||||||
|
&-overlay-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content-enter-active,
|
||||||
|
&-content-leave-active {
|
||||||
|
transition: 0.15s ease-out;
|
||||||
|
transition-property: opacity, translate, scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-content-enter-from,
|
||||||
|
&-content-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
scale: 0.99;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
new-client/src/shared/components/ui/DialogContainer.vue
Normal file
17
new-client/src/shared/components/ui/DialogContainer.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<Component :is="dialog.component" v-for="dialog in dialogs" v-bind="dialog.attrs" :id="dialog.id" :key="dialog.id">
|
||||||
|
<template v-for="(slot, key) in dialog.slots" #[key] :key="key">
|
||||||
|
<Component :is="slot" />
|
||||||
|
</template>
|
||||||
|
</Component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDialogManager } from '@shared/composables/use-dialog.ts'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'ChadDialogContainer',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { dialogs } = useDialogManager()
|
||||||
|
</script>
|
||||||
69
new-client/src/shared/composables/use-dialog.ts
Normal file
69
new-client/src/shared/composables/use-dialog.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import type { Component, ComponentInternalInstance } from 'vue'
|
||||||
|
import { createGlobalState } from '@vueuse/core'
|
||||||
|
import { mergeProps, shallowReactive } from 'vue'
|
||||||
|
|
||||||
|
type ComponentAttrs = Record<string, any>
|
||||||
|
|
||||||
|
export interface UseDialogOptions {
|
||||||
|
id: string
|
||||||
|
component: Component
|
||||||
|
attrs?: ComponentAttrs
|
||||||
|
slots?: Record<string, Component>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDialogManager = createGlobalState(() => {
|
||||||
|
const dialogs = shallowReactive<UseDialogOptions[]>([])
|
||||||
|
const instances = shallowReactive<ComponentInternalInstance[]>([])
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,10 @@
|
|||||||
<!-- <ChadButton style="margin: var(--space-2);" @click="logout"> -->
|
<!-- <ChadButton style="margin: var(--space-2);" @click="logout"> -->
|
||||||
<!-- Logout -->
|
<!-- Logout -->
|
||||||
<!-- </ChadButton> -->
|
<!-- </ChadButton> -->
|
||||||
|
|
||||||
|
<ChadButton style="margin: var(--space-2)" type="secondary" @click="createChannelDialog.open()">
|
||||||
|
Create channel
|
||||||
|
</ChadButton>
|
||||||
<ControlPanel />
|
<ControlPanel />
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
@@ -46,12 +50,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import ChadButton from '@shared/components/ui/Button.vue'
|
||||||
import { useApp } from '@shared/composables/use-app.js'
|
import { useApp } from '@shared/composables/use-app.js'
|
||||||
|
import { useDialog } from '@shared/composables/use-dialog.ts'
|
||||||
import { useMediasoup } from '@shared/composables/use-mediasoup.ts'
|
import { useMediasoup } from '@shared/composables/use-mediasoup.ts'
|
||||||
import { useProducers } from '@shared/composables/use-producers.ts'
|
import { useProducers } from '@shared/composables/use-producers.ts'
|
||||||
import ChannelList from '@widgets/channel-list/ui/ChannelList.vue'
|
import ChannelList from '@widgets/channel-list/ui/ChannelList.vue'
|
||||||
import ControlPanel from '@widgets/control-panel/ui/ControlPanel.vue'
|
import ControlPanel from '@widgets/control-panel/ui/ControlPanel.vue'
|
||||||
import { watchEffect } from 'vue'
|
import { watchEffect } from 'vue'
|
||||||
|
import CreateChannelDialog from '@/entities/channel/ui/CreateChannelDialog.vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'DefaultLayout',
|
name: 'DefaultLayout',
|
||||||
@@ -62,6 +69,11 @@ const { version } = useApp()
|
|||||||
const { sendTransport } = useMediasoup()
|
const { sendTransport } = useMediasoup()
|
||||||
const { enableMic } = useProducers()
|
const { enableMic } = useProducers()
|
||||||
|
|
||||||
|
const createChannelDialog = useDialog({
|
||||||
|
id: 'create-channel',
|
||||||
|
component: CreateChannelDialog,
|
||||||
|
})
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (!sendTransport.value)
|
if (!sendTransport.value)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ export function useChatScroll(target: TemplateRef<HTMLElement>, options?: MaybeR
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEventListener(el, 'scroll', () => {
|
useEventListener(el, 'scroll', () => {
|
||||||
console.log('scroll', el.value!.scrollTop)
|
|
||||||
getArrivedState()
|
getArrivedState()
|
||||||
lastScrollTop = el.value!.scrollTop
|
lastScrollTop = el.value!.scrollTop
|
||||||
}, { passive: true })
|
}, { passive: true })
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ async function download() {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.chat-message-attachment {
|
.chat-message-attachment {
|
||||||
|
$self: &;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 52px 1fr;
|
grid-template-columns: 52px 1fr;
|
||||||
outline: var(--border-w) solid var(--ink);
|
outline: var(--border-w) solid var(--ink);
|
||||||
@@ -54,10 +56,15 @@ async function download() {
|
|||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--grey-2);
|
background-color: var(--grey-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--grey-3);
|
||||||
|
}
|
||||||
|
|
||||||
&__extension {
|
&__extension {
|
||||||
@include font-label;
|
@include font-label;
|
||||||
|
|
||||||
@@ -92,6 +99,10 @@ async function download() {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
#{$self}:active & {
|
||||||
|
color: var(--grey-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1205,6 +1205,18 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@zag-js/anatomy/-/anatomy-1.41.0.tgz#af0d132a4470dcea93f857b1a12b6cc9c6d3b847"
|
resolved "https://registry.yarnpkg.com/@zag-js/anatomy/-/anatomy-1.41.0.tgz#af0d132a4470dcea93f857b1a12b6cc9c6d3b847"
|
||||||
integrity sha512-0M/bWcYbWgM09HEhfU0GvpKgPt3I4vakjr21FHcjTNK2vYRC1oz2GHc/y9ArJa4jXe0piTiPbACzMK1/z2ukRw==
|
integrity sha512-0M/bWcYbWgM09HEhfU0GvpKgPt3I4vakjr21FHcjTNK2vYRC1oz2GHc/y9ArJa4jXe0piTiPbACzMK1/z2ukRw==
|
||||||
|
|
||||||
|
"@zag-js/anatomy@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/anatomy/-/anatomy-1.41.1.tgz#9cb2a4c6506fd14bbd3387e523885257ed1e37d9"
|
||||||
|
integrity sha512-wBQVpl8TC9O5AjeJrnmNdJWEUYorTi7iklOcySeXIeaz6D7Y0YY0YbEOSFNsRTpn/NQHwkPejf3i5qkKavNHXw==
|
||||||
|
|
||||||
|
"@zag-js/aria-hidden@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/aria-hidden/-/aria-hidden-1.41.1.tgz#69c7c695c718baaaad4db9ae8ddae1c17d5bbfcb"
|
||||||
|
integrity sha512-+iZ2gG/EygWQRfafcIL9MMgKIP9QCnW8SfxlO71FYEMrexvJyzxyPUxzBn2NfpH+gOogzLrr3lvPTYZu+0kCVQ==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
|
||||||
"@zag-js/avatar@^1.40.0":
|
"@zag-js/avatar@^1.40.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/avatar/-/avatar-1.41.0.tgz#2505e32cba85d815845c7f5c07431e57a1b60d8a"
|
resolved "https://registry.yarnpkg.com/@zag-js/avatar/-/avatar-1.41.0.tgz#2505e32cba85d815845c7f5c07431e57a1b60d8a"
|
||||||
@@ -1235,6 +1247,38 @@
|
|||||||
"@zag-js/dom-query" "1.41.0"
|
"@zag-js/dom-query" "1.41.0"
|
||||||
"@zag-js/utils" "1.41.0"
|
"@zag-js/utils" "1.41.0"
|
||||||
|
|
||||||
|
"@zag-js/core@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/core/-/core-1.41.1.tgz#c348c7b70753ac33967093c02c53d263400619df"
|
||||||
|
integrity sha512-np7Tlf1EUK2ITojiX3aQy79LWIZhu4xxrS6pE8V/wD0h9JeQmhyNtyC147jqIE/AYjSunhMShsWp/+W1b5skjQ==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
"@zag-js/utils" "1.41.1"
|
||||||
|
|
||||||
|
"@zag-js/dialog@^1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/dialog/-/dialog-1.41.1.tgz#12d3e5e341064103184dbfeeb1e77c0f7f0036a6"
|
||||||
|
integrity sha512-+++Ct5Kj2NtAHk1EYHasYPHXm1GfunwE0QKnrtEjUo1yIgKe2NH230JkXKndpiGztxcDpLfkblMuDwot1lNtFw==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/anatomy" "1.41.1"
|
||||||
|
"@zag-js/aria-hidden" "1.41.1"
|
||||||
|
"@zag-js/core" "1.41.1"
|
||||||
|
"@zag-js/dismissable" "1.41.1"
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
"@zag-js/focus-trap" "1.41.1"
|
||||||
|
"@zag-js/remove-scroll" "1.41.1"
|
||||||
|
"@zag-js/types" "1.41.1"
|
||||||
|
"@zag-js/utils" "1.41.1"
|
||||||
|
|
||||||
|
"@zag-js/dismissable@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/dismissable/-/dismissable-1.41.1.tgz#697a1f042f054654d704035581addf3ca77676f2"
|
||||||
|
integrity sha512-nM3j3lz8XaYfW755N+Itp08BVFYhKhjlQ3EiBlc3LYwse4h2K5O3FwK87Ckqd/rBKrAb4eYFCkGNFSvjk0U/8g==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
"@zag-js/interact-outside" "1.41.1"
|
||||||
|
"@zag-js/utils" "1.41.1"
|
||||||
|
|
||||||
"@zag-js/dom-query@1.41.0":
|
"@zag-js/dom-query@1.41.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-1.41.0.tgz#5f434cf6cb6ccf524f479d4597c7b4f5ab3c561c"
|
resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-1.41.0.tgz#5f434cf6cb6ccf524f479d4597c7b4f5ab3c561c"
|
||||||
@@ -1242,6 +1286,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@zag-js/types" "1.41.0"
|
"@zag-js/types" "1.41.0"
|
||||||
|
|
||||||
|
"@zag-js/dom-query@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/dom-query/-/dom-query-1.41.1.tgz#e18b6b7f4b100e48d4c21643def02fb03fff7904"
|
||||||
|
integrity sha512-f6hBV6fPc9Ok/Re/tsxqJ8NcgQzsASQ6YoulUKSQnZMGb7tr0Ks1IH3Hjy3+ARXvCaSjgDhPPXt5+bkieur4eg==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/types" "1.41.1"
|
||||||
|
|
||||||
"@zag-js/file-upload@^1.41.0":
|
"@zag-js/file-upload@^1.41.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/file-upload/-/file-upload-1.41.0.tgz#6ad2deb4d5edc9db1c46fda6823be3a9d404b625"
|
resolved "https://registry.yarnpkg.com/@zag-js/file-upload/-/file-upload-1.41.0.tgz#6ad2deb4d5edc9db1c46fda6823be3a9d404b625"
|
||||||
@@ -1262,6 +1313,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@zag-js/i18n-utils" "1.41.0"
|
"@zag-js/i18n-utils" "1.41.0"
|
||||||
|
|
||||||
|
"@zag-js/focus-trap@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/focus-trap/-/focus-trap-1.41.1.tgz#0ab2427d283da6ed7c04a770dc71a5e865eff534"
|
||||||
|
integrity sha512-+KZpzvo4PQJI2M4GYRVgSEyD+X6Pu+paBS1zGlex0FLK+gzUVU0UnEtA1cSNS2oVMyHuu58mBZyYSCmeuMt5XA==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
|
||||||
"@zag-js/i18n-utils@1.41.0":
|
"@zag-js/i18n-utils@1.41.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/i18n-utils/-/i18n-utils-1.41.0.tgz#da493ffac2482df38668a99d542d85a568516cc4"
|
resolved "https://registry.yarnpkg.com/@zag-js/i18n-utils/-/i18n-utils-1.41.0.tgz#da493ffac2482df38668a99d542d85a568516cc4"
|
||||||
@@ -1269,6 +1327,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@zag-js/dom-query" "1.41.0"
|
"@zag-js/dom-query" "1.41.0"
|
||||||
|
|
||||||
|
"@zag-js/interact-outside@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/interact-outside/-/interact-outside-1.41.1.tgz#ea4caf67b4fa39e64dcd61374cc258ab1b9adf36"
|
||||||
|
integrity sha512-N31jT0bBzCLBtAn31wVFxuxiOnXemNT+lKjK9j5HBZgrqgA/L3RdeV59aZ4Ar02Bb6F6DxU+MImzVvfgra1e6A==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
"@zag-js/utils" "1.41.1"
|
||||||
|
|
||||||
"@zag-js/password-input@^1.40.0":
|
"@zag-js/password-input@^1.40.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/password-input/-/password-input-1.41.0.tgz#c55b8f15170bb5b7a86169623cc2277ec4788e96"
|
resolved "https://registry.yarnpkg.com/@zag-js/password-input/-/password-input-1.41.0.tgz#c55b8f15170bb5b7a86169623cc2277ec4788e96"
|
||||||
@@ -1280,6 +1346,13 @@
|
|||||||
"@zag-js/types" "1.41.0"
|
"@zag-js/types" "1.41.0"
|
||||||
"@zag-js/utils" "1.41.0"
|
"@zag-js/utils" "1.41.0"
|
||||||
|
|
||||||
|
"@zag-js/remove-scroll@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/remove-scroll/-/remove-scroll-1.41.1.tgz#9aac17b2526fafd1f31eee4c508d0f11de381fdd"
|
||||||
|
integrity sha512-OihOx/EDghH4haEnwTsESMa9hUAOyau7hSgJBwu1cio/zozGJ5/umKRGGMe1v6Eh1len3B+iVEpMf65Rp2bSGg==
|
||||||
|
dependencies:
|
||||||
|
"@zag-js/dom-query" "1.41.1"
|
||||||
|
|
||||||
"@zag-js/store@1.41.0":
|
"@zag-js/store@1.41.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/store/-/store-1.41.0.tgz#97a3ecc1bbb5fe8de51083e4dafaa0d0d3c2d741"
|
resolved "https://registry.yarnpkg.com/@zag-js/store/-/store-1.41.0.tgz#97a3ecc1bbb5fe8de51083e4dafaa0d0d3c2d741"
|
||||||
@@ -1305,11 +1378,23 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype "3.2.3"
|
csstype "3.2.3"
|
||||||
|
|
||||||
|
"@zag-js/types@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/types/-/types-1.41.1.tgz#46fb12a0fdf1ce20bdfe128ef66ece6216b677e4"
|
||||||
|
integrity sha512-xhKEX61yvNa/6yofkNe7IihKyt3JLe4/k5JxaH0hj46V4S2Kac2cNAXPgnWHbl1gXGBcfLr+qLFzo4oLl+VdwA==
|
||||||
|
dependencies:
|
||||||
|
csstype "3.2.3"
|
||||||
|
|
||||||
"@zag-js/utils@1.41.0":
|
"@zag-js/utils@1.41.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/utils/-/utils-1.41.0.tgz#61639369aeadf26f91fe009b4ddce926c5ba607c"
|
resolved "https://registry.yarnpkg.com/@zag-js/utils/-/utils-1.41.0.tgz#61639369aeadf26f91fe009b4ddce926c5ba607c"
|
||||||
integrity sha512-WUCIw+W4MYKYfyKad0LLNNqhL58/cRAAAVjLqDch05c1dZ0yhZq3t81jWeYUwiPnprt9V+BtGJEFMnWhdfxsBA==
|
integrity sha512-WUCIw+W4MYKYfyKad0LLNNqhL58/cRAAAVjLqDch05c1dZ0yhZq3t81jWeYUwiPnprt9V+BtGJEFMnWhdfxsBA==
|
||||||
|
|
||||||
|
"@zag-js/utils@1.41.1":
|
||||||
|
version "1.41.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zag-js/utils/-/utils-1.41.1.tgz#248fc28510d625034553fd9a4213147204fca323"
|
||||||
|
integrity sha512-IZGqDpQYvgCQlGcLTVCzWG5DEz318ZLVJhp8TtT9HPDNd+RJTcVHRja7z+vqQ0Su+wKZkuLlIh5gtraxQ+YX9Q==
|
||||||
|
|
||||||
"@zag-js/vue@^1.40.0":
|
"@zag-js/vue@^1.40.0":
|
||||||
version "1.41.0"
|
version "1.41.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zag-js/vue/-/vue-1.41.0.tgz#7e5649c1d5e7979493987de66d25d3deda90976e"
|
resolved "https://registry.yarnpkg.com/@zag-js/vue/-/vue-1.41.0.tgz#7e5649c1d5e7979493987de66d25d3deda90976e"
|
||||||
|
|||||||
Reference in New Issue
Block a user