refactor: update tag-related styles and UI components with new color system
This commit is contained in:
parent
6e50acbd22
commit
0d0607577d
@ -83,31 +83,31 @@
|
||||
display: inline;
|
||||
}
|
||||
|
||||
:host ::ng-deep .md-tag-palette-0 { background: rgba(190, 242, 100, 0.35); color: #3f6212; }
|
||||
:host ::ng-deep .md-tag-palette-1 { background: rgba(129, 230, 217, 0.35); color: #0f766e; }
|
||||
:host ::ng-deep .md-tag-palette-2 { background: rgba(196, 181, 253, 0.35); color: #6b21a8; }
|
||||
:host ::ng-deep .md-tag-palette-3 { background: rgba(248, 196, 113, 0.35); color: #b45309; }
|
||||
:host ::ng-deep .md-tag-palette-4 { background: rgba(248, 113, 113, 0.35); color: #b91c1c; }
|
||||
:host ::ng-deep .md-tag-palette-5 { background: rgba(129, 140, 248, 0.35); color: #4338ca; }
|
||||
:host ::ng-deep .md-tag-palette-6 { background: rgba(233, 213, 255, 0.35); color: #7e22ce; }
|
||||
:host ::ng-deep .md-tag-palette-7 { background: rgba(209, 250, 229, 0.35); color: #047857; }
|
||||
:host ::ng-deep .md-tag-palette-8 { background: rgba(165, 180, 252, 0.35); color: #1d4ed8; }
|
||||
:host ::ng-deep .md-tag-palette-9 { background: rgba(253, 224, 71, 0.35); color: #92400e; }
|
||||
:host ::ng-deep .md-tag-palette-10 { background: rgba(244, 114, 182, 0.35); color: #be185d; }
|
||||
:host ::ng-deep .md-tag-palette-11 { background: rgba(148, 163, 184, 0.35); color: #1f2937; }
|
||||
:host ::ng-deep .md-tag-color-0 { background: rgba(190, 242, 100, 0.35); color: #3f6212; }
|
||||
:host ::ng-deep .md-tag-color-1 { background: rgba(129, 230, 217, 0.35); color: #0f766e; }
|
||||
:host ::ng-deep .md-tag-color-2 { background: rgba(196, 181, 253, 0.35); color: #6b21a8; }
|
||||
:host ::ng-deep .md-tag-color-3 { background: rgba(248, 196, 113, 0.35); color: #b45309; }
|
||||
:host ::ng-deep .md-tag-color-4 { background: rgba(248, 113, 113, 0.35); color: #b91c1c; }
|
||||
:host ::ng-deep .md-tag-color-5 { background: rgba(129, 140, 248, 0.35); color: #4338ca; }
|
||||
:host ::ng-deep .md-tag-color-6 { background: rgba(233, 213, 255, 0.35); color: #7e22ce; }
|
||||
:host ::ng-deep .md-tag-color-7 { background: rgba(209, 250, 229, 0.35); color: #047857; }
|
||||
:host ::ng-deep .md-tag-color-8 { background: rgba(165, 180, 252, 0.35); color: #1d4ed8; }
|
||||
:host ::ng-deep .md-tag-color-9 { background: rgba(253, 224, 71, 0.35); color: #92400e; }
|
||||
:host ::ng-deep .md-tag-color-10 { background: rgba(244, 114, 182, 0.35); color: #be185d; }
|
||||
:host ::ng-deep .md-tag-color-11 { background: rgba(148, 163, 184, 0.35); color: #1f2937; }
|
||||
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-0 { background: rgba(132, 204, 22, 0.35); color: #d9f99d; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-1 { background: rgba(45, 212, 191, 0.3); color: #d1fae5; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-2 { background: rgba(168, 85, 247, 0.28); color: #ede9fe; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-3 { background: rgba(245, 158, 11, 0.28); color: #fde68a; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-4 { background: rgba(248, 113, 113, 0.3); color: #fee2e2; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-5 { background: rgba(99, 102, 241, 0.3); color: #e0e7ff; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-6 { background: rgba(217, 70, 239, 0.28); color: #f5d0fe; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-7 { background: rgba(34, 197, 94, 0.3); color: #bbf7d0; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-8 { background: rgba(59, 130, 246, 0.28); color: #bfdbfe; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-9 { background: rgba(250, 204, 21, 0.28); color: #fef08a; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-10 { background: rgba(236, 72, 153, 0.3); color: #fbcfe8; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-palette-11 { background: rgba(107, 114, 128, 0.3); color: #cbd5f5; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-0 { background: rgba(132, 204, 22, 0.35); color: #d9f99d; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-1 { background: rgba(45, 212, 191, 0.3); color: #d1fae5; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-2 { background: rgba(168, 85, 247, 0.28); color: #ede9fe; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-3 { background: rgba(245, 158, 11, 0.28); color: #fde68a; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-4 { background: rgba(248, 113, 113, 0.3); color: #fee2e2; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-5 { background: rgba(99, 102, 241, 0.3); color: #e0e7ff; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-6 { background: rgba(217, 70, 239, 0.28); color: #f5d0fe; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-7 { background: rgba(34, 197, 94, 0.3); color: #bbf7d0; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-8 { background: rgba(59, 130, 246, 0.28); color: #bfdbfe; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-9 { background: rgba(250, 204, 21, 0.28); color: #fef08a; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-10 { background: rgba(236, 72, 153, 0.3); color: #fbcfe8; }
|
||||
:host-context(.dark) ::ng-deep .md-tag-color-11 { background: rgba(107, 114, 128, 0.3); color: #cbd5f5; }
|
||||
|
||||
:host ::ng-deep .metadata-panel__item .md-tag-badge {
|
||||
cursor: default;
|
||||
|
||||
@ -45,5 +45,6 @@
|
||||
[noteId]="noteId"
|
||||
[tags]="tags"
|
||||
(saved)="tagsChange.emit($event)"
|
||||
(tagSelected)="tagSelected.emit($event)"
|
||||
></app-tag-manager>
|
||||
</header>
|
||||
|
||||
@ -24,6 +24,7 @@ export class NoteHeaderComponent implements AfterViewInit, OnDestroy {
|
||||
@Output() openDirectory = new EventEmitter<void>();
|
||||
@Output() copyRequested = new EventEmitter<void>();
|
||||
@Output() tagsChange = new EventEmitter<string[]>();
|
||||
@Output() tagSelected = new EventEmitter<string>();
|
||||
|
||||
pathParts: { prefix: string; filename: string } = { prefix: '', filename: '' };
|
||||
|
||||
|
||||
@ -92,30 +92,21 @@
|
||||
.mode-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.625rem 1rem;
|
||||
background: var(--bg-muted);
|
||||
border: 1.5px solid var(--border);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--text-main);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-base);
|
||||
min-width: 6.5rem;
|
||||
gap: 0.45rem;
|
||||
justify-content: center;
|
||||
min-width: 6.5rem;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mode-button:hover {
|
||||
background: var(--bg-main);
|
||||
border-color: var(--primary);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.mode-button.active {
|
||||
background: var(--primary);
|
||||
border-color: var(--primary);
|
||||
color: white;
|
||||
.mode-button:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
@ -126,6 +117,66 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Colored shadows small buttons (shared look with tag manager) */
|
||||
.btn-colored-xs {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: #0f172a;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand) 18%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand) 8%, transparent) 100%);
|
||||
box-shadow: 0 6px 14px -10px color-mix(in oklab, var(--brand) 65%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--brand) 22%, transparent);
|
||||
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-colored-xs:hover,
|
||||
.btn-colored-xs:focus-visible {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 18px -10px color-mix(in oklab, var(--brand) 75%, transparent);
|
||||
border-color: color-mix(in oklab, var(--brand) 35%, transparent);
|
||||
}
|
||||
|
||||
:host-context(.dark) .btn-colored-xs {
|
||||
color: #e2e8f0;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand-700) 22%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand-700) 12%, transparent) 100%);
|
||||
box-shadow: 0 10px 22px -14px color-mix(in oklab, var(--brand-700) 85%, transparent);
|
||||
border-color: color-mix(in oklab, var(--brand-700) 30%, transparent);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: white;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand-700) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--brand-700) 50%, transparent);
|
||||
}
|
||||
|
||||
.btn-neutral {
|
||||
color: inherit;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--surface-1, #e5e7eb) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--surface-2, #d1d5db) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--border, #cbd5e1) 60%, transparent);
|
||||
}
|
||||
|
||||
:host-context(.dark) .btn-neutral {
|
||||
color: #e2e8f0;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--card, #111827) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--surface2, #0b1220) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--border, #334155) 60%, transparent);
|
||||
}
|
||||
|
||||
/* Theme Grid */
|
||||
.theme-grid {
|
||||
display: grid;
|
||||
|
||||
@ -31,8 +31,9 @@
|
||||
<button
|
||||
*ngFor="let m of modes"
|
||||
(click)="setMode(m)"
|
||||
class="mode-button"
|
||||
[class.active]="prefs().mode === m"
|
||||
class="mode-button btn-colored-xs"
|
||||
[class.btn-primary]="prefs().mode === m"
|
||||
[class.btn-neutral]="prefs().mode !== m"
|
||||
[attr.aria-label]="'Set mode to ' + m">
|
||||
<svg *ngIf="m === 'system'" class="button-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
@ -100,8 +101,9 @@
|
||||
<button
|
||||
*ngFor="let l of languages"
|
||||
(click)="setLanguage(l)"
|
||||
class="mode-button"
|
||||
[class.active]="prefs().language === l"
|
||||
class="mode-button btn-colored-xs"
|
||||
[class.btn-primary]="prefs().language === l"
|
||||
[class.btn-neutral]="prefs().language !== l"
|
||||
[attr.aria-label]="'Set language to ' + l">
|
||||
<span class="button-text">{{ l === 'fr' ? 'Français' : 'English' }}</span>
|
||||
</button>
|
||||
|
||||
@ -24,7 +24,7 @@ import { GraphSettingsAccordionComponent } from '../../../components/graph-setti
|
||||
<!-- Expand all -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn-standard-icon"
|
||||
class="btn-colored-xs btn-neutral"
|
||||
title="Expand all"
|
||||
(click)="accordion?.expandAll()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@ -35,7 +35,7 @@ import { GraphSettingsAccordionComponent } from '../../../components/graph-setti
|
||||
<!-- Collapse all -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn-standard-icon"
|
||||
class="btn-colored-xs btn-neutral"
|
||||
title="Collapse all"
|
||||
(click)="accordion?.collapseAll()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@ -46,7 +46,7 @@ import { GraphSettingsAccordionComponent } from '../../../components/graph-setti
|
||||
<button
|
||||
type="button"
|
||||
(click)="onResetAll()"
|
||||
class="btn-standard-icon"
|
||||
class="btn-colored-xs btn-primary"
|
||||
title="Reset all settings">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
@ -57,7 +57,7 @@ import { GraphSettingsAccordionComponent } from '../../../components/graph-setti
|
||||
type="button"
|
||||
(click)="close.emit()"
|
||||
(keydown.escape)="close.emit()"
|
||||
class="btn-standard-icon"
|
||||
class="btn-colored-xs btn-neutral"
|
||||
aria-label="Close settings"
|
||||
title="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@ -133,6 +133,61 @@ import { GraphSettingsAccordionComponent } from '../../../components/graph-setti
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Colored shadows small buttons (shared look with tag manager) */
|
||||
.btn-colored-xs {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: #0f172a;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand) 18%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand) 8%, transparent) 100%);
|
||||
box-shadow: 0 6px 14px -10px color-mix(in oklab, var(--brand) 65%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--brand) 22%, transparent);
|
||||
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
.btn-colored-xs:hover,
|
||||
.btn-colored-xs:focus-visible {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 18px -10px color-mix(in oklab, var(--brand) 75%, transparent);
|
||||
border-color: color-mix(in oklab, var(--brand) 35%, transparent);
|
||||
}
|
||||
:host-context(.dark) .btn-colored-xs {
|
||||
color: #e2e8f0;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand-700) 22%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand-700) 12%, transparent) 100%);
|
||||
box-shadow: 0 10px 22px -14px color-mix(in oklab, var(--brand-700) 85%, transparent);
|
||||
border-color: color-mix(in oklab, var(--brand-700) 30%, transparent);
|
||||
}
|
||||
.btn-primary {
|
||||
color: white;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand-700) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--brand-700) 50%, transparent);
|
||||
}
|
||||
.btn-neutral {
|
||||
color: inherit;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--surface-1, #e5e7eb) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--surface-2, #d1d5db) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--border, #cbd5e1) 60%, transparent);
|
||||
}
|
||||
:host-context(.dark) .btn-neutral {
|
||||
color: #e2e8f0;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--card, #111827) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--surface2, #0b1220) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--border, #334155) 60%, transparent);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.panel-content {
|
||||
max-width: 100%;
|
||||
|
||||
@ -1,2 +1,66 @@
|
||||
/* Overlay styling relies on Tailwind utilities in the template. Keep minimal spacing fixes here if needed. */
|
||||
:host { display: contents; }
|
||||
|
||||
/* Small colored buttons with soft gradient and shadow ("Colored shadows") */
|
||||
.btn-colored-xs {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
color: #0f172a;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand) 18%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand) 8%, transparent) 100%);
|
||||
box-shadow: 0 6px 14px -10px color-mix(in oklab, var(--brand) 65%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--brand) 22%, transparent);
|
||||
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-colored-xs:hover,
|
||||
.btn-colored-xs:focus-visible {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 18px -10px color-mix(in oklab, var(--brand) 75%, transparent);
|
||||
border-color: color-mix(in oklab, var(--brand) 35%, transparent);
|
||||
}
|
||||
|
||||
:host-context(.dark) .btn-colored-xs {
|
||||
color: #e2e8f0;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand-700) 22%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand-700) 12%, transparent) 100%);
|
||||
box-shadow: 0 10px 22px -14px color-mix(in oklab, var(--brand-700) 85%, transparent);
|
||||
border-color: color-mix(in oklab, var(--brand-700) 30%, transparent);
|
||||
}
|
||||
|
||||
.btn-colored-active {
|
||||
outline: 2px solid color-mix(in oklab, var(--brand-700) 45%, transparent);
|
||||
}
|
||||
|
||||
/* Semantic variants for footer actions */
|
||||
.btn-primary {
|
||||
color: white;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--brand) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--brand-700) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--brand-700) 50%, transparent);
|
||||
}
|
||||
|
||||
.btn-neutral {
|
||||
color: inherit;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--surface-1, #e5e7eb) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--surface-2, #d1d5db) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--border, #cbd5e1) 60%, transparent);
|
||||
}
|
||||
|
||||
:host-context(.dark) .btn-neutral {
|
||||
color: #e2e8f0;
|
||||
background: linear-gradient(135deg,
|
||||
color-mix(in oklab, var(--card, #111827) 60%, transparent) 0%,
|
||||
color-mix(in oklab, var(--surface2, #0b1220) 60%, transparent) 100%);
|
||||
border-color: color-mix(in oklab, var(--border, #334155) 60%, transparent);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div class="fixed inset-0 z-50 flex items-end md:items-center justify-center">
|
||||
<div class="absolute inset-0 bg-black/40"></div>
|
||||
<div class="relative rounded-2xl shadow-xl border border-border dark:border-border bg-card dark:bg-main p-4 md:p-5 w-[min(780px,92vw)]">
|
||||
<div class="relative rounded-2xl shadow-xl border border-border dark:border-border bg-card dark:bg-main p-4 md:p-5 w-[min(880px,96vw)] md:max-h-[85vh] overflow-auto">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="h-5 w-5 text-muted" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h.01"/><path d="M3 7h5a2 2 0 0 1 1.414.586l7 7a2 2 0 0 1 0 2.828l-3.172 3.172a2 2 0 0 1-2.828 0l-7-7A2 2 0 0 1 3 12V7Z"/></svg>
|
||||
@ -12,38 +12,55 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex flex-wrap gap-2 rounded-xl border border-border dark:border-border p-3 min-h-[44px]">
|
||||
<div class="flex flex-col gap-4">
|
||||
<!-- Alphabet filter -->
|
||||
<div class="not-prose">
|
||||
<div class="flex flex-wrap items-center gap-1 md:gap-1.5">
|
||||
<button type="button" class="btn-colored-xs" [class.btn-colored-active]="letter()==='all'" (click)="letter.set('all')">Tous</button>
|
||||
@for (L of letters; track L) {
|
||||
<button type="button" class="btn-colored-xs" [class.btn-colored-active]="letter()===L" (click)="letter.set(L)">{{ L }}</button>
|
||||
}
|
||||
<button type="button" class="btn-colored-xs" [class.btn-colored-active]="letter()==='#'" (click)="letter.set('#')">#</button>
|
||||
<button type="button" class="btn-colored-xs" [class.btn-colored-active]="letter()==='other'" (click)="letter.set('other')">Autre</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selected tags + input -->
|
||||
<div class="flex flex-wrap items-center gap-2 rounded-xl border border-border dark:border-border p-3 min-h-[48px]">
|
||||
@for (t of working(); track t) {
|
||||
<span class="inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-sm font-medium bg-surface1 dark:bg-card">
|
||||
<span class="md-tag-badge" [ngClass]="tagColorClass(t)" [attr.data-tag]="t">
|
||||
{{ t }}
|
||||
<button type="button" class="w-6 h-6 inline-flex items-center justify-center rounded-full hover:bg-surface1 dark:hover:bg-surface2" (click)="removeTag(t)" aria-label="Retirer">
|
||||
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
||||
<button type="button" class="ml-1 inline-flex items-center justify-center w-5 h-5 rounded-full border border-transparent hover:border-border/60" (click)="removeTag(t)" aria-label="Retirer">
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
<input data-tag-input type="text" [value]="inputValue()" (input)="inputValue.set($any($event.target).value)" (keydown)="onKeydown($event)" placeholder="Ajouter un tag..." class="min-w-[200px] flex-1 bg-transparent outline-none px-2 py-1.5" />
|
||||
<input data-tag-input
|
||||
type="text"
|
||||
[value]="inputValue()"
|
||||
(input)="inputValue.set($any($event.target).value)"
|
||||
(keydown)="onKeydown($event)"
|
||||
placeholder="Ajouter un tag..."
|
||||
class="min-w-[200px] flex-1 w-full md:w-auto rounded-full border border-border bg-bg-muted/70 py-2.5 px-4 text-sm text-text-main placeholder:text-text-muted shadow-subtle focus:outline-none focus:ring-2 focus:ring-ring transition-all dark:border-border dark:bg-card/80 dark:text-gray-100 dark:placeholder-gray-400 dark:focus:ring-ring" />
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-border dark:border-border overflow-hidden">
|
||||
<div class="max-h-64 overflow-y-auto">
|
||||
<!-- Suggestions -->
|
||||
<div class="rounded-xl border border-border dark:border-border p-3">
|
||||
@if (suggestions().length === 0) {
|
||||
<div class="px-3 py-2 text-sm text-muted">Aucune suggestion</div>
|
||||
<div class="px-1 py-0.5 text-sm text-muted">Aucune suggestion</div>
|
||||
} @else {
|
||||
<ul>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@for (s of suggestions(); track s) {
|
||||
<li>
|
||||
<button type="button" class="w-full text-left px-3 py-2 hover:bg-surface1 dark:hover:bg-card" (click)="pickSuggestion(s)">{{ s }}</button>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<button type="button" class="md-tag-badge btn-colored-xs" [ngClass]="tagColorClass(s)" (click)="pickSuggestion(s)" [attr.data-tag]="s" [title]="'Ajouter #'+s">{{ s }}</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center justify-end gap-2 pt-1">
|
||||
<button type="button" class="px-3 py-1.5 rounded-lg border border-border dark:border-border hover:bg-surface1 dark:hover:bg-card" (click)="close.emit()">Annuler</button>
|
||||
<button type="button" class="px-3 py-1.5 rounded-lg bg-primary hover:bg-brand-700 text-white disabled:opacity-60" [disabled]="saving()" (click)="save()">Enregistrer</button>
|
||||
<button type="button" class="btn-colored-xs btn-neutral" (click)="close.emit()">Annuler</button>
|
||||
<button type="button" class="btn-colored-xs btn-primary" [disabled]="saving()" (click)="save()">Enregistrer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -28,10 +28,28 @@ export class TagEditorOverlayComponent {
|
||||
working = signal<string[]>([]);
|
||||
count = computed(() => this.working().length);
|
||||
|
||||
private readonly tagPaletteSize = 12;
|
||||
private readonly tagColorCache = new Map<string, number>();
|
||||
|
||||
// Alphabet filter state: 'all' | 'other' | '#', or 'a'..'z'
|
||||
letter = signal<string>('all');
|
||||
readonly letters = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
|
||||
|
||||
ngOnInit() {
|
||||
this.working.set(uniqueTags(this.value || []));
|
||||
}
|
||||
|
||||
tagColorClass(tag: string): string {
|
||||
if (!tag) return '';
|
||||
const normalized = `${tag}`.toLowerCase();
|
||||
if (this.tagColorCache.has(normalized)) return `md-tag-color-${this.tagColorCache.get(normalized)}`;
|
||||
let hash = 0;
|
||||
for (let i = 0; i < normalized.length; i++) hash = (hash * 31 + normalized.charCodeAt(i)) >>> 0;
|
||||
const colorIndex = hash % this.tagPaletteSize;
|
||||
this.tagColorCache.set(normalized, colorIndex);
|
||||
return `md-tag-color-${colorIndex}`;
|
||||
}
|
||||
|
||||
private allKnownTags = computed(() => {
|
||||
const provided = this.allTags || [];
|
||||
if (provided.length > 0) return provided;
|
||||
@ -44,10 +62,21 @@ export class TagEditorOverlayComponent {
|
||||
|
||||
suggestions = computed(() => {
|
||||
const q = this.inputValue().trim().toLowerCase();
|
||||
const selected = this.letter();
|
||||
const source = this.allKnownTags();
|
||||
const pool = q ? source.filter(t => t.toLowerCase().includes(q)) : source;
|
||||
|
||||
const matchesLetter = (t: string) => {
|
||||
if (selected === 'all') return true;
|
||||
const first = (t?.[0] || '').toUpperCase();
|
||||
if (selected === '#') return /[0-9]/.test(first);
|
||||
if (selected === 'other') return !/[A-Z0-9]/.test(first);
|
||||
return first === selected.toUpperCase();
|
||||
};
|
||||
|
||||
const byLetter = source.filter(matchesLetter);
|
||||
const byQuery = q ? byLetter.filter(t => t.toLowerCase().includes(q)) : byLetter;
|
||||
const exist = new Set(this.working().map(t => t.toLowerCase()));
|
||||
return pool.filter(t => !exist.has(t.toLowerCase())).slice(0, 50);
|
||||
return byQuery.filter(t => !exist.has(t.toLowerCase())).slice(0, 100);
|
||||
});
|
||||
|
||||
onKeydown(ev: KeyboardEvent) {
|
||||
|
||||
@ -12,9 +12,11 @@
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
class="px-3 py-1.5 rounded-full bg-slate-700/10 dark:bg-muted/10 text-sm font-medium hover:bg-slate-500/10 dark:hover:bg-surface2/10"
|
||||
class="md-tag-badge"
|
||||
*ngFor="let tag of normalizedTags()"
|
||||
[ngClass]="tagColorClass(tag)"
|
||||
(click)="onChipClick(tag)"
|
||||
[attr.data-tag]="tag"
|
||||
[title]="'Voir les notes #'+tag">
|
||||
{{ tag }}
|
||||
</button>
|
||||
|
||||
@ -32,6 +32,20 @@ export class TagManagerComponent {
|
||||
isEditing = signal(false);
|
||||
readonly normalizedTags = computed(() => uniqueTags(this.tagsSignal()));
|
||||
|
||||
private readonly tagPaletteSize = 12;
|
||||
private readonly tagColorCache = new Map<string, number>();
|
||||
|
||||
tagColorClass(tag: string): string {
|
||||
if (!tag) return '';
|
||||
const normalized = `${tag}`.toLowerCase();
|
||||
if (this.tagColorCache.has(normalized)) return `md-tag-color-${this.tagColorCache.get(normalized)}`;
|
||||
let hash = 0;
|
||||
for (let i = 0; i < normalized.length; i++) hash = (hash * 31 + normalized.charCodeAt(i)) >>> 0;
|
||||
const colorIndex = hash % this.tagPaletteSize;
|
||||
this.tagColorCache.set(normalized, colorIndex);
|
||||
return `md-tag-color-${colorIndex}`;
|
||||
}
|
||||
|
||||
toggleEditor(): void {
|
||||
const next = !this.isEditing();
|
||||
this.isEditing.set(next);
|
||||
|
||||
@ -59,6 +59,7 @@ export interface WikiLinkActivation {
|
||||
(copyRequested)="copyPath()"
|
||||
(openDirectory)="directoryClicked.emit(getDirectoryFromPath(note().filePath))"
|
||||
(tagsChange)="onTagsChange($event)"
|
||||
(tagSelected)="tagClicked.emit($event)"
|
||||
></app-note-header>
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
@ -116,15 +117,15 @@ export interface WikiLinkActivation {
|
||||
⋯
|
||||
</button>
|
||||
@if (menuOpen()) {
|
||||
<div class="absolute right-0 mt-2 w-56 rounded-md border border-border bg-card shadow-subtle not-prose z-10">
|
||||
<button type="button" class="block w-full text-left px-3 py-2 hover:bg-muted" (click)="parametersRequested.emit(); closeMenu()">
|
||||
<div class="absolute right-0 mt-2 w-56 rounded-xl border border-border bg-card shadow-subtle not-prose z-10 overflow-hidden">
|
||||
<button type="button" class="block w-full text-left px-3 py-2 text-sm transition-colors hover:bg-[rgba(99,102,241,0.12)] dark:hover:bg-[rgba(99,102,241,0.28)] focus-visible:bg-[rgba(99,102,241,0.16)] dark:focus-visible:bg-[rgba(99,102,241,0.35)]" (click)="parametersRequested.emit(); closeMenu()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="inline h-4 w-4 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v6m0 6v6m-6-6h6m6 0h-6M4.93 4.93l4.24 4.24m5.66 5.66l4.24 4.24m-4.24-14.14l4.24-4.24M4.93 19.07l4.24-4.24"/>
|
||||
</svg>
|
||||
Parameters
|
||||
</button>
|
||||
<button type="button" class="block w-full text-left px-3 py-2 hover:bg-muted" (click)="legacyRequested.emit(); closeMenu()">🔧 Legacy</button>
|
||||
<button type="button" class="block w-full text-left px-3 py-2 text-sm transition-colors hover:bg-[rgba(99,102,241,0.12)] dark:hover:bg-[rgba(99,102,241,0.28)] focus-visible:bg-[rgba(99,102,241,0.16)] dark:focus-visible:bg-[rgba(99,102,241,0.35)]" (click)="legacyRequested.emit(); closeMenu()">🔧 Legacy</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -126,7 +126,9 @@ export class MarkdownService {
|
||||
if (this.canUseFastPath(markdown)) {
|
||||
const env: MarkdownRenderEnv = { codeBlockIndex: 0 };
|
||||
this.activeSlugState = new Map<string, number>();
|
||||
return this.md.render(markdown, env);
|
||||
// Even on fast path, decorate inline #tags so they render as clickable badges
|
||||
const decoratedFast = this.decorateInlineTags(markdown);
|
||||
return this.md.render(decoratedFast, env);
|
||||
}
|
||||
|
||||
const env: MarkdownRenderEnv = { codeBlockIndex: 0 };
|
||||
|
||||
@ -4,7 +4,10 @@ auteur: Bruno Charest
|
||||
creation_date: 2025-10-19T11:13:12-04:00
|
||||
modification_date: 2025-10-19T12:09:46-04:00
|
||||
catégorie: ""
|
||||
tags: []
|
||||
tags:
|
||||
- configuration
|
||||
- test
|
||||
- tag3
|
||||
aliases: []
|
||||
status: en-cours
|
||||
publish: false
|
||||
@ -17,4 +20,7 @@ private: false
|
||||
---
|
||||
# Archived Note
|
||||
|
||||
#bruno
|
||||
|
||||
|
||||
This note was archived and moved to trash.
|
||||
|
||||
@ -4,7 +4,10 @@ auteur: Bruno Charest
|
||||
creation_date: 2025-10-19T11:13:12-04:00
|
||||
modification_date: 2025-10-19T12:09:46-04:00
|
||||
catégorie: ""
|
||||
tags: []
|
||||
tags:
|
||||
- configuration
|
||||
- test
|
||||
- tag3
|
||||
aliases: []
|
||||
status: en-cours
|
||||
publish: false
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user