Files
Warp/apps/ui/src/components/WDialog.vue
T
tajniak81andClaude Opus 5.5 7e5e38c921 Admin panel (warp-admin) and the apps/ui design system
apps/ui: Warp's design system for Vue 3 + Tailwind v4. Tokens, fonts,
icons and logo come from the brand package, with a Tailwind theme on the
tokens and Vue components on the brand component styles.

apps/admin: the admin panel as a separate, optional service. warp-admin
embeds the built Vue app and proxies only the login endpoints and
/_warp/admin/v1 to the homeserver. Pages: dashboard, users, rooms,
federation, registration and tokens, server notices, application
services, audit log.

Also: pnpm workspace, go.work entry, Dockerfile, an `admin` compose
profile, Makefile targets, a CI job with a proxy smoke test, and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:05:16 +02:00

70 lines
1.6 KiB
Vue

<script setup lang="ts">
import { nextTick, onBeforeUnmount, ref, useId, watch } from 'vue'
import WIconButton from './WIconButton.vue'
// A modal on the native <dialog>: the browser traps focus, closes it on
// Escape and gives focus back to whatever opened it.
const props = withDefaults(
defineProps<{
title: string
/** Wider body for tables and long forms. */
wide?: boolean
/** Keep the dialog open on Escape, e.g. while a request is running. */
persistent?: boolean
}>(),
{ wide: false, persistent: false },
)
const open = defineModel<boolean>('open', { default: false })
const el = ref<HTMLDialogElement>()
const titleId = useId()
watch(
open,
async (value) => {
await nextTick()
const d = el.value
if (!d) return
if (value && !d.open) d.showModal()
if (!value && d.open) d.close()
},
{ immediate: true },
)
function onCancel(e: Event) {
if (props.persistent) e.preventDefault()
else open.value = false
}
function onClose() {
open.value = false
}
onBeforeUnmount(() => {
if (el.value?.open) el.value.close()
})
</script>
<template>
<dialog
ref="el"
class="wp-dialog"
:style="wide ? { maxWidth: '720px' } : undefined"
:aria-labelledby="titleId"
@cancel="onCancel"
@close="onClose"
>
<template v-if="open">
<div class="wp-dialog-head">
<h2 :id="titleId" class="wp-dialog-title">{{ title }}</h2>
<WIconButton icon="close" label="Close" :disabled="persistent" @click="open = false" />
</div>
<slot />
<div v-if="$slots.actions" class="wp-dialog-actions">
<slot name="actions" />
</div>
</template>
</dialog>
</template>