feat: ajouter support background images + filtres CSS overlay sur note cards avec classes .note-has-bg (background-image cover/center), 7 filtres ::after pseudo (glass backdrop-blur 2px, vignette radial-gradient dark edges, lined repeating 28px horizontal, grid 28px squared, noise SVG fractalNoise 0.06 opacity, dots radial 14px, stripes diagonal -45deg), z-index layering .note-inner/hover-actions au-dessus overlay, et sync panel dataset (color/background/filter/fontColor) après chaque action set

This commit is contained in:
Bruno Charest 2026-04-21 11:37:58 -04:00
parent 5674688e02
commit 1313f78b93
2 changed files with 130 additions and 4 deletions

View File

@ -1580,4 +1580,103 @@ body.view-notes .notes-masonry:empty::after {
.bg-studio-clear:hover { .bg-studio-clear:hover {
background: color-mix(in srgb, var(--text-main) 10%, transparent); background: color-mix(in srgb, var(--text-main) 10%, transparent);
color: var(--special-view-strong); color: var(--special-view-strong);
}
/* =========================================================
Note / Todo card background image display
========================================================= */
.note-card.note-has-bg {
background-image: var(--note-bg-image, none) !important;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.note-modal.note-has-bg {
background-image: var(--note-bg-image, none) !important;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
/* =========================================================
Note / Todo card CSS filter overlays (::after pseudo)
========================================================= */
.note-card {
position: relative;
}
.note-card.note-filter-glass::after,
.note-card.note-filter-vignette::after,
.note-card.note-filter-lined::after,
.note-card.note-filter-grid::after,
.note-card.note-filter-noise::after,
.note-card.note-filter-dots::after,
.note-card.note-filter-stripes::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
border-radius: inherit;
}
/* Filter: Glass — frosted glass tint */
.note-card.note-filter-glass::after {
background: rgba(255, 255, 255, 0.06);
backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px);
}
/* Filter: Vignette — dark edges */
.note-card.note-filter-vignette::after {
background: radial-gradient(ellipse at center, transparent 45%, rgba(0, 0, 0, 0.42) 100%);
}
/* Filter: Lined — horizontal ruled lines */
.note-card.note-filter-lined::after {
background-image: repeating-linear-gradient(
to bottom,
transparent 0px,
transparent 27px,
rgba(128, 128, 128, 0.18) 27px,
rgba(128, 128, 128, 0.18) 28px
);
}
/* Filter: Grid — squared grid */
.note-card.note-filter-grid::after {
background-image:
repeating-linear-gradient(to right, rgba(128, 128, 128, 0.15) 0px, rgba(128, 128, 128, 0.15) 1px, transparent 1px, transparent 28px),
repeating-linear-gradient(to bottom, rgba(128, 128, 128, 0.15) 0px, rgba(128, 128, 128, 0.15) 1px, transparent 1px, transparent 28px);
}
/* Filter: Noise — subtle stipple effect */
.note-card.note-filter-noise::after {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E");
background-repeat: repeat;
}
/* Filter: Dots — dot pattern */
.note-card.note-filter-dots::after {
background-image: radial-gradient(circle, rgba(128, 128, 128, 0.3) 1px, transparent 1px);
background-size: 14px 14px;
}
/* Filter: Stripes — diagonal lines */
.note-card.note-filter-stripes::after {
background-image: repeating-linear-gradient(
-45deg,
transparent 0px,
transparent 8px,
rgba(128, 128, 128, 0.12) 8px,
rgba(128, 128, 128, 0.12) 9px
);
}
/* Keep card inner content above the filter overlay */
.note-card .note-inner,
.note-card .note-hover-actions {
position: relative;
z-index: 1;
} }

View File

@ -1358,8 +1358,12 @@ function ensureBackgroundStudioPanel() {
renderBackgroundStudioPanel(panelEl); renderBackgroundStudioPanel(panelEl);
} else if (mode === "modal") { } else if (mode === "modal") {
setModalNoteColor(key); setModalNoteColor(key);
panelEl.dataset.color = key;
renderBackgroundStudioPanel(panelEl);
} else { } else {
setNoteColor(entityId, key, editUrl); setNoteColor(entityId, key, editUrl);
panelEl.dataset.color = key;
renderBackgroundStudioPanel(panelEl);
} }
return; return;
} }
@ -1372,23 +1376,31 @@ function ensureBackgroundStudioPanel() {
renderBackgroundStudioPanel(panelEl); renderBackgroundStudioPanel(panelEl);
} else if (mode === "modal") { } else if (mode === "modal") {
setModalNoteBackground(key); setModalNoteBackground(key);
panelEl.dataset.background = key;
renderBackgroundStudioPanel(panelEl);
} else { } else {
setNoteBackground(entityId, key, editUrl); setNoteBackground(entityId, key, editUrl);
panelEl.dataset.background = key;
renderBackgroundStudioPanel(panelEl);
} }
return; return;
} }
if (action === "set-filter") { if (action === "set-filter") {
const filterKey = actionBtn.dataset.filter || "none"; const filterKey = actionBtn.dataset.filter || "none";
const normalizedFilter = normalizeFilterKey(filterKey || "") || "none";
if (mode === "draft") { if (mode === "draft") {
const normalized = normalizeFilterKey(filterKey || "") || "none"; panelEl.dataset.filter = normalizedFilter;
panelEl.dataset.filter = normalized; applyDraft({ filter: normalizedFilter });
applyDraft({ filter: normalized });
renderBackgroundStudioPanel(panelEl); renderBackgroundStudioPanel(panelEl);
} else if (mode === "modal") { } else if (mode === "modal") {
setModalNoteFilter(filterKey); setModalNoteFilter(filterKey);
panelEl.dataset.filter = normalizedFilter;
renderBackgroundStudioPanel(panelEl);
} else { } else {
setNoteFilter(entityId, filterKey, editUrl); setNoteFilter(entityId, filterKey, editUrl);
panelEl.dataset.filter = normalizedFilter;
renderBackgroundStudioPanel(panelEl);
} }
return; return;
} }
@ -1404,12 +1416,19 @@ function ensureBackgroundStudioPanel() {
if (action === "set-defaults") { if (action === "set-defaults") {
if (mode === "draft") { if (mode === "draft") {
panelEl.dataset.color = "default"; panelEl.dataset.color = "default";
applyDraft({ color: "default" }); panelEl.dataset.background = "none";
applyDraft({ color: "default", background: "none" });
renderBackgroundStudioPanel(panelEl); renderBackgroundStudioPanel(panelEl);
} else if (mode === "modal") { } else if (mode === "modal") {
setModalNoteColor("default"); setModalNoteColor("default");
panelEl.dataset.color = "default";
panelEl.dataset.background = "none";
renderBackgroundStudioPanel(panelEl);
} else { } else {
setNoteColor(entityId, "default", editUrl); setNoteColor(entityId, "default", editUrl);
panelEl.dataset.color = "default";
panelEl.dataset.background = "none";
renderBackgroundStudioPanel(panelEl);
} }
return; return;
} }
@ -1421,8 +1440,12 @@ function ensureBackgroundStudioPanel() {
renderBackgroundStudioPanel(panelEl); renderBackgroundStudioPanel(panelEl);
} else if (mode === "modal") { } else if (mode === "modal") {
setModalNoteFontColor("auto"); setModalNoteFontColor("auto");
panelEl.dataset.fontColor = "auto";
renderBackgroundStudioPanel(panelEl);
} else { } else {
setNoteFontColor(entityId, "auto", editUrl); setNoteFontColor(entityId, "auto", editUrl);
panelEl.dataset.fontColor = "auto";
renderBackgroundStudioPanel(panelEl);
} }
return; return;
} }
@ -1445,8 +1468,12 @@ function ensureBackgroundStudioPanel() {
renderBackgroundStudioPanel(panelEl); renderBackgroundStudioPanel(panelEl);
} else if (mode === "modal") { } else if (mode === "modal") {
setModalNoteFontColor(fontColorKey); setModalNoteFontColor(fontColorKey);
panelEl.dataset.fontColor = fontColorKey;
renderBackgroundStudioPanel(panelEl);
} else { } else {
setNoteFontColor(entityId, fontColorKey, editUrl); setNoteFontColor(entityId, fontColorKey, editUrl);
panelEl.dataset.fontColor = fontColorKey;
renderBackgroundStudioPanel(panelEl);
} }
return; return;
} }