mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
style(client): unify modal backdrops with dedicated scrim tokens
Replace tinted modal veils with dedicated scrim tokens so dialogs, sheets, and image lightboxes dim consistently in both light and dark themes. Enforce scrim token usage in style validation to prevent backdrops that wash out in dark mode.
This commit is contained in:
@@ -32,6 +32,19 @@ const TUNED_TEXT_TOKENS = [
|
|||||||
// (`hover:`, `placeholder:`, `group-data-[active=true]/item:` and so on).
|
// (`hover:`, `placeholder:`, `group-data-[active=true]/item:` and so on).
|
||||||
const FADED_TEXT_PATTERN = new RegExp(String.raw`(?:[\w[\]=.\-/]+:)*text-(?:${TUNED_TEXT_TOKENS.join('|')})\/\d+`, 'g')
|
const FADED_TEXT_PATTERN = new RegExp(String.raw`(?:[\w[\]=.\-/]+:)*text-(?:${TUNED_TEXT_TOKENS.join('|')})\/\d+`, 'g')
|
||||||
const LEGACY_SETTINGS_BUTTON_PATTERN = /\bsettings-btn-(?:primary|outline|secondary|danger)\b/g
|
const LEGACY_SETTINGS_BUTTON_PATTERN = /\bsettings-btn-(?:primary|outline|secondary|danger)\b/g
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal backdrops take their veil from `bg-scrim`, or `bg-scrim-media` behind image viewers, so
|
||||||
|
* every dialog and sheet dims the page the same way in both themes. A backdrop tinted with a theme
|
||||||
|
* colour inverts in dark mode: `--foreground` is near-white there, so the veil washes the page grey
|
||||||
|
* instead of dimming it. A full-screen layer counts as a backdrop when it is fixed or dismisses on
|
||||||
|
* click; tinted overlays that only decorate a cover or card are left alone.
|
||||||
|
*/
|
||||||
|
const ELEMENT_OPENING_TAG_PATTERN = /<[A-Za-z][\w-]*\b[^<>]*>/g
|
||||||
|
const DIALOG_OVERLAY_TAG_PATTERN = /^<(?:Dialog|AlertDialog)Overlay\b/
|
||||||
|
const SCRIM_CLASS_PATTERN = /\bbg-scrim(?:-media)?\b/
|
||||||
|
const TINTED_BACKDROP_PATTERN = /\bbg-(?:black|white|foreground|background)\/\d+/
|
||||||
|
const BACKDROP_ROLE_PATTERN = /\bfixed\b|@click/
|
||||||
const BUTTON_OPENING_TAG_PATTERN = /<Button\b[\s\S]*?>/g
|
const BUTTON_OPENING_TAG_PATTERN = /<Button\b[\s\S]*?>/g
|
||||||
const DESTRUCTIVE_BUTTON_VARIANT_PATTERN = /\bvariant=["']destructive(?:-outline|-ghost)?["']/
|
const DESTRUCTIVE_BUTTON_VARIANT_PATTERN = /\bvariant=["']destructive(?:-outline|-ghost)?["']/
|
||||||
const DESTRUCTIVE_BUTTON_COLOR_OVERRIDE_PATTERN =
|
const DESTRUCTIVE_BUTTON_COLOR_OVERRIDE_PATTERN =
|
||||||
@@ -74,6 +87,17 @@ for (const file of await sourceFiles(sourceDirectory)) {
|
|||||||
errors.push(`${relativePath}:${line}: destructive Button color override - keep destructive styling centralized in the shared Button variants.`)
|
errors.push(`${relativePath}:${line}: destructive Button color override - keep destructive styling centralized in the shared Button variants.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const match of source.matchAll(ELEMENT_OPENING_TAG_PATTERN)) {
|
||||||
|
const tag = match[0]
|
||||||
|
const isDialogOverlay = DIALOG_OVERLAY_TAG_PATTERN.test(tag)
|
||||||
|
const isTintedBackdrop = /\binset-0\b/.test(tag) && BACKDROP_ROLE_PATTERN.test(tag) && TINTED_BACKDROP_PATTERN.test(tag)
|
||||||
|
if ((!isDialogOverlay || SCRIM_CLASS_PATTERN.test(tag)) && !isTintedBackdrop) continue
|
||||||
|
const line = source.slice(0, match.index).split('\n').length
|
||||||
|
errors.push(
|
||||||
|
`${relativePath}:${line}: modal backdrop - use bg-scrim, or bg-scrim-media behind an image viewer, so it dims the page in both themes.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for (const [index, line] of lines.entries()) {
|
for (const [index, line] of lines.entries()) {
|
||||||
for (const match of line.matchAll(LEGACY_SETTINGS_BUTTON_PATTERN)) {
|
for (const match of line.matchAll(LEGACY_SETTINGS_BUTTON_PATTERN)) {
|
||||||
errors.push(`${relativePath}:${index + 1}: ${match[0]} - use the shared Button component and its variants.`)
|
errors.push(`${relativePath}:${index + 1}: ${match[0]} - use the shared Button component and its variants.`)
|
||||||
@@ -99,4 +123,4 @@ if (errors.length > 0) {
|
|||||||
throw new Error(`Style validation failed:\n${errors.join('\n')}`)
|
throw new Error(`Style validation failed:\n${errors.join('\n')}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Validated style tokens and shared settings buttons')
|
console.log('Validated style tokens, modal backdrops and shared settings buttons')
|
||||||
|
|||||||
@@ -65,6 +65,8 @@
|
|||||||
|
|
||||||
--color-diff-del: var(--diff-del);
|
--color-diff-del: var(--diff-del);
|
||||||
--color-diff-ins: var(--diff-ins);
|
--color-diff-ins: var(--diff-ins);
|
||||||
|
--color-scrim: var(--scrim);
|
||||||
|
--color-scrim-media: var(--scrim-media);
|
||||||
--color-path-dim: var(--path-dim);
|
--color-path-dim: var(--path-dim);
|
||||||
--color-path-fold: var(--path-fold);
|
--color-path-fold: var(--path-fold);
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,13 @@
|
|||||||
--surface-3: oklch(0.93 var(--tint-c-surface) var(--tint-h));
|
--surface-3: oklch(0.93 var(--tint-c-surface) var(--tint-h));
|
||||||
--surface-4: oklch(0.91 var(--tint-c-surface) var(--tint-h));
|
--surface-4: oklch(0.91 var(--tint-c-surface) var(--tint-h));
|
||||||
|
|
||||||
|
/* Modal scrims: the veil behind every dialog and sheet. Dark in both themes. Tinting it with the
|
||||||
|
foreground colour washed dark mode out to grey instead of dimming it, because there the
|
||||||
|
foreground is near-white. --scrim-media sits behind image viewers, where the picture is the
|
||||||
|
point, so it is near-opaque in both themes. */
|
||||||
|
--scrim: oklch(0.2 0.02 var(--tint-h) / 0.35);
|
||||||
|
--scrim-media: oklch(0 0 0 / 0.82);
|
||||||
|
|
||||||
/* Shadows */
|
/* Shadows */
|
||||||
--elevation-xs: 0 1px 2px oklch(0 0 0 / 0.05);
|
--elevation-xs: 0 1px 2px oklch(0 0 0 / 0.05);
|
||||||
--elevation-sm: 0 1px 3px oklch(0 0 0 / 0.08), 0 1px 2px oklch(0 0 0 / 0.06);
|
--elevation-sm: 0 1px 3px oklch(0 0 0 / 0.08), 0 1px 2px oklch(0 0 0 / 0.06);
|
||||||
@@ -362,6 +369,9 @@
|
|||||||
--surface-3: oklch(calc(0.245 + var(--bg-lift)) var(--tint-c-surface) var(--tint-h));
|
--surface-3: oklch(calc(0.245 + var(--bg-lift)) var(--tint-c-surface) var(--tint-h));
|
||||||
--surface-4: oklch(calc(0.295 + var(--bg-lift)) var(--tint-c-surface) var(--tint-h));
|
--surface-4: oklch(calc(0.295 + var(--bg-lift)) var(--tint-c-surface) var(--tint-h));
|
||||||
|
|
||||||
|
/* A dark surface needs a deeper veil than a light one to read as dimmed at all. */
|
||||||
|
--scrim: oklch(0.06 0.01 var(--tint-h) / 0.62);
|
||||||
|
|
||||||
/* Shadows */
|
/* Shadows */
|
||||||
--elevation-xs: 0 1px 2px oklch(0 0 0 / 0.4);
|
--elevation-xs: 0 1px 2px oklch(0 0 0 / 0.4);
|
||||||
--elevation-sm: 0 1px 3px oklch(0 0 0 / 0.5), 0 1px 2px oklch(0 0 0 / 0.4);
|
--elevation-sm: 0 1px 3px oklch(0 0 0 / 0.5), 0 1px 2px oklch(0 0 0 / 0.4);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const ADDITIONAL_TERMS_URL = `${PROJECT_URL}/blob/main/ADDITIONAL_TERMS.md`
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="open" @update:open="handleOpenChange">
|
<DialogRoot :open="open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/50" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
class="fixed left-1/2 top-1/2 z-50 max-h-[calc(100svh-2rem)] w-[calc(100%-2rem)] max-w-xl -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
class="fixed left-1/2 top-1/2 z-50 max-h-[calc(100svh-2rem)] w-[calc(100%-2rem)] max-w-xl -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function handleCancel() {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="open" @update:open="handleOpenChange">
|
<DialogRoot :open="open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-[70] bg-foreground/50" />
|
<DialogOverlay class="fixed inset-0 z-[70] bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
class="fixed left-1/2 top-1/2 z-[70] w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
class="fixed left-1/2 top-1/2 z-[70] w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ describe('ConfirmDialog', () => {
|
|||||||
// Simulate an underlying drawer/sheet overlay rendered at z-50
|
// Simulate an underlying drawer/sheet overlay rendered at z-50
|
||||||
const sheetOverlay = document.createElement('div')
|
const sheetOverlay = document.createElement('div')
|
||||||
sheetOverlay.setAttribute('data-slot', 'sheet-overlay')
|
sheetOverlay.setAttribute('data-slot', 'sheet-overlay')
|
||||||
sheetOverlay.className = 'fixed inset-0 z-50 bg-black/15'
|
sheetOverlay.className = 'fixed inset-0 z-50 bg-scrim'
|
||||||
document.body.appendChild(sheetOverlay)
|
document.body.appendChild(sheetOverlay)
|
||||||
|
|
||||||
const wrapper = mountDialog()
|
const wrapper = mountDialog()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const delegatedProps = reactiveOmit(props, 'class')
|
|||||||
data-slot="sheet-overlay"
|
data-slot="sheet-overlay"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/15',
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-scrim',
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function handleCopy() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 px-4" @click.self="handleClose">
|
<div class="fixed inset-0 z-[60] flex items-center justify-center bg-scrim px-4" @click.self="handleClose">
|
||||||
<div class="w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-xl">
|
<div class="w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-xl">
|
||||||
<div class="flex items-start justify-between mb-4">
|
<div class="flex items-start justify-between mb-4">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ t('adminFeature.resetLink.title') }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ t('adminFeature.resetLink.title') }}</h2>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-[70] flex items-center justify-center bg-black/50 px-4">
|
<div class="fixed inset-0 z-[70] flex items-center justify-center bg-scrim px-4">
|
||||||
<div class="w-full max-w-sm rounded-lg border border-border bg-card shadow-xl p-6">
|
<div class="w-full max-w-sm rounded-lg border border-border bg-card shadow-xl p-6">
|
||||||
<div class="flex items-center justify-between mb-5">
|
<div class="flex items-center justify-between mb-5">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ t('auth.changePassword.title') }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ t('auth.changePassword.title') }}</h2>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const resolvedCancelLabel = computed(() => props.cancelLabel ?? t('common.cancel
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-[70] flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-[70] flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="emit('cancel')" />
|
<div class="absolute inset-0 bg-scrim" @click="emit('cancel')" />
|
||||||
<div class="relative z-10 mx-4 w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-2xl">
|
<div class="relative z-10 mx-4 w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-2xl">
|
||||||
<div class="mb-5 flex items-start gap-4">
|
<div class="mb-5 flex items-start gap-4">
|
||||||
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full" :class="destructive ? 'bg-destructive/10' : 'bg-primary/10'">
|
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full" :class="destructive ? 'bg-destructive/10' : 'bg-primary/10'">
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ watch(resolvedBio, () => {
|
|||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div
|
<div
|
||||||
v-if="imageLightboxOpen && displayImageUrl"
|
v-if="imageLightboxOpen && displayImageUrl"
|
||||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm"
|
class="fixed inset-0 z-50 flex items-center justify-center bg-scrim-media"
|
||||||
@click="imageLightboxOpen = false"
|
@click="imageLightboxOpen = false"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ function handleClose() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
|
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h2 class="text-base font-semibold text-foreground">
|
<h2 class="text-base font-semibold text-foreground">
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ function onCoverLoad(event: Event) {
|
|||||||
|
|
||||||
<DialogRoot :open="!!lightbox" @update:open="onLightboxOpenChange">
|
<DialogRoot :open="!!lightbox" @update:open="onLightboxOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=open]:fade-in-0" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim-media data-[state=open]:animate-in data-[state=open]:fade-in-0" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-50 max-h-[90vh] max-w-[90vw] -translate-x-1/2 -translate-y-1/2 outline-none data-[state=open]:animate-in data-[state=open]:zoom-in-95"
|
class="fixed left-1/2 top-1/2 z-50 max-h-[90vh] max-w-[90vw] -translate-x-1/2 -translate-y-1/2 outline-none data-[state=open]:animate-in data-[state=open]:zoom-in-95"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex">
|
<div class="fixed inset-0 z-50 flex">
|
||||||
<div class="hidden sm:block flex-1 bg-black/50 backdrop-blur-sm" @click="$emit('close')" />
|
<div class="hidden sm:block flex-1 bg-scrim" @click="$emit('close')" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col w-full h-full bg-background sm:border-l border-border shadow-2xl overflow-hidden transition-[width,max-width] duration-300"
|
class="relative flex flex-col w-full h-full bg-background sm:border-l border-border shadow-2xl overflow-hidden transition-[width,max-width] duration-300"
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ async function handleDiscardResultDuplicates() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
<div class="relative z-10 w-full max-w-2xl mx-4 bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
|
<div class="relative z-10 w-full max-w-2xl mx-4 bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h2 class="text-base font-semibold text-foreground">
|
<h2 class="text-base font-semibold text-foreground">
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ function handleClose() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
<div class="relative z-10 w-full max-w-xl mx-4 bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
|
<div class="relative z-10 w-full max-w-xl mx-4 bg-card border border-border rounded-lg shadow-2xl overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h2 class="text-base font-semibold text-foreground">
|
<h2 class="text-base font-semibold text-foreground">
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ onMounted(() => loadPage(1))
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="emit('close')">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="emit('close')">
|
||||||
<div class="bg-background border border-border rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col">
|
<div class="bg-background border border-border rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col">
|
||||||
<div class="flex items-center justify-between px-4 py-3 border-b border-border shrink-0">
|
<div class="flex items-center justify-between px-4 py-3 border-b border-border shrink-0">
|
||||||
<h2 class="text-sm font-semibold">{{ t('bookMetadataFetch.report.authorTitle') }}</h2>
|
<h2 class="text-sm font-semibold">{{ t('bookMetadataFetch.report.authorTitle') }}</h2>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ onMounted(() => loadPage(1))
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="emit('close')">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="emit('close')">
|
||||||
<div class="bg-background border border-border rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col">
|
<div class="bg-background border border-border rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col">
|
||||||
<div class="flex items-center justify-between px-4 py-3 border-b border-border shrink-0">
|
<div class="flex items-center justify-between px-4 py-3 border-b border-border shrink-0">
|
||||||
<h2 class="text-sm font-semibold">{{ t('bookMetadataFetch.report.bookTitle') }}</h2>
|
<h2 class="text-sm font-semibold">{{ t('bookMetadataFetch.report.bookTitle') }}</h2>
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ function handleSubmit() {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="isOpen" @update:open="handleOpenChange">
|
<DialogRoot :open="isOpen" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/50" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
class="fixed left-1/2 top-1/2 z-50 max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
class="fixed left-1/2 top-1/2 z-50 max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function handleOpenChange(open: boolean) {
|
|||||||
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<DialogOverlay
|
||||||
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 motion-reduce:animate-none"
|
class="fixed inset-0 z-50 bg-scrim-media data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 motion-reduce:animate-none"
|
||||||
/>
|
/>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-50 flex max-h-[90vh] max-w-[90vw] -translate-x-1/2 -translate-y-1/2 flex-col items-center gap-3 outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 motion-reduce:animate-none"
|
class="fixed left-1/2 top-1/2 z-50 flex max-h-[90vh] max-w-[90vw] -translate-x-1/2 -translate-y-1/2 flex-col items-center gap-3 outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 motion-reduce:animate-none"
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ function handleDelete() {
|
|||||||
<DialogRoot :open="coverLightboxOpen" @update:open="coverLightboxOpen = $event">
|
<DialogRoot :open="coverLightboxOpen" @update:open="coverLightboxOpen = $event">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<DialogOverlay
|
||||||
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
class="fixed inset-0 z-50 bg-scrim-media data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||||
/>
|
/>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2 max-w-[90vw] max-h-[90vh] outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95"
|
class="fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2 max-w-[90vw] max-h-[90vh] outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95"
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ watch(
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
<div class="relative z-10 w-full max-w-lg mx-4 max-h-[90vh] bg-card border border-border rounded-lg shadow-2xl flex flex-col">
|
<div class="relative z-10 w-full max-w-lg mx-4 max-h-[90vh] bg-card border border-border rounded-lg shadow-2xl flex flex-col">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center justify-between px-6 py-4 border-b border-border shrink-0">
|
<div class="flex items-center justify-between px-6 py-4 border-b border-border shrink-0">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const { t } = useI18n()
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="emit('cancel')" />
|
<div class="absolute inset-0 bg-scrim" @click="emit('cancel')" />
|
||||||
<div class="relative z-10 w-full max-w-sm mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
<div class="relative z-10 w-full max-w-sm mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
||||||
<div class="flex items-start gap-4 mb-5">
|
<div class="flex items-start gap-4 mb-5">
|
||||||
<div class="shrink-0 h-10 w-10 rounded-full bg-destructive/10 flex items-center justify-center">
|
<div class="shrink-0 h-10 w-10 rounded-full bg-destructive/10 flex items-center justify-center">
|
||||||
|
|||||||
@@ -47,12 +47,7 @@ const sections = computed(() => [
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<Transition name="shortcut-overlay">
|
<Transition name="shortcut-overlay">
|
||||||
<div
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="handleClose" @keydown.escape="handleClose">
|
||||||
v-if="open"
|
|
||||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm"
|
|
||||||
@click.self="handleClose"
|
|
||||||
@keydown.escape="handleClose"
|
|
||||||
>
|
|
||||||
<div class="relative w-full max-w-md rounded-xl border border-border bg-card shadow-xl" role="dialog" :aria-label="t('book.shortcuts.title')">
|
<div class="relative w-full max-w-md rounded-xl border border-border bg-card shadow-xl" role="dialog" :aria-label="t('book.shortcuts.title')">
|
||||||
<div class="flex items-center justify-between border-b border-border px-5 py-3">
|
<div class="flex items-center justify-between border-b border-border px-5 py-3">
|
||||||
<h2 class="text-sm font-semibold text-foreground">{{ t('book.shortcuts.title') }}</h2>
|
<h2 class="text-sm font-semibold text-foreground">{{ t('book.shortcuts.title') }}</h2>
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ watch(
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="closeDialog" />
|
<div class="absolute inset-0 bg-scrim" @click="closeDialog" />
|
||||||
<div class="relative z-10 mx-4 w-full max-w-2xl rounded-lg border border-border bg-card shadow-2xl">
|
<div class="relative z-10 mx-4 w-full max-w-2xl rounded-lg border border-border bg-card shadow-2xl">
|
||||||
<div class="flex items-center justify-between border-b border-border px-5 py-4">
|
<div class="flex items-center justify-between border-b border-border px-5 py-4">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function handleConfirm() {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/20" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-5 shadow-xl"
|
class="fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-5 shadow-xl"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ function formatPillClass(filename: string): string {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-[70] flex items-center justify-center p-2 sm:p-4">
|
<div class="fixed inset-0 z-[70] flex items-center justify-center p-2 sm:p-4">
|
||||||
<div class="absolute inset-0 bg-black/50 backdrop-blur-[2px]" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col w-full max-w-2xl bg-background rounded-lg shadow-2xl border border-border overflow-hidden"
|
class="relative flex flex-col w-full max-w-2xl bg-background rounded-lg shadow-2xl border border-border overflow-hidden"
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ function handleSubmit() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
||||||
<div class="flex items-center justify-between mb-5">
|
<div class="flex items-center justify-between mb-5">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ t('book.detail.addSession.title') }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ t('book.detail.addSession.title') }}</h2>
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ async function confirmDelete() {
|
|||||||
|
|
||||||
<!-- Rename -->
|
<!-- Rename -->
|
||||||
<div v-if="renameTarget" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="closeRenameModal">
|
<div v-if="renameTarget" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="closeRenameModal">
|
||||||
<button class="absolute inset-0 bg-black/45" :aria-label="t('common.cancel')" @click="closeRenameModal" />
|
<button class="absolute inset-0 bg-scrim" :aria-label="t('common.cancel')" @click="closeRenameModal" />
|
||||||
<div
|
<div
|
||||||
class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5"
|
class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
@@ -365,7 +365,7 @@ async function confirmDelete() {
|
|||||||
|
|
||||||
<!-- Delete -->
|
<!-- Delete -->
|
||||||
<div v-if="deleteTarget" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="closeDeleteModal">
|
<div v-if="deleteTarget" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="closeDeleteModal">
|
||||||
<button class="absolute inset-0 bg-black/45" :aria-label="t('common.cancel')" @click="closeDeleteModal" />
|
<button class="absolute inset-0 bg-scrim" :aria-label="t('common.cancel')" @click="closeDeleteModal" />
|
||||||
<div
|
<div
|
||||||
class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5"
|
class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
|
|||||||
@@ -464,7 +464,7 @@ watch(
|
|||||||
<DialogRoot :open="lightboxSrc !== null" @update:open="handleCoverPreviewOpenChange">
|
<DialogRoot :open="lightboxSrc !== null" @update:open="handleCoverPreviewOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<DialogOverlay
|
||||||
class="fixed inset-0 z-[60] bg-black/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 motion-reduce:animate-none"
|
class="fixed inset-0 z-[60] bg-scrim-media data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 motion-reduce:animate-none"
|
||||||
/>
|
/>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
:aria-describedby="undefined"
|
:aria-describedby="undefined"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ async function handleToggleCoverLock(field: 'cover' | 'audioCover') {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="book !== null" @update:open="handleOpenChange">
|
<DialogRoot :open="book !== null" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-50 w-full max-w-sm -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-card shadow-xl outline-none"
|
class="fixed left-1/2 top-1/2 z-50 w-full max-w-sm -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-card shadow-xl outline-none"
|
||||||
@escape-key-down="handleOpenChange(false)"
|
@escape-key-down="handleOpenChange(false)"
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ async function submit() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="emit('close')" />
|
<div class="absolute inset-0 bg-scrim" @click="emit('close')" />
|
||||||
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
||||||
<div class="flex items-center justify-between mb-5">
|
<div class="flex items-center justify-between mb-5">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ dialogTitle }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ dialogTitle }}</h2>
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ async function confirmDelete() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="emit('close')" />
|
<div class="absolute inset-0 bg-scrim" @click="emit('close')" />
|
||||||
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
||||||
<div class="flex items-center justify-between mb-5">
|
<div class="flex items-center justify-between mb-5">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ t('collection.editDialog.title') }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ t('collection.editDialog.title') }}</h2>
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ function applyServerErrors(items: { filename: string; status: string; error?: st
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="open" @update:open="handleOpenChange">
|
<DialogRoot :open="open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-50 flex max-h-[85vh] w-[calc(100vw-2rem)] max-w-2xl -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-border bg-card shadow-xl outline-none"
|
class="fixed left-1/2 top-1/2 z-50 flex max-h-[85vh] w-[calc(100vw-2rem)] max-w-2xl -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-border bg-card shadow-xl outline-none"
|
||||||
@escape-key-down="closeDialog"
|
@escape-key-down="closeDialog"
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ function cancelDelete() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
||||||
<button class="absolute inset-0 bg-black/45" @click="cancelDelete" />
|
<button class="absolute inset-0 bg-scrim" @click="cancelDelete" />
|
||||||
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">{{ t('email.groups.deleteTitle') }}</p>
|
<p class="text-base font-semibold text-foreground">{{ t('email.groups.deleteTitle') }}</p>
|
||||||
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ function cancelDelete() {
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
||||||
<button class="absolute inset-0 bg-black/45" @click="cancelDelete" />
|
<button class="absolute inset-0 bg-scrim" @click="cancelDelete" />
|
||||||
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">{{ t('email.history.deleteTitle') }}</p>
|
<p class="text-base font-semibold text-foreground">{{ t('email.history.deleteTitle') }}</p>
|
||||||
<p class="mt-1 text-sm text-muted-foreground line-clamp-2">{{ deleteConfirm.subject ?? t('email.history.noSubject') }}</p>
|
<p class="mt-1 text-sm text-muted-foreground line-clamp-2">{{ deleteConfirm.subject ?? t('email.history.noSubject') }}</p>
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ function cancelDelete() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
||||||
<button class="absolute inset-0 bg-black/45" @click="cancelDelete" />
|
<button class="absolute inset-0 bg-scrim" @click="cancelDelete" />
|
||||||
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">{{ t('email.providers.deleteTitle') }}</p>
|
<p class="text-base font-semibold text-foreground">{{ t('email.providers.deleteTitle') }}</p>
|
||||||
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ function cancelDelete() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
||||||
<button class="absolute inset-0 bg-black/45" @click="cancelDelete" />
|
<button class="absolute inset-0 bg-scrim" @click="cancelDelete" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">{{ t('email.recipients.deleteTitle') }}</p>
|
<p class="text-base font-semibold text-foreground">{{ t('email.recipients.deleteTitle') }}</p>
|
||||||
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ function close() {
|
|||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<Transition name="dialog-fade">
|
<Transition name="dialog-fade">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||||
<div class="absolute inset-0 bg-black/50 backdrop-blur-[1px]" @click="close" />
|
<div class="absolute inset-0 bg-scrim" @click="close" />
|
||||||
|
|
||||||
<div class="relative w-full max-w-md bg-background border border-border rounded-lg shadow-2xl overflow-hidden">
|
<div class="relative w-full max-w-md bg-background border border-border rounded-lg shadow-2xl overflow-hidden">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ function cancelDelete() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
<div v-if="deleteConfirm" class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4" @click.self="deleteConfirm = null">
|
||||||
<button class="absolute inset-0 bg-black/45" @click="cancelDelete" />
|
<button class="absolute inset-0 bg-scrim" @click="cancelDelete" />
|
||||||
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-xl border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">{{ t('email.templates.deleteTitle') }}</p>
|
<p class="text-base font-semibold text-foreground">{{ t('email.templates.deleteTitle') }}</p>
|
||||||
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
<p class="mt-1 text-sm text-muted-foreground">{{ t('email.deleteConfirm', { name: deleteConfirm.name }) }}</p>
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ describe('SendBookDialog', () => {
|
|||||||
|
|
||||||
it('emits close when the backdrop is clicked', async () => {
|
it('emits close when the backdrop is clicked', async () => {
|
||||||
const wrapper = mountDialog()
|
const wrapper = mountDialog()
|
||||||
await wrapper.find('.absolute.inset-0.bg-black\\/50').trigger('click')
|
await wrapper.find('.absolute.inset-0.bg-scrim').trigger('click')
|
||||||
expect(wrapper.emitted('update:open')).toEqual([[false]])
|
expect(wrapper.emitted('update:open')).toEqual([[false]])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ function normalizeSearch(value: string): string {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-[70] flex items-end justify-center bg-foreground/35 px-2 py-3 md:items-center md:px-6" @click.self="handleClose">
|
<div class="fixed inset-0 z-[70] flex items-end justify-center bg-scrim px-2 py-3 md:items-center md:px-6" @click.self="handleClose">
|
||||||
<section
|
<section
|
||||||
ref="dialogRef"
|
ref="dialogRef"
|
||||||
class="flex max-h-[92vh] w-full max-w-6xl flex-col rounded-lg border border-border bg-background shadow-xl outline-none"
|
class="flex max-h-[92vh] w-full max-w-6xl flex-col rounded-lg border border-border bg-background shadow-xl outline-none"
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ function formatPillClass(filename: string): string {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-[70] flex items-center justify-center p-2 sm:p-4">
|
<div class="fixed inset-0 z-[70] flex items-center justify-center p-2 sm:p-4">
|
||||||
<div class="absolute inset-0 bg-black/50 backdrop-blur-[2px]" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col w-full max-w-2xl bg-background rounded-lg shadow-2xl border border-border overflow-hidden"
|
class="relative flex flex-col w-full max-w-2xl bg-background rounded-lg shadow-2xl border border-border overflow-hidden"
|
||||||
|
|||||||
@@ -80,11 +80,7 @@ useModal({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div
|
<div class="fixed inset-0 z-[80] flex items-end justify-center bg-scrim sm:items-center sm:p-4" role="presentation" @click.self="requestClose">
|
||||||
class="fixed inset-0 z-[80] flex items-end justify-center bg-foreground/30 sm:items-center sm:p-4"
|
|
||||||
role="presentation"
|
|
||||||
@click.self="requestClose"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
ref="panel"
|
ref="panel"
|
||||||
class="flex h-dvh w-full flex-col overflow-hidden bg-background shadow-2xl outline-none sm:h-[min(82dvh,700px)] sm:max-w-xl sm:rounded-lg sm:border sm:border-border"
|
class="flex h-dvh w-full flex-col overflow-hidden bg-background shadow-2xl outline-none sm:h-[min(82dvh,700px)] sm:max-w-xl sm:rounded-lg sm:border sm:border-border"
|
||||||
|
|||||||
@@ -566,7 +566,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-70 bg-foreground/25 motion-safe:animate-in motion-safe:fade-in-0" role="presentation" @click.self="requestClose">
|
<div class="fixed inset-0 z-70 bg-scrim motion-safe:animate-in motion-safe:fade-in-0" role="presentation" @click.self="requestClose">
|
||||||
<div
|
<div
|
||||||
ref="panel"
|
ref="panel"
|
||||||
class="fixed inset-y-0 end-0 flex w-full flex-col bg-background shadow-2xl outline-none sm:max-w-[56rem] sm:border-s sm:border-border motion-safe:animate-in motion-safe:duration-300 ltr:motion-safe:slide-in-from-right rtl:motion-safe:slide-in-from-left"
|
class="fixed inset-y-0 end-0 flex w-full flex-col bg-background shadow-2xl outline-none sm:max-w-[56rem] sm:border-s sm:border-border motion-safe:animate-in motion-safe:duration-300 ltr:motion-safe:slide-in-from-right rtl:motion-safe:slide-in-from-left"
|
||||||
|
|||||||
@@ -1307,7 +1307,7 @@ const sourceTypeCompatibility = computed<SourceTypeCompatibility | null>(() => {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-[70] flex items-center justify-center p-4">
|
<div class="fixed inset-0 z-[70] flex items-center justify-center p-4">
|
||||||
<div class="absolute inset-0 bg-black/50 backdrop-blur-[2px]" @click="handleClose" />
|
<div class="absolute inset-0 bg-scrim" @click="handleClose" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col w-full max-w-5xl bg-background rounded-lg shadow-2xl overflow-hidden border border-border"
|
class="relative flex flex-col w-full max-w-5xl bg-background rounded-lg shadow-2xl overflow-hidden border border-border"
|
||||||
|
|||||||
@@ -1190,7 +1190,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<!-- Chapter sheet backdrop -->
|
<!-- Chapter sheet backdrop -->
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div v-if="showChapters" class="absolute inset-0 z-20 bg-black/40" @click="showChapters = false" />
|
<div v-if="showChapters" class="absolute inset-0 z-20 bg-scrim" @click="showChapters = false" />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<!-- Chapter / Bookmarks sheet (slide up) -->
|
<!-- Chapter / Bookmarks sheet (slide up) -->
|
||||||
@@ -1272,7 +1272,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
<!-- Settings sheet backdrop -->
|
<!-- Settings sheet backdrop -->
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div v-if="showSettings" class="absolute inset-0 z-20 bg-black/40" @click="showSettings = false" />
|
<div v-if="showSettings" class="absolute inset-0 z-20 bg-scrim" @click="showSettings = false" />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<!-- Settings sheet (slide up) -->
|
<!-- Settings sheet (slide up) -->
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ onUnmounted(() => document.removeEventListener('keydown', onKeyDown, true))
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div data-backdrop class="fixed inset-0 z-[60] flex items-center justify-center bg-black/50 px-4 backdrop-blur-sm" @click="handleBackdropClick">
|
<div data-backdrop class="fixed inset-0 z-[60] flex items-center justify-center bg-scrim px-4" @click="handleBackdropClick">
|
||||||
<div class="w-full max-w-md rounded-xl border border-border/80 bg-card shadow-2xl">
|
<div class="w-full max-w-md rounded-xl border border-border/80 bg-card shadow-2xl">
|
||||||
<div class="flex items-center justify-between border-b border-border/80 bg-gradient-to-br from-muted/75 via-card to-muted/40 px-4 py-3">
|
<div class="flex items-center justify-between border-b border-border/80 bg-gradient-to-br from-muted/75 via-card to-muted/40 px-4 py-3">
|
||||||
<div class="inline-flex items-center gap-2">
|
<div class="inline-flex items-center gap-2">
|
||||||
|
|||||||
@@ -548,7 +548,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="pendingExternalUrl" class="fixed inset-0 z-[70] flex items-center justify-center bg-background/70 p-4 backdrop-blur-sm">
|
<div v-if="pendingExternalUrl" class="fixed inset-0 z-[70] flex items-center justify-center bg-scrim p-4">
|
||||||
<div class="w-full max-w-md rounded-xl border border-border bg-card p-5 text-card-foreground shadow-2xl">
|
<div class="w-full max-w-md rounded-xl border border-border bg-card p-5 text-card-foreground shadow-2xl">
|
||||||
<div class="mb-4 flex items-start gap-3">
|
<div class="mb-4 flex items-start gap-3">
|
||||||
<div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary"><ExternalLink :size="18" /></div>
|
<div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary"><ExternalLink :size="18" /></div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function handleSave() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div class="fixed inset-0 z-[70] flex items-center justify-center bg-foreground/35 p-4" @click.self="handleBackdropClick">
|
<div class="fixed inset-0 z-[70] flex items-center justify-center bg-scrim p-4" @click.self="handleBackdropClick">
|
||||||
<div class="bg-card text-card-foreground rounded-lg shadow-2xl p-4 w-full max-w-sm flex flex-col gap-3">
|
<div class="bg-card text-card-foreground rounded-lg shadow-2xl p-4 w-full max-w-sm flex flex-col gap-3">
|
||||||
<p class="text-sm font-medium">{{ t('reader.note.title') }}</p>
|
<p class="text-sm font-medium">{{ t('reader.note.title') }}</p>
|
||||||
<p class="text-xs text-muted-foreground line-clamp-2 italic">"{{ selectedText }}"</p>
|
<p class="text-xs text-muted-foreground line-clamp-2 italic">"{{ selectedText }}"</p>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ function handleSubmit(): void {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/50" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
class="fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
class="fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
|
|||||||
@@ -1438,7 +1438,7 @@ async function handleDownloadPlugin() {
|
|||||||
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
||||||
@click.self="handleCloseDeleteConfirm"
|
@click.self="handleCloseDeleteConfirm"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="handleCloseDeleteConfirm" />
|
<button class="absolute inset-0 bg-scrim" @click="handleCloseDeleteConfirm" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">
|
<p class="text-base font-semibold text-foreground">
|
||||||
{{ t('settings.reader.koreader.deleteConfirmTitle') }}
|
{{ t('settings.reader.koreader.deleteConfirmTitle') }}
|
||||||
@@ -1462,7 +1462,7 @@ async function handleDownloadPlugin() {
|
|||||||
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
||||||
@click.self="handleCloseUnlink"
|
@click.self="handleCloseUnlink"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="handleCloseUnlink" />
|
<button class="absolute inset-0 bg-scrim" @click="handleCloseUnlink" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">
|
<p class="text-base font-semibold text-foreground">
|
||||||
{{ t('settings.reader.koreader.hashLinks.unlinkConfirmTitle') }}
|
{{ t('settings.reader.koreader.hashLinks.unlinkConfirmTitle') }}
|
||||||
@@ -1502,7 +1502,7 @@ async function handleDownloadPlugin() {
|
|||||||
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
||||||
@click.self="handleCloseRemoveDevice"
|
@click.self="handleCloseRemoveDevice"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="handleCloseRemoveDevice" />
|
<button class="absolute inset-0 bg-scrim" @click="handleCloseRemoveDevice" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">
|
<p class="text-base font-semibold text-foreground">
|
||||||
{{
|
{{
|
||||||
@@ -1534,7 +1534,7 @@ async function handleDownloadPlugin() {
|
|||||||
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
||||||
@click.self="handleCloseDismiss"
|
@click.self="handleCloseDismiss"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="handleCloseDismiss" />
|
<button class="absolute inset-0 bg-scrim" @click="handleCloseDismiss" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">
|
<p class="text-base font-semibold text-foreground">
|
||||||
{{
|
{{
|
||||||
@@ -1571,7 +1571,7 @@ async function handleDownloadPlugin() {
|
|||||||
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
||||||
@click.self="handleCloseDismissAll"
|
@click.self="handleCloseDismissAll"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="handleCloseDismissAll" />
|
<button class="absolute inset-0 bg-scrim" @click="handleCloseDismissAll" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">
|
<p class="text-base font-semibold text-foreground">
|
||||||
{{
|
{{
|
||||||
@@ -1603,7 +1603,7 @@ async function handleDownloadPlugin() {
|
|||||||
@click.self="handleCloseLink"
|
@click.self="handleCloseLink"
|
||||||
@keydown.esc="handleCloseLink"
|
@keydown.esc="handleCloseLink"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="handleCloseLink" />
|
<button class="absolute inset-0 bg-scrim" @click="handleCloseLink" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-2xl md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-2xl md:rounded-lg md:p-5">
|
||||||
<div class="flex items-start justify-between gap-3">
|
<div class="flex items-start justify-between gap-3">
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ function isExpired(expiresAt: string | null | undefined): boolean {
|
|||||||
|
|
||||||
<DialogRoot :open="showCreateForm" @update:open="handleCreateOpenChange">
|
<DialogRoot :open="showCreateForm" @update:open="handleCreateOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/50" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
class="fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
class="fixed left-1/2 top-1/2 z-50 w-[calc(100%-2rem)] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-card p-6 shadow-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ function cancelDelete() {
|
|||||||
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
class="fixed inset-0 z-[70] flex items-end justify-center md:items-center md:px-4"
|
||||||
@click.self="deleteConfirmUser = null"
|
@click.self="deleteConfirmUser = null"
|
||||||
>
|
>
|
||||||
<button class="absolute inset-0 bg-black/45" @click="cancelDelete" />
|
<button class="absolute inset-0 bg-scrim" @click="cancelDelete" />
|
||||||
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
<div class="relative w-full rounded-t-lg border border-border bg-card p-4 shadow-xl md:max-w-md md:rounded-lg md:p-5">
|
||||||
<p class="text-base font-semibold text-foreground">
|
<p class="text-base font-semibold text-foreground">
|
||||||
{{ t('settings.reader.opds.deleteConfirmTitle') }}
|
{{ t('settings.reader.opds.deleteConfirmTitle') }}
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="deleteConfirmField" class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4" @click.self="cancelDeleteConfirm">
|
<div v-if="deleteConfirmField" class="fixed inset-0 z-50 flex items-center justify-center bg-scrim p-4" @click.self="cancelDeleteConfirm">
|
||||||
<div class="w-full max-w-md rounded-xl border border-border bg-card shadow-xl">
|
<div class="w-full max-w-md rounded-xl border border-border bg-card shadow-xl">
|
||||||
<div class="p-5 border-b border-border flex items-start gap-3">
|
<div class="p-5 border-b border-border flex items-start gap-3">
|
||||||
<div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-destructive/10 text-destructive">
|
<div class="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-destructive/10 text-destructive">
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ async function submit() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="emit('close')" />
|
<div class="absolute inset-0 bg-scrim" @click="emit('close')" />
|
||||||
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
||||||
<div class="flex items-center justify-between mb-5">
|
<div class="flex items-center justify-between mb-5">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ dialogTitle }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ dialogTitle }}</h2>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ async function submit() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
<div v-if="open" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
<div class="absolute inset-0 bg-black/40 backdrop-blur-sm" @click="emit('close')" />
|
<div class="absolute inset-0 bg-scrim" @click="emit('close')" />
|
||||||
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
<div class="relative z-10 w-full max-w-md mx-4 bg-card border border-border rounded-lg shadow-2xl p-6">
|
||||||
<div class="flex items-center justify-between mb-5">
|
<div class="flex items-center justify-between mb-5">
|
||||||
<h2 class="text-base font-semibold text-foreground">{{ t('smartScope.saveAsDialog.title') }}</h2>
|
<h2 class="text-base font-semibold text-foreground">{{ t('smartScope.saveAsDialog.title') }}</h2>
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ async function save() {
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<Transition name="smartScope-fade">
|
<Transition name="smartScope-fade">
|
||||||
<div v-if="open" class="fixed inset-0 z-40 bg-black/40 backdrop-blur-sm" @click="emit('close')" />
|
<div v-if="open" class="fixed inset-0 z-40 bg-scrim" @click="emit('close')" />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<Transition name="smartScope-slide">
|
<Transition name="smartScope-slide">
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function handleCancel(): void {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
<DialogRoot :open="props.open" @update:open="handleOpenChange">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/50 backdrop-blur-[2px]" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-popover p-5 shadow-2xl focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
class="fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-popover p-5 shadow-2xl focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ function preventDismiss(event: Event): void {
|
|||||||
<template>
|
<template>
|
||||||
<DialogRoot :open="props.open">
|
<DialogRoot :open="props.open">
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay class="fixed inset-0 z-50 bg-foreground/50 backdrop-blur-[2px]" />
|
<DialogOverlay class="fixed inset-0 z-50 bg-scrim" />
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-popover p-5 shadow-2xl focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
class="fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-popover p-5 shadow-2xl focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
||||||
@escape-key-down="preventDismiss"
|
@escape-key-down="preventDismiss"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ function handleCancel(): void {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="handleCancel">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="handleCancel">
|
||||||
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-lg mx-4 overflow-hidden flex flex-col h-150 max-h-[85vh]">
|
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-lg mx-4 overflow-hidden flex flex-col h-150 max-h-[85vh]">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border shrink-0">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border shrink-0">
|
||||||
<h3 class="text-base font-semibold flex items-center gap-2">
|
<h3 class="text-base font-semibold flex items-center gap-2">
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function handleCancel(): void {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="handleCancel">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="handleCancel">
|
||||||
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h3 class="text-base font-semibold text-destructive flex items-center gap-2">
|
<h3 class="text-base font-semibold text-destructive flex items-center gap-2">
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function handleCancel(): void {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="handleCancel">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="handleCancel">
|
||||||
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h3 class="text-base font-semibold text-destructive flex items-center gap-2">
|
<h3 class="text-base font-semibold text-destructive flex items-center gap-2">
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function handleCancel(): void {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="handleCancel">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="handleCancel">
|
||||||
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h3 class="text-base font-semibold">{{ t('tools.entityManager.renameModal.title') }}</h3>
|
<h3 class="text-base font-semibold">{{ t('tools.entityManager.renameModal.title') }}</h3>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function isValid(): boolean {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" @click.self="handleCancel">
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-scrim" @click.self="handleCancel">
|
||||||
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
<div class="bg-card border border-border rounded-lg shadow-lg w-full max-w-md mx-4 overflow-hidden">
|
||||||
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
||||||
<h3 class="text-base font-semibold">{{ t('tools.entityManager.splitModal.title') }}</h3>
|
<h3 class="text-base font-semibold">{{ t('tools.entityManager.splitModal.title') }}</h3>
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ function handleClose() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
|
<div class="fixed inset-0 bg-scrim z-50 flex items-center justify-center p-4">
|
||||||
<div class="bg-card border border-border rounded-xl w-full max-w-2xl max-h-[90vh] flex flex-col shadow-xl">
|
<div class="bg-card border border-border rounded-xl w-full max-w-2xl max-h-[90vh] flex flex-col shadow-xl">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center justify-between p-5 border-b border-border flex-shrink-0">
|
<div class="flex items-center justify-between p-5 border-b border-border flex-shrink-0">
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ useModal({
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div
|
<div
|
||||||
class="fixed inset-0 z-[75] flex items-end justify-center bg-black/50 motion-safe:animate-in motion-safe:fade-in sm:items-center sm:px-4"
|
class="fixed inset-0 z-[75] flex items-end justify-center bg-scrim motion-safe:animate-in motion-safe:fade-in sm:items-center sm:px-4"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
aria-labelledby="whats-new-title"
|
aria-labelledby="whats-new-title"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ onUnmounted(() => {
|
|||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div
|
<div
|
||||||
ref="panel"
|
ref="panel"
|
||||||
class="fixed inset-0 z-[90] flex items-center justify-center bg-black/80 p-4 motion-safe:animate-in motion-safe:fade-in"
|
class="fixed inset-0 z-[90] flex items-center justify-center bg-scrim-media p-4 motion-safe:animate-in motion-safe:fade-in"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
:aria-label="t('whatsNew.imageViewer')"
|
:aria-label="t('whatsNew.imageViewer')"
|
||||||
|
|||||||
Reference in New Issue
Block a user