diff --git a/shaarli-pro/css/custom_views.css b/shaarli-pro/css/custom_views.css index 959c586..6fac56a 100644 --- a/shaarli-pro/css/custom_views.css +++ b/shaarli-pro/css/custom_views.css @@ -542,6 +542,100 @@ body.view-notes .content-container { color: #e8eaed; } +.bookmark-palette { + display: inline-flex; + align-items: center; + position: relative; +} + +.bookmark-palette > button { + background: none; + border: none; + width: 34px; + height: 34px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-light, #5f6368); + cursor: pointer; + font-size: 1.1rem; + transition: background-color 0.2s, color 0.2s; +} + +[data-theme="dark"] .bookmark-palette > button { + color: #9aa0a6; +} + +.palette-popup { + display: none; + position: absolute; + left: 0; + bottom: calc(100% + 8px); + background: var(--background-secondary, #ffffff); + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 12px; + padding: 10px; + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18); + z-index: 50; + width: max-content; + max-width: min(340px, calc(100vw - 32px)); +} + +[data-theme="dark"] .palette-popup { + background: #202124; + border-color: rgba(255, 255, 255, 0.16); +} + +.palette-popup.open { + display: block; +} + +.palette-row { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.palette-row + .palette-row { + margin-top: 10px; +} + +.palette-btn { + width: 24px; + height: 24px; + border-radius: 50%; + border: 1px solid rgba(0, 0, 0, 0.18); + cursor: pointer; + padding: 0; + background-position: center bottom; + background-size: cover; +} + +[data-theme="dark"] .palette-btn { + border-color: rgba(255, 255, 255, 0.22); +} + +.palette-btn.is-active { + outline: 2px solid var(--primary-color, #2563eb); + outline-offset: 2px; +} + +.palette-btn-bg-none { + display: flex; + align-items: center; + justify-content: center; +} + +.note-modal-color-picker { + position: relative; +} + +.palette-popup.note-modal-palette { + bottom: auto; + top: calc(100% + 8px); +} + .spacer { flex: 1; } @@ -708,18 +802,12 @@ body.view-notes .content-container { --note-card-fg: #2a2d31; } -[data-theme="dark"] .note-card.note-color-grey { - background-color: #e8eaed; - border-color: transparent; - --note-card-fg: #2a2d31; -} - .note-card.note-has-bg, .note-modal.note-has-bg, .link-outer.note-has-bg { background-image: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16)), var(--note-bg-image); background-size: cover; - background-position: center; + background-position: center bottom; } .note-card .note-title, @@ -734,642 +822,83 @@ body.view-notes .content-container { color: var(--note-card-fg, #202124); } -.link-outer[class*="note-color-"] { - color: var(--note-card-fg, #202124); -} - -.link-outer.note-color-default { - background-color: #20293a; - border-color: transparent; - --note-card-fg: #dbe7ff; -} - -[data-theme="dark"] .link-outer.note-color-default { - background-color: #20293a; - border-color: transparent; - --note-card-fg: #dbe7ff; -} - -.link-outer.note-color-red { - background-color: #f28b82; - border-color: transparent; - --note-card-fg: #2f1714; -} - -[data-theme="dark"] .link-outer.note-color-red { - background-color: #f28b82; - border-color: transparent; - --note-card-fg: #2f1714; -} - -.link-outer.note-color-orange { - background-color: #fbbc04; - border-color: transparent; - --note-card-fg: #3d2a00; -} - -[data-theme="dark"] .link-outer.note-color-orange { - background-color: #fbbc04; - border-color: transparent; - --note-card-fg: #3d2a00; -} - -.link-outer.note-color-yellow { - background-color: #fff475; - border-color: transparent; - --note-card-fg: #383100; -} - -[data-theme="dark"] .link-outer.note-color-yellow { - background-color: #fff475; - border-color: transparent; - --note-card-fg: #383100; -} - -.link-outer.note-color-green { - background-color: #ccff90; - border-color: transparent; - --note-card-fg: #203400; -} - -[data-theme="dark"] .link-outer.note-color-green { - background-color: #ccff90; - border-color: transparent; - --note-card-fg: #203400; -} - -.link-outer.note-color-teal { - background-color: #a7ffeb; - border-color: transparent; - --note-card-fg: #08342d; -} - -[data-theme="dark"] .link-outer.note-color-teal { - background-color: #a7ffeb; - border-color: transparent; - --note-card-fg: #08342d; -} - -.link-outer.note-color-blue { - background-color: #cbf0f8; - border-color: transparent; - --note-card-fg: #113541; -} - -[data-theme="dark"] .link-outer.note-color-blue { - background-color: #cbf0f8; - border-color: transparent; - --note-card-fg: #113541; -} - -.link-outer.note-color-darkblue { - background-color: #aecbfa; - border-color: transparent; - --note-card-fg: #102645; -} - -[data-theme="dark"] .link-outer.note-color-darkblue { - background-color: #aecbfa; - border-color: transparent; - --note-card-fg: #102645; -} - -.link-outer.note-color-purple { - background-color: #d7aefb; - border-color: transparent; - --note-card-fg: #2f1845; -} - -[data-theme="dark"] .link-outer.note-color-purple { - background-color: #d7aefb; - border-color: transparent; - --note-card-fg: #2f1845; -} - -.link-outer.note-color-pink { - background-color: #fdcfe8; - border-color: transparent; - --note-card-fg: #4a1d34; -} - -[data-theme="dark"] .link-outer.note-color-pink { - background-color: #fdcfe8; - border-color: transparent; - --note-card-fg: #4a1d34; -} - -.link-outer.note-color-brown { - background-color: #e6c9a8; - border-color: transparent; - --note-card-fg: #3c2714; -} - -[data-theme="dark"] .link-outer.note-color-brown { - background-color: #e6c9a8; - border-color: transparent; - --note-card-fg: #3c2714; -} - -.link-outer.note-color-grey { - background-color: #e8eaed; - border-color: transparent; - --note-card-fg: #2a2d31; -} - -[data-theme="dark"] .link-outer.note-color-grey { - background-color: #e8eaed; - border-color: transparent; - --note-card-fg: #2a2d31; -} - -.link-outer[class*="note-color-"] .link-title, -.link-outer[class*="note-color-"] .link-url, -.link-outer[class*="note-color-"] .link-meta, -.link-outer[class*="note-color-"] .link-description, -.link-outer[class*="note-color-"] .link-tag a, -.link-outer[class*="note-color-"] .link-actions a, -.link-outer[class*="note-color-"] .link-actions button, -.link-outer[class*="note-color-"] .bookmark-palette > button { - color: inherit; -} - -.link-actions .bookmark-palette { - display: flex; - align-items: center; -} - -.link-actions .bookmark-palette > button { - background: none; - border: none; - width: 36px; - height: 36px; - border-radius: 0.5rem; - display: flex; - align-items: center; - justify-content: center; - padding: 0; - cursor: pointer; -} - -.link-actions .bookmark-palette > button i { - font-size: 1.15rem; -} - -.link-actions .bookmark-palette > button:hover { - background: rgba(255, 255, 255, 0.08); -} - -.link-actions .bookmark-palette .palette-popup { - left: 0; - right: auto; -} - -/* --- PALETTE POPUP --- */ -.palette-popup { - position: absolute; - bottom: 100%; - left: 0; - width: min(500px, 92vw); - background: #1f232b; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); - border-radius: 12px; - padding: 0; - z-index: 5000; - display: none; - /* JS toggles this */ -} - -[data-theme="dark"] .palette-popup { - background: #1f232b; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5); - border: 1px solid #5f6368; -} - -.palette-popup.open { - display: block; -} - -.palette-popup.open-down { - top: calc(100% + 8px); - bottom: auto; -} - -.palette-btn { - width: 32px; - height: 32px; - min-width: 32px; - min-height: 32px; - padding: 0; - border-radius: 50%; - border: 1px solid rgba(255, 255, 255, 0.18); - cursor: pointer; - display: inline-flex; - align-items: center; - justify-content: center; - position: relative; - flex: 0 0 auto; - background-position: center; +/* --- NOTES: Vue Masonry/Grid (multi-colonnes, largeur variable) --- */ +.notes-masonry .note-card.note-has-bg { + /* Les cartes masonry ont des largeurs variables selon les breakpoints: + - >1200px: ~25% (4 colonnes) + - 800-1200px: ~33% (3 colonnes) + - 500-800px: ~50% (2 colonnes) + - <500px: 100% (1 colonne) + On utilise 'cover' avec un focus sur le centre pour garder l'essentiel visible */ background-size: cover; + background-position: center bottom; + /* Pour les petites cartes en masonry, on s'assure que l'image couvre bien */ + min-height: 120px; } -.palette-btn:hover { - border-color: rgba(255, 255, 255, 0.8); -} - -[data-theme="dark"] .palette-btn { - border-color: rgba(255, 255, 255, 0.2); -} - -.palette-btn.is-active { - outline: 2px solid #a855f7; - outline-offset: 1px; -} - -.palette-row { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 12px; - overflow-x: auto; - flex-wrap: nowrap; - scrollbar-width: thin; -} - -.palette-row::-webkit-scrollbar { - height: 6px; -} - -.palette-row::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.24); - border-radius: 999px; -} - -.palette-row+.palette-row { - border-top: 1px solid rgba(255, 255, 255, 0.14); -} - -.palette-btn-default, -.palette-btn-bg-none { - background: #2b313c; - color: #d7dce5; - display: inline-flex; - align-items: center; - justify-content: center; -} - -.palette-btn-default i, -.palette-btn-bg-none i { - font-size: 1rem; -} - -/* Prevent link action generic button rules from deforming swatches in bookmark palette */ -.link-actions .palette-popup .palette-btn { - width: 32px; - height: 32px; - min-width: 32px; - min-height: 32px; - border-radius: 50%; - padding: 0; - background: transparent; - border: 1px solid rgba(255, 255, 255, 0.18); - background-position: center; +/* --- NOTES: Vue Liste (600px max, centré) --- */ +.notes-list-view .note-card.note-has-bg { + /* Vue liste: largeur fixe de 600px, cards plus larges qu'en masonry + On peut utiliser cover mais avec une position légèrement ajustée */ background-size: cover; + background-position: center bottom; + /* Les cards en liste sont souvent plus hautes, on adapte */ + min-height: 100px; } -.link-actions .palette-popup .palette-btn:hover { - background: transparent; - border-color: rgba(255, 255, 255, 0.8); +/* --- NOTES: Modal (min(720px, 92vw)) --- */ +.note-modal.note-has-bg { + /* Modal plus large (jusqu'à 720px), on privilégie une couverture complète + avec une légère obscurcissement pour la lisibilité du texte */ + background-size: cover; + background-position: center bottom; + /* L'overlay gradient est déjà présent dans la règle de base */ } -.link-outer.palette-open, -.view-list .link-outer.palette-open, -.view-compact .link-outer.palette-open { - overflow: visible; - z-index: 4000; - content-visibility: visible; - contain: none; - contain-intrinsic-size: auto; +/* --- BOOKMARKS: Vue Grid (minmax(320px, 1fr)) --- */ +.view-grid .link-outer.note-has-bg { + /* Grid bookmarks: cards de minimum 320px, layout en grille + Les cards sont généralement carrées ou rectangulaires selon le contenu */ + background-size: cover; + background-position: center bottom; + /* S'assurer que le background couvre bien la card avec le padding existant */ + background-origin: padding-box; } -/* --- MODAL FOR NOTE VIEW --- */ -.note-modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.6); - z-index: 1000; - display: flex; - align-items: center; - justify-content: center; - backdrop-filter: blur(2px); - opacity: 0; - pointer-events: none; - transition: opacity 0.2s; +/* --- BOOKMARKS: Vue Liste (1 colonne, thumbnail latéral) --- */ +.view-list .link-outer.note-has-bg { + /* List view: cards en pleine largeur avec layout flex et thumbnail de 300px + On ajuste pour que le background couvre toute la hauteur malgré le thumbnail */ + background-size: cover; + background-position: center bottom; + /* Le thumbnail a son propre mask gradient, on s'assure que le background + couvre bien toute la card derrière le contenu */ + background-origin: padding-box; } -.note-modal-overlay.open { - opacity: 1; - pointer-events: auto; +/* --- BOOKMARKS: Vue Compact (liste dense, pas de thumbnail) --- */ +.view-compact .link-outer.note-has-bg { + /* Compact view: cards très compactes sans thumbnail, hauteur réduite (~60px) + On utilise contain ou une taille spécifique pour éviter que l'image + soit trop étirée sur une si petite hauteur */ + background-size: 200% auto; + background-position: center bottom; + /* Réduire l'opacité du gradient pour plus de visibilité sur petites cards */ + background-image: linear-gradient(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.08)), var(--note-bg-image); } -.note-modal { - background: var(--modal-note-bg, #7a4b00); - color: var(--modal-note-fg, #fff2d9); - width: min(720px, 92vw); - max-height: 88vh; - border-radius: 10px; - overflow: hidden; - box-shadow: 0 12px 32px rgba(0, 0, 0, 0.42); - position: relative; - display: flex; - flex-direction: column; - --note-scrollbar-thumb: rgba(255, 229, 170, 0.75); - --note-separator: rgba(255, 230, 182, 0.22); - --note-footer-bg: rgba(0, 0, 0, 0.14); -} - -.note-modal.note-color-default { - --modal-note-bg: #20293a; - --modal-note-fg: #dbe7ff; - --note-scrollbar-thumb: rgba(219, 231, 255, 0.45); - --note-separator: rgba(219, 231, 255, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.08); -} - -.note-modal.note-color-red { - --modal-note-bg: #f28b82; - --modal-note-fg: #2f1714; - --note-scrollbar-thumb: rgba(47, 23, 20, 0.45); - --note-separator: rgba(47, 23, 20, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.18); -} - -.note-modal.note-color-orange { - --modal-note-bg: #fbbc04; - --modal-note-fg: #3d2a00; - --note-scrollbar-thumb: rgba(61, 42, 0, 0.45); - --note-separator: rgba(61, 42, 0, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.2); -} - -.note-modal.note-color-yellow { - --modal-note-bg: #fff475; - --modal-note-fg: #383100; - --note-scrollbar-thumb: rgba(56, 49, 0, 0.45); - --note-separator: rgba(56, 49, 0, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.24); -} - -.note-modal.note-color-green { - --modal-note-bg: #ccff90; - --modal-note-fg: #203400; - --note-scrollbar-thumb: rgba(32, 52, 0, 0.45); - --note-separator: rgba(32, 52, 0, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.22); -} - -.note-modal.note-color-teal { - --modal-note-bg: #a7ffeb; - --modal-note-fg: #08342d; - --note-scrollbar-thumb: rgba(8, 52, 45, 0.45); - --note-separator: rgba(8, 52, 45, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.22); -} - -.note-modal.note-color-blue { - --modal-note-bg: #cbf0f8; - --modal-note-fg: #113541; - --note-scrollbar-thumb: rgba(17, 53, 65, 0.45); - --note-separator: rgba(17, 53, 65, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.22); -} - -.note-modal.note-color-darkblue { - --modal-note-bg: #aecbfa; - --modal-note-fg: #102645; - --note-scrollbar-thumb: rgba(16, 38, 69, 0.45); - --note-separator: rgba(16, 38, 69, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.2); -} - -.note-modal.note-color-purple { - --modal-note-bg: #d7aefb; - --modal-note-fg: #2f1845; - --note-scrollbar-thumb: rgba(47, 24, 69, 0.45); - --note-separator: rgba(47, 24, 69, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.2); -} - -.note-modal.note-color-pink { - --modal-note-bg: #fdcfe8; - --modal-note-fg: #4a1d34; - --note-scrollbar-thumb: rgba(74, 29, 52, 0.45); - --note-separator: rgba(74, 29, 52, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.2); -} - -.note-modal.note-color-brown { - --modal-note-bg: #e6c9a8; - --modal-note-fg: #3c2714; - --note-scrollbar-thumb: rgba(60, 39, 20, 0.45); - --note-separator: rgba(60, 39, 20, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.2); -} - -.note-modal.note-color-grey { - --modal-note-bg: #e8eaed; - --modal-note-fg: #2a2d31; - --note-scrollbar-thumb: rgba(42, 45, 49, 0.45); - --note-separator: rgba(42, 45, 49, 0.2); - --note-footer-bg: rgba(255, 255, 255, 0.2); -} - -[data-theme="dark"] .note-modal { - border: 1px solid rgba(255, 255, 255, 0.12); -} - -.note-modal-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 12px; - padding: 18px 20px 10px; - flex-shrink: 0; -} - -.note-modal .note-title { - font-size: 1.6rem; - line-height: 1.35; - margin: 0; - color: inherit; - font-weight: 500; -} - -.note-modal-pin-toggle { - background: transparent; - border: none; - color: inherit; - opacity: 0.85; - width: 34px; - height: 34px; - border-radius: 50%; - display: inline-flex; - align-items: center; - justify-content: center; - cursor: pointer; - flex-shrink: 0; - transition: background-color 0.2s, opacity 0.2s; -} - -.note-modal-pin-toggle i { - font-size: 1.2rem; -} - -.note-modal-pin-toggle:hover, -.note-modal-pin-toggle.active { - opacity: 1; - background-color: rgba(255, 255, 255, 0.14); -} - -.note-modal-content { - flex: 1; - overflow-y: auto; - padding: 0 20px 18px; - scrollbar-width: thin; - scrollbar-color: var(--note-scrollbar-thumb) transparent; -} - -.note-modal-content::-webkit-scrollbar { - width: 10px; -} - -.note-modal-content::-webkit-scrollbar-track { - background: transparent; -} - -.note-modal-content::-webkit-scrollbar-thumb { - background: var(--note-scrollbar-thumb); - border-radius: 10px; - border: 2px solid transparent; - background-clip: content-box; -} - -.note-modal .note-body { - font-size: 1rem; - line-height: 1.75; - display: block; - -webkit-line-clamp: initial; - line-clamp: initial; - -webkit-box-orient: initial; - max-height: none; - overflow: visible; - color: inherit; -} - -.note-modal .note-body * { - color: inherit; -} - -.note-modal-tags { - display: flex; - flex-wrap: wrap; - gap: 8px; - padding: 10px 20px 12px; - border-top: 1px solid var(--note-separator); - flex-shrink: 0; -} - -.note-modal-tags.is-empty { - display: none; -} - -.note-modal-tags .note-tag { - background: rgba(255, 255, 255, 0.12); - border: 1px solid rgba(255, 255, 255, 0.22); - color: inherit; - border-radius: 999px; - padding: 4px 10px; - font-size: 0.72rem; - letter-spacing: 0.02em; -} - -.note-modal-actions { - display: flex; - align-items: center; - justify-content: space-between; - gap: 10px; - padding: 8px 12px; - border-top: 1px solid var(--note-separator); - background: var(--note-footer-bg); - flex-shrink: 0; -} - -.note-modal-actions-left { - display: flex; - align-items: center; - gap: 2px; - flex-wrap: wrap; -} - -.note-modal-actions-left > button, -.note-modal-actions-left > a, -.note-modal-actions-left > .note-modal-color-picker > button { - background: transparent; - border: none; - color: inherit; - opacity: 0.9; - width: 32px; - height: 32px; - border-radius: 50%; - display: inline-flex; - align-items: center; - justify-content: center; - cursor: pointer; - text-decoration: none; - transition: background-color 0.2s, opacity 0.2s; -} - -.note-modal-actions-left > button:hover, -.note-modal-actions-left > a:hover, -.note-modal-actions-left > .note-modal-color-picker > button:hover { - opacity: 1; - background: rgba(255, 255, 255, 0.14); -} - -.note-modal-color-picker { - position: relative; - display: inline-flex; -} - -.note-modal-palette { - left: -8px; - bottom: calc(100% + 8px); - width: min(500px, 92vw); -} - -.note-modal-close-btn { - background: transparent; - border: none; - color: inherit; - font-weight: 600; - border-radius: 8px; - padding: 6px 10px; - cursor: pointer; -} - -.note-modal-close-btn:hover { - background: rgba(255, 255, 255, 0.14); -} - -@media (max-width: 640px) { - .note-modal { - width: 96vw; - max-height: 92vh; +/* Responsive: sur petits écrans, ajuster les backgrounds */ +@media (max-width: 768px) { + /* En mobile, les cards sont plus étroites, on ajuste */ + .notes-masonry .note-card.note-has-bg, + .view-grid .link-outer.note-has-bg { + background-size: cover; + background-position: center bottom; } - - .note-modal .note-title { - font-size: 1.25rem; + + /* Vue liste en mobile: thumbnail passe en haut */ + .view-list .link-outer.note-has-bg { + background-size: cover; + background-position: center bottom; } } \ No newline at end of file diff --git a/shaarli-pro/img/gg-note-bg-light/bg-JournalDeTravail.png b/shaarli-pro/img/gg-note-bg-light/bg-JournalDeTravail.png deleted file mode 100644 index f609893..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-JournalDeTravail.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-Radio.png b/shaarli-pro/img/gg-note-bg-light/bg-Radio.png deleted file mode 100644 index 3967cc8..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-Radio.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-cafe.png b/shaarli-pro/img/gg-note-bg-light/bg-cafe.png deleted file mode 100644 index f242566..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-cafe.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-cerisier.png b/shaarli-pro/img/gg-note-bg-light/bg-cerisier.png deleted file mode 100644 index 752deea..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-cerisier.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-codes.png b/shaarli-pro/img/gg-note-bg-light/bg-codes.png deleted file mode 100644 index aee42a8..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-codes.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-feuilleLigne.png b/shaarli-pro/img/gg-note-bg-light/bg-feuilleLigne.png deleted file mode 100644 index 9839d52..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-feuilleLigne.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-feuilleQuadrille.png b/shaarli-pro/img/gg-note-bg-light/bg-feuilleQuadrille.png deleted file mode 100644 index cfe48aa..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-feuilleQuadrille.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-foret.png b/shaarli-pro/img/gg-note-bg-light/bg-foret.png deleted file mode 100644 index b1f2cb9..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-foret.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-legumes.png b/shaarli-pro/img/gg-note-bg-light/bg-legumes.png deleted file mode 100644 index 6c13c80..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-legumes.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-livres.png b/shaarli-pro/img/gg-note-bg-light/bg-livres.png deleted file mode 100644 index b19dedc..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-livres.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-montagnes.png b/shaarli-pro/img/gg-note-bg-light/bg-montagnes.png deleted file mode 100644 index 391bfbe..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-montagnes.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-ocean.png b/shaarli-pro/img/gg-note-bg-light/bg-ocean.png deleted file mode 100644 index bbd82a7..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-ocean.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-vague1.png b/shaarli-pro/img/gg-note-bg-light/bg-vague1.png deleted file mode 100644 index 52b9c21..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-vague1.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-vague2.png b/shaarli-pro/img/gg-note-bg-light/bg-vague2.png deleted file mode 100644 index e298490..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-vague2.png and /dev/null differ diff --git a/shaarli-pro/img/gg-note-bg-light/bg-valise.png b/shaarli-pro/img/gg-note-bg-light/bg-valise.png deleted file mode 100644 index d6fb139..0000000 Binary files a/shaarli-pro/img/gg-note-bg-light/bg-valise.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/README.md b/shaarli-pro/img/note-backgrounds/README.md deleted file mode 100644 index 58c1ac1..0000000 --- a/shaarli-pro/img/note-backgrounds/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Note backgrounds (Shaarli Pro) - -Ce dossier contient les images de fond utilisées par la palette des notes (`notebg-*`). - -## Fichiers attendus - -Le thème référence actuellement ces fichiers : - -- `bg-canyon.png` -- `bg-leaves.png` -- `bg-shore.png` -- `bg-sunset.png` -- `bg-planet.png` -- `bg-crystal.png` -- `bg-orchid.png` -- `bg-lake.png` -- `bg-ladder.png` -- `bg-burst.png` - -## Formats recommandés - -- **SVG** (idéal pour motifs/illustrations légères) -- **JPG / JPEG** (photos) -- **PNG** (illustrations avec transparence) -- **WEBP** (poids réduit, recommandé) - -## Conseils d'image - -- Ratio conseillé: **16:9** ou **4:3** -- Taille conseillée: entre **1200x800** et **1920x1080** -- Poids conseillé: **< 500 KB** par image pour garder l'interface fluide -- Privilégier des visuels **peu chargés** pour conserver la lisibilité du texte - -Si vous remplacez une image, conservez le même nom de fichier pour qu'elle apparaisse automatiquement dans la palette. diff --git a/shaarli-pro/img/note-backgrounds/bg-burst.png b/shaarli-pro/img/note-backgrounds/bg-burst.png deleted file mode 100644 index 71c144d..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-burst.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-canyon.png b/shaarli-pro/img/note-backgrounds/bg-canyon.png deleted file mode 100644 index 5149df4..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-canyon.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-crystal.png b/shaarli-pro/img/note-backgrounds/bg-crystal.png deleted file mode 100644 index ca143c3..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-crystal.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-ladder.png b/shaarli-pro/img/note-backgrounds/bg-ladder.png deleted file mode 100644 index b65c490..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-ladder.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-lake.png b/shaarli-pro/img/note-backgrounds/bg-lake.png deleted file mode 100644 index b822f2a..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-lake.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-leaves.png b/shaarli-pro/img/note-backgrounds/bg-leaves.png deleted file mode 100644 index a2e2965..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-leaves.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-orchid.png b/shaarli-pro/img/note-backgrounds/bg-orchid.png deleted file mode 100644 index 1d2fc98..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-orchid.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-planet.png b/shaarli-pro/img/note-backgrounds/bg-planet.png deleted file mode 100644 index 6047b81..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-planet.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-shore.png b/shaarli-pro/img/note-backgrounds/bg-shore.png deleted file mode 100644 index ca3f510..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-shore.png and /dev/null differ diff --git a/shaarli-pro/img/note-backgrounds/bg-sunset.png b/shaarli-pro/img/note-backgrounds/bg-sunset.png deleted file mode 100644 index f0224d9..0000000 Binary files a/shaarli-pro/img/note-backgrounds/bg-sunset.png and /dev/null differ diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_cafe.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-cafe.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_cafe.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-cafe.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_codes.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-codes.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_codes.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-codes.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_dune.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-dune.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_dune.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-dune.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_feuilleLigne.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-feuilleLigne.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_feuilleLigne.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-feuilleLigne.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_feuilleQuadrille.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-feuilleQuadrille.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_feuilleQuadrille.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-feuilleQuadrille.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_fleurs.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-fleurs.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_fleurs.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-fleurs.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_foret.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-foret.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_foret.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-foret.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_grid.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-grid.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_grid.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-grid.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_JournalDeTravail.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-journal.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_JournalDeTravail.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-journal.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_livres.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-lecture.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_livres.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-lecture.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_legumes.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-legumes.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_legumes.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-legumes.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_montagnes.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-montagnes.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_montagnes.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-montagnes.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_ocean.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-ocean.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_ocean.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-ocean.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_sports.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-sports.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_sports.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-sports.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_vague1.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-vague1.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_vague1.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-vague1.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_vague2.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-vague2.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_vague2.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-vague2.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_ville.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-ville.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_ville.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-ville.jpg diff --git a/shaarli-pro/img/note-bg-dark/bg-Dark_voyages.jpg b/shaarli-pro/img/note-bg-dark/bg-dark-voyage.jpg similarity index 100% rename from shaarli-pro/img/note-bg-dark/bg-Dark_voyages.jpg rename to shaarli-pro/img/note-bg-dark/bg-dark-voyage.jpg diff --git a/shaarli-pro/img/note-bg-light/bg-light-dune.jpg b/shaarli-pro/img/note-bg-light/bg-light-dune.jpg new file mode 100644 index 0000000..23d21f5 Binary files /dev/null and b/shaarli-pro/img/note-bg-light/bg-light-dune.jpg differ diff --git a/shaarli-pro/img/note-bg-light/bg-light-feuilleLignes.jpg b/shaarli-pro/img/note-bg-light/bg-light-feuilleLigne.jpg similarity index 100% rename from shaarli-pro/img/note-bg-light/bg-light-feuilleLignes.jpg rename to shaarli-pro/img/note-bg-light/bg-light-feuilleLigne.jpg diff --git a/shaarli-pro/img/note-bg-light/bg-light-feuilleQuadrilles.jpg b/shaarli-pro/img/note-bg-light/bg-light-feuilleQuadrille.jpg similarity index 100% rename from shaarli-pro/img/note-bg-light/bg-light-feuilleQuadrilles.jpg rename to shaarli-pro/img/note-bg-light/bg-light-feuilleQuadrille.jpg diff --git a/shaarli-pro/img/note-bg-light/bg-light-fleur.jpg b/shaarli-pro/img/note-bg-light/bg-light-fleurs.jpg similarity index 100% rename from shaarli-pro/img/note-bg-light/bg-light-fleur.jpg rename to shaarli-pro/img/note-bg-light/bg-light-fleurs.jpg diff --git a/shaarli-pro/img/note-bg-light/bg-light-grid.jpg b/shaarli-pro/img/note-bg-light/bg-light-grid.jpg new file mode 100644 index 0000000..d9a1928 Binary files /dev/null and b/shaarli-pro/img/note-bg-light/bg-light-grid.jpg differ diff --git a/shaarli-pro/img/note-bg-light/bg-light-sports.jpg b/shaarli-pro/img/note-bg-light/bg-light-sports.jpg new file mode 100644 index 0000000..3320c62 Binary files /dev/null and b/shaarli-pro/img/note-bg-light/bg-light-sports.jpg differ diff --git a/shaarli-pro/img/note-bg-light/bg-light-ville.jpg b/shaarli-pro/img/note-bg-light/bg-light-ville.jpg new file mode 100644 index 0000000..d586b31 Binary files /dev/null and b/shaarli-pro/img/note-bg-light/bg-light-ville.jpg differ diff --git a/shaarli-pro/includes.html b/shaarli-pro/includes.html index f990884..877c3f3 100644 --- a/shaarli-pro/includes.html +++ b/shaarli-pro/includes.html @@ -61,8 +61,8 @@ visibility: '{$visibility}', untaggedonly: {if="$untaggedonly"}true{else}false{/if} }; - - + + {if="file_exists('tpl/shaarli-pro/extra.html')"} {include="extra"} diff --git a/shaarli-pro/js/backgrounds-manifest.js b/shaarli-pro/js/backgrounds-manifest.js new file mode 100644 index 0000000..55f4d0f --- /dev/null +++ b/shaarli-pro/js/backgrounds-manifest.js @@ -0,0 +1,146 @@ +window.SHAARLI_NOTE_BACKGROUNDS_MANIFEST = [ + { + key: "cafe", + label: "Café", + files: { + light: "bg-light-cafe.jpg", + dark: "bg-dark-cafe.jpg", + }, + }, + { + key: "codes", + label: "Codes", + files: { + light: "bg-light-codes.jpg", + dark: "bg-dark-codes.jpg", + }, + }, + { + key: "dune", + label: "Dune", + files: { + light: "bg-light-dune.jpg", + dark: "bg-dark-dune.jpg", + }, + }, + { + key: "feuille-ligne", + label: "Feuille Ligne", + files: { + light: "bg-light-feuilleLigne.jpg", + dark: "bg-dark-feuilleLigne.jpg", + }, + }, + { + key: "feuille-quadrillage", + label: "Feuille Quadrillage", + files: { + light: "bg-light-feuilleQuadrille.jpg", + dark: "bg-dark-feuilleQuadrille.jpg", + }, + }, + { + key: "fleurs", + label: "Fleurs", + files: { + light: "bg-light-fleurs.jpg", + dark: "bg-dark-fleurs.jpg", + }, + }, + { + key: "foret", + label: "Forêt", + files: { + light: "bg-light-foret.jpg", + dark: "bg-dark-foret.jpg", + }, + }, + { + key: "grid", + label: "Grid", + files: { + light: "bg-light-grid.jpg", + dark: "bg-dark-grid.jpg", + }, + }, + { + key: "journal", + label: "Journal", + files: { + light: "bg-light-journal.jpg", + dark: "bg-dark-journal.jpg", + }, + }, + { + key: "lecture", + label: "Lecture", + files: { + light: "bg-light-lecture.jpg", + dark: "bg-dark-lecture.jpg", + }, + }, + { + key: "legumes", + label: "Légumes", + files: { + light: "bg-light-legumes.jpg", + dark: "bg-dark-legumes.jpg", + }, + }, + { + key: "montagnes", + label: "Montagnes", + files: { + light: "bg-light-montagnes.jpg", + dark: "bg-dark-montagnes.jpg", + }, + }, + { + key: "ocean", + label: "Océan", + files: { + light: "bg-light-ocean.jpg", + dark: "bg-dark-ocean.jpg", + }, + }, + { + key: "sports", + label: "Sports", + files: { + light: "bg-light-sports.jpg", + dark: "bg-dark-sports.jpg", + }, + }, + { + key: "vague1", + label: "Vague 1", + files: { + light: "bg-light-vague1.jpg", + dark: "bg-dark-vague1.jpg", + }, + }, + { + key: "vague2", + label: "Vague 2", + files: { + light: "bg-light-vague2.jpg", + dark: "bg-dark-vague2.jpg", + }, + }, + { + key: "ville", + label: "Ville", + files: { + light: "bg-light-ville.jpg", + dark: "bg-dark-ville.jpg", + }, + }, + { + key: "voyage", + label: "Voyage", + files: { + light: "bg-light-voyage.jpg", + dark: "bg-dark-voyage.jpg", + }, + }, +]; diff --git a/shaarli-pro/js/backgrounds-manifest.json b/shaarli-pro/js/backgrounds-manifest.json new file mode 100644 index 0000000..17536df --- /dev/null +++ b/shaarli-pro/js/backgrounds-manifest.json @@ -0,0 +1,146 @@ +[ + { + "key": "cafe", + "label": "Café", + "files": { + "light": "bg-light-cafe.jpg", + "dark": "bg-dark-cafe.jpg" + } + }, + { + "key": "codes", + "label": "Codes", + "files": { + "light": "bg-light-codes.jpg", + "dark": "bg-dark-codes.jpg" + } + }, + { + "key": "dune", + "label": "Dune", + "files": { + "light": "bg-light-dune.jpg", + "dark": "bg-dark-dune.jpg" + } + }, + { + "key": "feuille-ligne", + "label": "Feuille Ligne", + "files": { + "light": "bg-light-feuilleLigne.jpg", + "dark": "bg-dark-feuilleLigne.jpg" + } + }, + { + "key": "feuille-quadrillage", + "label": "Feuille Quadrillage", + "files": { + "light": "bg-light-feuilleQuadrille.jpg", + "dark": "bg-dark-feuilleQuadrille.jpg" + } + }, + { + "key": "fleurs", + "label": "Fleurs", + "files": { + "light": "bg-light-fleurs.jpg", + "dark": "bg-dark-fleurs.jpg" + } + }, + { + "key": "foret", + "label": "Forêt", + "files": { + "light": "bg-light-foret.jpg", + "dark": "bg-dark-foret.jpg" + } + }, + { + "key": "grid", + "label": "Grid", + "files": { + "light": "bg-light-grid.jpg", + "dark": "bg-dark-grid.jpg" + } + }, + { + "key": "journal", + "label": "Journal", + "files": { + "light": "bg-light-journal.jpg", + "dark": "bg-dark-journal.jpg" + } + }, + { + "key": "lecture", + "label": "Lecture", + "files": { + "light": "bg-light-lecture.jpg", + "dark": "bg-dark-lecture.jpg" + } + }, + { + "key": "legumes", + "label": "Légumes", + "files": { + "light": "bg-light-legumes.jpg", + "dark": "bg-dark-legumes.jpg" + } + }, + { + "key": "montagnes", + "label": "Montagnes", + "files": { + "light": "bg-light-montagnes.jpg", + "dark": "bg-dark-montagnes.jpg" + } + }, + { + "key": "ocean", + "label": "Océan", + "files": { + "light": "bg-light-ocean.jpg", + "dark": "bg-dark-ocean.jpg" + } + }, + { + "key": "sports", + "label": "Sports", + "files": { + "light": "bg-light-sports.jpg", + "dark": "bg-dark-sports.jpg" + } + }, + { + "key": "vague1", + "label": "Vague 1", + "files": { + "light": "bg-light-vague1.jpg", + "dark": "bg-dark-vague1.jpg" + } + }, + { + "key": "vague2", + "label": "Vague 2", + "files": { + "light": "bg-light-vague2.jpg", + "dark": "bg-dark-vague2.jpg" + } + }, + { + "key": "ville", + "label": "Ville", + "files": { + "light": "bg-light-ville.jpg", + "dark": "bg-dark-ville.jpg" + } + }, + { + "key": "voyage", + "label": "Voyage", + "files": { + "light": "bg-light-voyage.jpg", + "dark": "bg-dark-voyage.jpg" + } + } +] diff --git a/shaarli-pro/js/custom_views.js b/shaarli-pro/js/custom_views.js index 89cd0bd..568b454 100644 --- a/shaarli-pro/js/custom_views.js +++ b/shaarli-pro/js/custom_views.js @@ -6,38 +6,117 @@ document.addEventListener("DOMContentLoaded", function () { const linkList = document.getElementById("links-list"); const container = document.querySelector(".content-container"); - if (typeof initBookmarkPaletteButtons === "function") { - initBookmarkPaletteButtons(); - } + const startViewInitialization = function () { + if (typeof initBookmarkPaletteButtons === "function") { + initBookmarkPaletteButtons(); + } - // Always init Pinned Items logic (sorting and listeners) - // This function is defined at the end of the file - if (typeof initPinnedItems === "function") { - initPinnedItems(); - } + // Always init Pinned Items logic (sorting and listeners) + // This function is defined at the end of the file + if (typeof initPinnedItems === "function") { + initPinnedItems(); + } - if (!linkList || !container) return; + if (!linkList || !container) return; - if (searchTags === "todo") { - initTodoView(linkList, container); - } else if (searchTags === "note") { - initNoteView(linkList, container); + if (searchTags === "todo") { + initTodoView(linkList, container); + } else if (searchTags === "note") { + initNoteView(linkList, container); + } + }; + + // Charger les backgrounds dynamiquement, puis initialiser les vues + initThemeModeBackgroundSync(); + + if (typeof loadBackgroundOptions === "function") { + loadBackgroundOptions() + .then(() => { + startViewInitialization(); + }) + .catch((err) => { + console.error("Erreur lors du chargement des backgrounds:", err); + // Initialiser quand même même si le chargement échoue + startViewInitialization(); + }); + } else { + startViewInitialization(); } }); const NOTE_COLOR_OPTIONS = [ - { key: "default", label: "Par défaut", hex: "#20293A" }, - { key: "red", label: "Rouge", hex: "#f28b82" }, - { key: "orange", label: "Orange", hex: "#fbbc04" }, - { key: "yellow", label: "Jaune", hex: "#fff475" }, - { key: "green", label: "Vert", hex: "#ccff90" }, - { key: "teal", label: "Menthe", hex: "#a7ffeb" }, - { key: "blue", label: "Bleu clair", hex: "#cbf0f8" }, - { key: "darkblue", label: "Bleu", hex: "#aecbfa" }, - { key: "purple", label: "Violet", hex: "#d7aefb" }, - { key: "pink", label: "Rose", hex: "#fdcfe8" }, - { key: "brown", label: "Beige", hex: "#e6c9a8" }, - { key: "grey", label: "Gris", hex: "#e8eaed" }, + { + key: "default", + label: "Par défaut", + light: "#ffffff", + dark: "#20293A" + }, + { + key: "red", + label: "Rouge", + light: "#f28b82", + dark: "#9c2116" + }, + { + key: "orange", + label: "Orange", + light: "#fbbc04", + dark: "#9c7a16" + }, + { + key: "yellow", + label: "Jaune", + light: "#fff475", + dark: "#9c9116" + }, + { + key: "green", + label: "Vert", + light: "#ccff90", + dark: "#5e9c16" + }, + { + key: "teal", + label: "Menthe", + light: "#a7ffeb", + dark: "#169c7d" + }, + { + key: "blue", + label: "Bleu clair", + light: "#cbf0f8", + dark: "#16849c" + }, + { + key: "darkblue", + label: "Bleu", + light: "#aecbfa", + dark: "#16499c" + }, + { + key: "purple", + label: "Violet", + light: "#d7aefb", + dark: "#5d169c" + }, + { + key: "pink", + label: "Rose", + light: "#fdcfe8", + dark: "#9c165f" + }, + { + key: "brown", + label: "Beige", + light: "#e6c9a8", + dark: "#9c5d16" + }, + { + key: "grey", + label: "Gris", + light: "#e8eaed", + dark: "#4e5764" + } ]; const NOTE_BACKGROUND_TAG_PREFIX = "notebg-"; @@ -68,25 +147,325 @@ function resolveThemeAssetBasePath() { return "/tpl/shaarli-pro"; } -const NOTE_BACKGROUND_BASE_PATH = `${resolveThemeAssetBasePath().replace(/\/$/, "")}/img/note-backgrounds`; -const NOTE_BACKGROUND_OPTIONS = [ - { key: "bg-canyon", label: "Canyon", file: "bg-canyon.png" }, - { key: "bg-leaves", label: "Feuilles", file: "bg-leaves.png" }, - { key: "bg-shore", label: "Rivage", file: "bg-shore.png" }, - { key: "bg-sunset", label: "Coucher", file: "bg-sunset.png" }, - { key: "bg-planet", label: "Planète", file: "bg-planet.png" }, - { key: "bg-crystal", label: "Cristal", file: "bg-crystal.png" }, - { key: "bg-orchid", label: "Orchidée", file: "bg-orchid.png" }, - { key: "bg-lake", label: "Lac", file: "bg-lake.png" }, - { key: "bg-ladder", label: "Échelle", file: "bg-ladder.png" }, - { key: "bg-burst", label: "Étoile", file: "bg-burst.png" }, +const NOTE_BACKGROUND_ASSET_ROOT = `${resolveThemeAssetBasePath().replace(/\/$/, "")}/img`; + +// Liste des backgrounds - chargée dynamiquement depuis le serveur +let NOTE_BACKGROUND_OPTIONS = []; +let isBackgroundOptionsLoaded = false; +let backgroundOptionsLoadPromise = null; + +window.__shaarliCustomViewsVersion = "1.0.5-inline-bg-manifest"; +if (typeof console !== "undefined" && console && typeof console.info === "function") { + console.info("[custom_views] loaded", window.__shaarliCustomViewsVersion); +} + +const NOTE_BACKGROUND_MANIFEST_INLINE = [ + { key: "cafe", label: "Café", files: { light: "bg-light-cafe.jpg", dark: "bg-dark-cafe.jpg" } }, + { key: "codes", label: "Codes", files: { light: "bg-light-codes.jpg", dark: "bg-dark-codes.jpg" } }, + { key: "dune", label: "Dune", files: { light: "bg-light-dune.jpg", dark: "bg-dark-dune.jpg" } }, + { key: "feuille-ligne", label: "Feuille Ligne", files: { light: "bg-light-feuilleLigne.jpg", dark: "bg-dark-feuilleLigne.jpg" } }, + { key: "feuille-quadrillage", label: "Feuille Quadrillage", files: { light: "bg-light-feuilleQuadrille.jpg", dark: "bg-dark-feuilleQuadrille.jpg" } }, + { key: "fleurs", label: "Fleurs", files: { light: "bg-light-fleurs.jpg", dark: "bg-dark-fleurs.jpg" } }, + { key: "foret", label: "Forêt", files: { light: "bg-light-foret.jpg", dark: "bg-dark-foret.jpg" } }, + { key: "grid", label: "Grid", files: { light: "bg-light-grid.jpg", dark: "bg-dark-grid.jpg" } }, + { key: "journal", label: "Journal", files: { light: "bg-light-journal.jpg", dark: "bg-dark-journal.jpg" } }, + { key: "lecture", label: "Lecture", files: { light: "bg-light-lecture.jpg", dark: "bg-dark-lecture.jpg" } }, + { key: "legumes", label: "Légumes", files: { light: "bg-light-legumes.jpg", dark: "bg-dark-legumes.jpg" } }, + { key: "montagnes", label: "Montagnes", files: { light: "bg-light-montagnes.jpg", dark: "bg-dark-montagnes.jpg" } }, + { key: "ocean", label: "Océan", files: { light: "bg-light-ocean.jpg", dark: "bg-dark-ocean.jpg" } }, + { key: "sports", label: "Sports", files: { light: "bg-light-sports.jpg", dark: "bg-dark-sports.jpg" } }, + { key: "vague1", label: "Vague 1", files: { light: "bg-light-vague1.jpg", dark: "bg-dark-vague1.jpg" } }, + { key: "vague2", label: "Vague 2", files: { light: "bg-light-vague2.jpg", dark: "bg-dark-vague2.jpg" } }, + { key: "ville", label: "Ville", files: { light: "bg-light-ville.jpg", dark: "bg-dark-ville.jpg" } }, + { key: "voyage", label: "Voyage", files: { light: "bg-light-voyage.jpg", dark: "bg-dark-voyage.jpg" } }, ]; -function getNoteBackgroundUrl(backgroundKey) { - const found = NOTE_BACKGROUND_OPTIONS.find((bg) => bg.key === backgroundKey); - if (!found) return ""; +/** + * Charge la liste des backgrounds depuis le endpoint PHP + * @returns {Promise} Liste des backgrounds + */ +function loadBackgroundOptions() { + if (isBackgroundOptionsLoaded) { + return Promise.resolve(NOTE_BACKGROUND_OPTIONS); + } - return `${NOTE_BACKGROUND_BASE_PATH}/${found.file}`; + if (backgroundOptionsLoadPromise) { + return backgroundOptionsLoadPromise; + } + + NOTE_BACKGROUND_OPTIONS = normalizeDynamicBackgroundOptions(NOTE_BACKGROUND_MANIFEST_INLINE); + isBackgroundOptionsLoaded = true; + backgroundOptionsLoadPromise = Promise.resolve(NOTE_BACKGROUND_OPTIONS); + return backgroundOptionsLoadPromise; +} + +function normalizeBackgroundKey(key) { + if (typeof key !== "string") return ""; + + return key + .trim() + .toLowerCase() + .replace(/[\s_]+/g, "-") + .replace(/[^a-z0-9-]/g, "-") + .replace(/-+/g, "-") + .replace(/^-|-$/g, ""); +} + +function formatBackgroundLabel(rawLabel, fallbackKey) { + const base = (typeof rawLabel === "string" && rawLabel.trim() !== "" ? rawLabel : fallbackKey) + .replace(/[_-]+/g, " ") + .replace(/([a-z0-9])([A-Z])/g, "$1 $2") + .replace(/\s+/g, " ") + .trim(); + + return base + .split(" ") + .filter((part) => part !== "") + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(" "); +} + +function getCurrentThemeMode() { + return document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light"; +} + +function getColorOption(colorKey) { + const normalizedKey = typeof colorKey === "string" ? colorKey.trim().toLowerCase() : ""; + + return NOTE_COLOR_OPTIONS.find((opt) => opt.key === normalizedKey) || NOTE_COLOR_OPTIONS.find((opt) => opt.key === "default") || null; +} + +function getThemeColorValue(option, mode = getCurrentThemeMode()) { + if (!option || typeof option !== "object") return ""; + + const safeMode = mode === "dark" ? "dark" : "light"; + const preferred = typeof option[safeMode] === "string" ? option[safeMode].trim() : ""; + const fallbackLight = typeof option.light === "string" ? option.light.trim() : ""; + const fallbackDark = typeof option.dark === "string" ? option.dark.trim() : ""; + + return preferred || fallbackLight || fallbackDark; +} + +function parseHexColor(colorValue) { + if (typeof colorValue !== "string") return null; + + const safeValue = colorValue.trim(); + const shortHexMatch = /^#([0-9a-f]{3})$/i.exec(safeValue); + if (shortHexMatch) { + return { + r: parseInt(shortHexMatch[1].charAt(0).repeat(2), 16), + g: parseInt(shortHexMatch[1].charAt(1).repeat(2), 16), + b: parseInt(shortHexMatch[1].charAt(2).repeat(2), 16), + }; + } + + const longHexMatch = /^#([0-9a-f]{6})$/i.exec(safeValue); + if (longHexMatch) { + return { + r: parseInt(longHexMatch[1].slice(0, 2), 16), + g: parseInt(longHexMatch[1].slice(2, 4), 16), + b: parseInt(longHexMatch[1].slice(4, 6), 16), + }; + } + + return null; +} + +function getReadableForegroundForBackground(colorValue, mode = getCurrentThemeMode()) { + const rgb = parseHexColor(colorValue); + if (!rgb) { + return mode === "dark" ? "#e8eaed" : "#202124"; + } + + const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255; + return luminance > 0.56 ? "#202124" : "#f5f7fb"; +} + +function normalizeDynamicBackgroundOptions(rawOptions) { + const rawList = Array.isArray(rawOptions) + ? rawOptions + : rawOptions && Array.isArray(rawOptions.backgrounds) + ? rawOptions.backgrounds + : []; + + const mergedByKey = {}; + + rawList.forEach((option) => { + if (!option || typeof option !== "object") return; + + const key = normalizeBackgroundKey(typeof option.key === "string" ? option.key : option.label || ""); + if (!key) return; + + const files = option.files && typeof option.files === "object" ? option.files : {}; + const lightFile = typeof files.light === "string" ? files.light.trim() : ""; + const darkFile = typeof files.dark === "string" ? files.dark.trim() : ""; + if (!lightFile && !darkFile) return; + + if (!mergedByKey[key]) { + mergedByKey[key] = { + key, + label: formatBackgroundLabel(option.label || "", key), + paths: { + light: "", + dark: "", + }, + }; + } + + if (lightFile) { + mergedByKey[key].paths.light = `note-bg-light/${lightFile}`; + } + if (darkFile) { + mergedByKey[key].paths.dark = `note-bg-dark/${darkFile}`; + } + }); + + return Object.values(mergedByKey).sort((a, b) => a.label.localeCompare(b.label, "fr", { sensitivity: "base" })); +} + +function getAvailableBackgroundOptionsForMode(mode = getCurrentThemeMode()) { + const safeMode = mode === "dark" ? "dark" : "light"; + return NOTE_BACKGROUND_OPTIONS.filter((option) => option.paths && option.paths[safeMode]); +} + +function getNoteBackgroundUrl(backgroundKey, mode = getCurrentThemeMode()) { + const normalizedKey = normalizeBackgroundKey(backgroundKey); + if (!normalizedKey) return ""; + + const found = NOTE_BACKGROUND_OPTIONS.find((bg) => bg.key === normalizedKey); + if (!found || !found.paths) return ""; + + const safeMode = mode === "dark" ? "dark" : "light"; + const selectedPath = found.paths[safeMode] || ""; + + if (!selectedPath) return ""; + return `${NOTE_BACKGROUND_ASSET_ROOT}/${selectedPath}`; +} + +function getElementVisualColor(element) { + if (!element) return "default"; + + const colorClass = Array.from(element.classList).find((cls) => cls.startsWith("note-color-")); + if (colorClass) { + return colorClass.replace("note-color-", "") || "default"; + } + + return element.dataset.color || "default"; +} + +function getElementVisualBackground(element) { + if (!element) return "none"; + + const normalizedBackground = normalizeBackgroundKey(element.dataset.background || ""); + return normalizedBackground || "none"; +} + +function refreshNoteBackgroundVisuals() { + document.querySelectorAll(".note-card, .note-modal, .link-outer").forEach((element) => { + applyNoteVisualState(element, { + color: getElementVisualColor(element), + background: getElementVisualBackground(element), + }); + }); +} + +function refreshBackgroundPalettes() { + document.querySelectorAll(".note-card").forEach((card) => { + const palettePopup = card.querySelector(".note-hover-actions .palette-popup"); + if (!palettePopup) return; + + const noteId = card.dataset.id || ""; + if (!noteId) return; + + const editLink = card.querySelector( + '.note-hover-actions a[href*="/admin/shaare/"], .note-hover-actions a[href*="do=editlink"], .note-hover-actions a[title="Edit"]', + ); + + palettePopup.innerHTML = generatePaletteButtons({ + id: noteId, + editUrl: editLink && editLink.href ? editLink.href : "#", + color: getElementVisualColor(card), + background: getElementVisualBackground(card), + }); + }); + + document.querySelectorAll(".link-outer").forEach((card) => { + const palettePopup = card.querySelector(".bookmark-palette .palette-popup"); + if (!palettePopup) return; + + const noteId = card.dataset.id || card.getAttribute("data-id") || card.id; + if (!noteId) return; + + const actions = card.querySelector(".link-actions"); + const editLink = actions + ? actions.querySelector('a[title="Modifier"], a[aria-label="Modifier ce bookmark"], a[href*="/admin/shaare/"]') + : null; + + palettePopup.innerHTML = generateBookmarkPaletteButtons( + noteId, + editLink && editLink.href ? editLink.href : "#", + getElementVisualColor(card), + getElementVisualBackground(card), + ); + }); + + const modal = document.querySelector(".note-modal-overlay"); + if (!modal || !modal.currentNote) return; + + const modalCard = modal.querySelector(".note-modal"); + if (modalCard) { + modal.currentNote.color = getElementVisualColor(modalCard); + modal.currentNote.background = getElementVisualBackground(modalCard); + } + + const modalColorPopup = modal.querySelector("#note-modal-color-popup"); + if (modalColorPopup) { + modalColorPopup.innerHTML = generateModalPaletteButtons(modal.currentNote); + } +} + +function parseBackgroundManifestPayload(rawPayload) { + const payload = typeof rawPayload === "string" ? rawPayload.trim() : ""; + if (!payload) return []; + + try { + return JSON.parse(payload); + } catch (parseError) { + const firstArrayBracket = payload.indexOf("["); + const lastArrayBracket = payload.lastIndexOf("]"); + if (firstArrayBracket === -1 || lastArrayBracket === -1 || lastArrayBracket <= firstArrayBracket) { + throw parseError; + } + + const jsonSlice = payload.slice(firstArrayBracket, lastArrayBracket + 1); + return JSON.parse(jsonSlice); + } +} + + +let isThemeModeBackgroundSyncInitialized = false; + +function initThemeModeBackgroundSync() { + if (isThemeModeBackgroundSyncInitialized) return; + + const root = document.documentElement; + if (!root) return; + + let lastTheme = getCurrentThemeMode(); + const observer = new MutationObserver((mutations) => { + const themeChanged = mutations.some((mutation) => mutation.attributeName === "data-theme"); + if (!themeChanged) return; + + const nextTheme = getCurrentThemeMode(); + if (nextTheme === lastTheme) return; + + lastTheme = nextTheme; + refreshNoteBackgroundVisuals(); + refreshBackgroundPalettes(); + }); + + observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] }); + isThemeModeBackgroundSyncInitialized = true; } function positionPalettePopup(popup) { @@ -123,14 +502,29 @@ function positionPalettePopup(popup) { function applyNoteVisualState(element, note) { if (!element || !note) return; - const color = note.color || "default"; - const background = note.background || "none"; + const resolvedColorOption = getColorOption(note.color || "default"); + const color = resolvedColorOption ? resolvedColorOption.key : "default"; + const colorValue = getThemeColorValue(resolvedColorOption); + const foregroundColor = getReadableForegroundForBackground(colorValue); + const normalizedBackground = normalizeBackgroundKey(note.background || ""); + const background = normalizedBackground || "none"; element.classList.forEach((cls) => { if (cls.startsWith("note-color-")) element.classList.remove(cls); }); element.classList.add(`note-color-${color}`); + if (colorValue) { + element.style.backgroundColor = colorValue; + element.style.borderColor = "transparent"; + } else { + element.style.removeProperty("background-color"); + } + + if (foregroundColor) { + element.style.setProperty("--note-card-fg", foregroundColor); + } + if (background && background !== "none") { const bgUrl = getNoteBackgroundUrl(background); if (bgUrl) { @@ -166,8 +560,8 @@ function extractNoteVisualStateFromTags(tags) { let background = "none"; const foundBgTag = safeTags.find((t) => typeof t === "string" && t.startsWith(NOTE_BACKGROUND_TAG_PREFIX)); if (foundBgTag) { - const candidate = foundBgTag.substring(NOTE_BACKGROUND_TAG_PREFIX.length); - if (candidate && NOTE_BACKGROUND_OPTIONS.some((bg) => bg.key === candidate)) { + const candidate = normalizeBackgroundKey(foundBgTag.substring(NOTE_BACKGROUND_TAG_PREFIX.length)); + if (candidate) { background = candidate; } } @@ -246,19 +640,21 @@ function initBookmarkPaletteButtons() { function generateBookmarkPaletteButtons(bookmarkId, editUrl, currentColor, currentBackground) { const color = currentColor || "default"; - const background = currentBackground || "none"; + const background = normalizeBackgroundKey(currentBackground || "") || "none"; const colorButtons = [ ``, ...NOTE_COLOR_OPTIONS.filter((opt) => opt.key !== "default").map( - (opt) => - ``, + (opt) => { + const swatchColor = getThemeColorValue(opt); + return ``; + }, ), ].join(""); const backgroundButtons = [ ``, - ...NOTE_BACKGROUND_OPTIONS.map((bg) => { + ...getAvailableBackgroundOptionsForMode().map((bg) => { const bgUrl = getNoteBackgroundUrl(bg.key); return ``; }), @@ -754,7 +1150,7 @@ function parseNoteFromLink(linkEl) { tags.push(t); } } else if (t.startsWith(NOTE_BACKGROUND_TAG_PREFIX)) { - background = t.substring(NOTE_BACKGROUND_TAG_PREFIX.length) || "none"; + background = normalizeBackgroundKey(t.substring(NOTE_BACKGROUND_TAG_PREFIX.length)) || "none"; } else { tags.push(t); } @@ -970,19 +1366,21 @@ function openNoteModal(note) { function generateModalPaletteButtons(note) { const currentColor = note.color || "default"; - const currentBackground = note.background || "none"; + const currentBackground = normalizeBackgroundKey(note.background || "") || "none"; const colorButtons = [ ``, ...NOTE_COLOR_OPTIONS.filter((opt) => opt.key !== "default").map( - (opt) => - ``, + (opt) => { + const swatchColor = getThemeColorValue(opt); + return ``; + }, ), ].join(""); const backgroundButtons = [ ``, - ...NOTE_BACKGROUND_OPTIONS.map((bg) => { + ...getAvailableBackgroundOptionsForMode().map((bg) => { const bgUrl = getNoteBackgroundUrl(bg.key); return ``; }), @@ -1020,9 +1418,10 @@ window.setModalNoteBackground = function (backgroundKey) { if (!modal || !modal.currentNote) return; const currentNote = modal.currentNote; - setNoteBackground(currentNote.id, backgroundKey, currentNote.editUrl); + const normalizedBackgroundKey = backgroundKey === "none" ? "none" : normalizeBackgroundKey(backgroundKey) || "none"; + setNoteBackground(currentNote.id, normalizedBackgroundKey, currentNote.editUrl); - currentNote.background = backgroundKey; + currentNote.background = normalizedBackgroundKey; const modalCard = modal.querySelector(".note-modal"); if (modalCard) { applyNoteVisualState(modalCard, currentNote); @@ -1038,19 +1437,21 @@ window.setModalNoteBackground = function (backgroundKey) { function generatePaletteButtons(note) { const currentColor = note.color || "default"; - const currentBackground = note.background || "none"; + const currentBackground = normalizeBackgroundKey(note.background || "") || "none"; const colorButtons = [ ``, ...NOTE_COLOR_OPTIONS.filter((opt) => opt.key !== "default").map( - (opt) => - ``, + (opt) => { + const swatchColor = getThemeColorValue(opt); + return ``; + }, ), ].join(""); const backgroundButtons = [ ``, - ...NOTE_BACKGROUND_OPTIONS.map((bg) => { + ...getAvailableBackgroundOptionsForMode().map((bg) => { const bgUrl = getNoteBackgroundUrl(bg.key); return ``; }), @@ -1157,27 +1558,29 @@ window.setNoteColor = function (noteId, color, editUrl) { }; window.setNoteBackground = function (noteId, backgroundKey, editUrl) { + const normalizedBackgroundKey = backgroundKey === "none" ? "none" : normalizeBackgroundKey(backgroundKey) || "none"; + const card = document.querySelector(`.note-card[data-id="${noteId}"]`); if (card) { const colorClass = Array.from(card.classList).find((cls) => cls.startsWith("note-color-")); const color = colorClass ? colorClass.replace("note-color-", "") : card.dataset.color || "default"; - applyNoteVisualState(card, { color, background: backgroundKey }); + applyNoteVisualState(card, { color, background: normalizedBackgroundKey }); } const bookmarkCard = document.querySelector(`.link-outer[data-id="${noteId}"]`); if (bookmarkCard) { const colorClass = Array.from(bookmarkCard.classList).find((cls) => cls.startsWith("note-color-")); const color = colorClass ? colorClass.replace("note-color-", "") : bookmarkCard.dataset.color || "default"; - applyNoteVisualState(bookmarkCard, { color, background: backgroundKey }); + applyNoteVisualState(bookmarkCard, { color, background: normalizedBackgroundKey }); const palettePopup = bookmarkCard.querySelector(".bookmark-palette .palette-popup"); if (palettePopup) { - palettePopup.innerHTML = generateBookmarkPaletteButtons(noteId, editUrl, color, backgroundKey); + palettePopup.innerHTML = generateBookmarkPaletteButtons(noteId, editUrl, color, normalizedBackgroundKey); } } const modal = document.querySelector(".note-modal-overlay"); if (modal && modal.currentNote && String(modal.currentNote.id) === String(noteId)) { - modal.currentNote.background = backgroundKey; + modal.currentNote.background = normalizedBackgroundKey; const modalCard = modal.querySelector(".note-modal"); if (modalCard) { applyNoteVisualState(modalCard, modal.currentNote); @@ -1212,8 +1615,8 @@ window.setNoteBackground = function (noteId, backgroundKey, editUrl) { let tagsArray = currentTags.split(/[\s,]+/).filter((t) => t.trim() !== ""); tagsArray = tagsArray.filter((t) => !t.startsWith(NOTE_BACKGROUND_TAG_PREFIX)); - if (backgroundKey && backgroundKey !== "none") { - tagsArray.push(`${NOTE_BACKGROUND_TAG_PREFIX}${backgroundKey}`); + if (normalizedBackgroundKey && normalizedBackgroundKey !== "none") { + tagsArray.push(`${NOTE_BACKGROUND_TAG_PREFIX}${normalizedBackgroundKey}`); } formData.set("lf_tags", tagsArray.join(" "));