generated from nhcarrigan/template
feat: add theme support to editor dialogs and context menu
Update ConfirmDialog, InputDialog, and FileContextMenu to use CSS variables instead of hardcoded Tailwind colors, so they respect the user's theme selection (dark/light/high-contrast).
This commit is contained in:
@@ -31,30 +31,101 @@
|
||||
<svelte:window onkeydown={handleKeydown} />
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onclick={onCancel}>
|
||||
<div class="dialog-overlay" onclick={onCancel}>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="mx-4 w-full max-w-md rounded-lg border border-gray-700 bg-gray-800 p-6 shadow-xl"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<h2 class="mb-2 text-lg font-semibold text-gray-100">{title}</h2>
|
||||
<p class="mb-6 text-sm text-gray-300">{message}</p>
|
||||
<div class="dialog-content" onclick={(e) => e.stopPropagation()}>
|
||||
<h2 class="dialog-title">{title}</h2>
|
||||
<p class="dialog-message">{message}</p>
|
||||
|
||||
<div class="flex justify-end gap-3">
|
||||
<button
|
||||
class="rounded-md border border-gray-600 bg-gray-700 px-4 py-2 text-sm text-gray-200 hover:bg-gray-600"
|
||||
onclick={onCancel}
|
||||
>
|
||||
<div class="dialog-actions">
|
||||
<button class="btn-cancel" onclick={onCancel}>
|
||||
{cancelText}
|
||||
</button>
|
||||
<button
|
||||
class="rounded-md px-4 py-2 text-sm text-white {destructive
|
||||
? 'bg-red-600 hover:bg-red-700'
|
||||
: 'bg-pink-600 hover:bg-pink-700'}"
|
||||
onclick={onConfirm}
|
||||
>
|
||||
<button class="btn-confirm" class:destructive onclick={onConfirm}>
|
||||
{confirmText}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
margin: 0 1rem;
|
||||
width: 100%;
|
||||
max-width: 28rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-secondary);
|
||||
padding: 1.5rem;
|
||||
box-shadow:
|
||||
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.dialog-message {
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-primary);
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background-color: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
border-radius: 0.375rem;
|
||||
border: none;
|
||||
background-color: var(--accent-primary);
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-confirm:hover {
|
||||
background-color: var(--accent-secondary);
|
||||
}
|
||||
|
||||
.btn-confirm.destructive {
|
||||
background-color: #dc2626;
|
||||
}
|
||||
|
||||
.btn-confirm.destructive:hover {
|
||||
background-color: #b91c1c;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="fixed inset-0 z-50"
|
||||
class="menu-overlay"
|
||||
onclick={onClose}
|
||||
oncontextmenu={(e) => {
|
||||
e.preventDefault();
|
||||
@@ -70,16 +70,9 @@
|
||||
}}
|
||||
>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="absolute z-50 min-w-[160px] rounded-md border border-gray-700 bg-gray-800 py-1 shadow-lg"
|
||||
style="left: {x}px; top: {y}px;"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm text-gray-200 hover:bg-gray-700"
|
||||
onclick={handleNewFile}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="menu-content" style="left: {x}px; top: {y}px;" onclick={(e) => e.stopPropagation()}>
|
||||
<button class="menu-item" onclick={handleNewFile}>
|
||||
<svg class="menu-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
@@ -90,11 +83,8 @@
|
||||
New File
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm text-gray-200 hover:bg-gray-700"
|
||||
onclick={handleNewFolder}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<button class="menu-item" onclick={handleNewFolder}>
|
||||
<svg class="menu-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
@@ -106,13 +96,10 @@
|
||||
</button>
|
||||
|
||||
{#if targetEntry}
|
||||
<div class="my-1 border-t border-gray-700"></div>
|
||||
<div class="menu-divider"></div>
|
||||
|
||||
<button
|
||||
class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm text-gray-200 hover:bg-gray-700"
|
||||
onclick={handleRename}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<button class="menu-item" onclick={handleRename}>
|
||||
<svg class="menu-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
@@ -123,11 +110,8 @@
|
||||
Rename
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm text-red-400 hover:bg-gray-700"
|
||||
onclick={handleDelete}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<button class="menu-item destructive" onclick={handleDelete}>
|
||||
<svg class="menu-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
@@ -140,3 +124,57 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.menu-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
min-width: 160px;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-secondary);
|
||||
padding: 0.25rem 0;
|
||||
box-shadow:
|
||||
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
||||
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
text-align: left;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-primary);
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
|
||||
.menu-item.destructive {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.menu-divider {
|
||||
margin: 0.25rem 0;
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
onCancel,
|
||||
}: Props = $props();
|
||||
|
||||
// svelte-ignore state_referenced_locally - intentionally capture initial value once
|
||||
let inputValue = $state(initialValue);
|
||||
let inputElement: HTMLInputElement | undefined = $state();
|
||||
|
||||
@@ -52,36 +51,123 @@
|
||||
<svelte:window onkeydown={handleKeydown} />
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onclick={onCancel}>
|
||||
<div class="dialog-overlay" onclick={onCancel}>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="mx-4 w-full max-w-md rounded-lg border border-gray-700 bg-gray-800 p-6 shadow-xl"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<h2 class="mb-4 text-lg font-semibold text-gray-100">{title}</h2>
|
||||
<div class="dialog-content" onclick={(e) => e.stopPropagation()}>
|
||||
<h2 class="dialog-title">{title}</h2>
|
||||
|
||||
<input
|
||||
bind:this={inputElement}
|
||||
bind:value={inputValue}
|
||||
type="text"
|
||||
{placeholder}
|
||||
class="mb-6 w-full rounded-md border border-gray-600 bg-gray-700 px-3 py-2 text-sm text-gray-100 placeholder-gray-400 focus:border-pink-500 focus:outline-none focus:ring-1 focus:ring-pink-500"
|
||||
class="dialog-input"
|
||||
/>
|
||||
|
||||
<div class="flex justify-end gap-3">
|
||||
<button
|
||||
class="rounded-md border border-gray-600 bg-gray-700 px-4 py-2 text-sm text-gray-200 hover:bg-gray-600"
|
||||
onclick={onCancel}
|
||||
>
|
||||
<div class="dialog-actions">
|
||||
<button class="btn-cancel" onclick={onCancel}>
|
||||
{cancelText}
|
||||
</button>
|
||||
<button
|
||||
class="rounded-md bg-pink-600 px-4 py-2 text-sm text-white hover:bg-pink-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
onclick={handleSubmit}
|
||||
disabled={!inputValue.trim()}
|
||||
>
|
||||
<button class="btn-confirm" onclick={handleSubmit} disabled={!inputValue.trim()}>
|
||||
{confirmText}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
margin: 0 1rem;
|
||||
width: 100%;
|
||||
max-width: 28rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-secondary);
|
||||
padding: 1.5rem;
|
||||
box-shadow:
|
||||
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||
0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.dialog-input {
|
||||
width: 100%;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-primary);
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-primary);
|
||||
outline: none;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
.dialog-input::placeholder {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.dialog-input:focus {
|
||||
border-color: var(--accent-primary);
|
||||
box-shadow: 0 0 0 1px var(--accent-primary);
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-primary);
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background-color: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
border-radius: 0.375rem;
|
||||
border: none;
|
||||
background-color: var(--accent-primary);
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-confirm:hover {
|
||||
background-color: var(--accent-secondary);
|
||||
}
|
||||
|
||||
.btn-confirm:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user