feat: améliorer styles dark mode avec background unifié #20293a, bordures notes/cards (1px solid #000 light, #dedfe2 dark), width input 600px→800px, ajout bouton pin corner absolu (top-right, hover scale 1.06), suppression backgrounds/borders/outlines inputs (transparent + !important), nettoyage code dupliqué note-input-collapsed, styles todo-draft-row transparent, et corrections mineures formatage CSS (espaces, indentation)
This commit is contained in:
parent
ef6f9cb486
commit
f99c1cbecb
@ -19,7 +19,7 @@ body.view-todo .content-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] body.view-todo .content-container {
|
[data-theme="dark"] body.view-todo .content-container {
|
||||||
background-color: var(--bg-body);
|
background-color: #20293a;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.view-todo #linklist {
|
body.view-todo #linklist {
|
||||||
@ -105,7 +105,7 @@ body.view-todo #linklist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .todo-main {
|
[data-theme="dark"] .todo-main {
|
||||||
background-color: #0f172a;
|
background-color: #20293a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-main-header {
|
.todo-main-header {
|
||||||
@ -212,14 +212,16 @@ body.view-todo #linklist {
|
|||||||
/* --- NOTES VIEW --- */
|
/* --- NOTES VIEW --- */
|
||||||
|
|
||||||
/* Wrapper */
|
/* Wrapper */
|
||||||
body.view-notes .content-container {
|
body.view-notes .content-container,
|
||||||
|
body.view-archive .content-container {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
background-color: var(--bg-body);
|
background-color: var(--bg-body);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] body.view-notes .content-container {
|
[data-theme="dark"] body.view-notes .content-container,
|
||||||
background-color: var(--bg-body);
|
[data-theme="dark"] body.view-archive .content-container {
|
||||||
|
background-color: #20293a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tool Bar / Input Area */
|
/* Tool Bar / Input Area */
|
||||||
@ -233,7 +235,7 @@ body.view-notes .content-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notes-top-bar-inner {
|
.notes-top-bar-inner {
|
||||||
width: 600px;
|
width: 800px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@ -241,10 +243,11 @@ body.view-notes .content-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.note-input-container {
|
.note-input-container {
|
||||||
width: 600px;
|
width: 800px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background-color: var(--background-secondary, #ffffff);
|
background-color: var(--background-secondary, #ffffff);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
border: 1px solid #000;
|
||||||
box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3), 0 2px 6px 2px rgba(60, 64, 67, 0.15);
|
box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3), 0 2px 6px 2px rgba(60, 64, 67, 0.15);
|
||||||
transition: box-shadow 0.2s;
|
transition: box-shadow 0.2s;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -255,9 +258,9 @@ body.view-notes .content-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-input-container {
|
[data-theme="dark"] .note-input-container {
|
||||||
background-color: #202124;
|
background-color: #20293a;
|
||||||
border: none;
|
border: 1px solid var(--border);
|
||||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.6), 0 2px 6px 2px rgba(0, 0, 0, 0.4);
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-input-collapsed {
|
.note-input-collapsed {
|
||||||
@ -268,6 +271,16 @@ body.view-notes .content-container {
|
|||||||
color: var(--note-card-fg, var(--text-light, #80868b));
|
color: var(--note-card-fg, var(--text-light, #80868b));
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
padding: 12px 16px;
|
||||||
|
cursor: text;
|
||||||
|
color: var(--note-card-fg, var(--text-light, #80868b));
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 12px 16px;
|
||||||
|
cursor: text;
|
||||||
|
color: var(--note-card-fg, var(--text-light, #80868b));
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-input-container.is-editing {
|
.note-input-container.is-editing {
|
||||||
@ -327,6 +340,14 @@ body.view-notes .content-container {
|
|||||||
.todo-draft-row .todo-item-text {
|
.todo-draft-row .todo-item-text {
|
||||||
padding: 5px 4px;
|
padding: 5px 4px;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .todo-draft-row .todo-item-text {
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-draft-add-btn {
|
.todo-draft-add-btn {
|
||||||
@ -355,26 +376,32 @@ body.view-notes .content-container {
|
|||||||
|
|
||||||
.note-input-title {
|
.note-input-title {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 0;
|
border: none !important;
|
||||||
outline: none;
|
outline: none !important;
|
||||||
background: transparent;
|
box-shadow: none !important;
|
||||||
|
background-color: transparent;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .note-input-title {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.note-input-description-source {
|
.note-input-description-source {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none !important;
|
||||||
background: transparent;
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background-color: transparent;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
resize: none;
|
resize: none;
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
max-height: 44vh;
|
max-height: 44vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
outline: none;
|
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@ -385,7 +412,8 @@ body.view-notes .content-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-input-description-source {
|
[data-theme="dark"] .note-input-description-source {
|
||||||
border: none;
|
border: none !important;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-input-container.is-enhanced .note-input-description-source {
|
.note-input-container.is-enhanced .note-input-description-source {
|
||||||
@ -419,8 +447,15 @@ body.view-notes .content-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; transform: translateY(-4px); }
|
from {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
opacity: 0;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-format-btn {
|
.note-format-btn {
|
||||||
@ -476,7 +511,7 @@ body.view-notes .content-container {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-input-actions-left > button {
|
.note-input-actions-left>button {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -491,17 +526,17 @@ body.view-notes .content-container {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-input-actions-left > button:disabled {
|
.note-input-actions-left>button:disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
opacity: 0.35;
|
opacity: 0.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-input-actions-left > button:hover:not(:disabled) {
|
.note-input-actions-left>button:hover:not(:disabled) {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background: rgba(0, 0, 0, 0.08);
|
background: rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-input-actions-left > button:hover:not(:disabled) {
|
[data-theme="dark"] .note-input-actions-left>button:hover:not(:disabled) {
|
||||||
background: rgba(255, 255, 255, 0.14);
|
background: rgba(255, 255, 255, 0.14);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,15 +654,63 @@ body.view-notes .content-container {
|
|||||||
column-span: none;
|
column-span: none;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border: 1px solid #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-card {
|
.note-card {
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .note-card {
|
||||||
|
border-color: #dedfe2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-card .note-inner {
|
.note-card .note-inner {
|
||||||
|
position: relative;
|
||||||
padding: 14px 16px 12px;
|
padding: 14px 16px 12px;
|
||||||
|
padding-right: 58px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-pin-corner {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--note-card-fg, currentColor);
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
z-index: 4;
|
||||||
|
opacity: 0.92;
|
||||||
|
transition: transform 0.15s ease, opacity 0.15s ease, color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-pin-corner i {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-pin-corner:hover {
|
||||||
|
transform: scale(1.06);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-pin-corner.active {
|
||||||
|
color: var(--note-card-fg, currentColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .note-pin-corner {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .note-pin-corner.active {
|
||||||
|
color: var(--note-card-fg, currentColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
@ -683,7 +766,7 @@ body.view-notes .content-container {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--background-secondary, #ffffff);
|
background: var(--background-secondary, #ffffff);
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
border: 1px solid #000;
|
||||||
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
|
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -696,8 +779,8 @@ body.note-modal-open {
|
|||||||
|
|
||||||
[data-theme="dark"] .note-modal {
|
[data-theme="dark"] .note-modal {
|
||||||
background: #202124;
|
background: #202124;
|
||||||
border-color: transparent;
|
border-color: #dedfe2;
|
||||||
box-shadow: 0 14px 28px rgba(0,0,0,0.5), 0 10px 10px rgba(0,0,0,0.4);
|
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.5), 0 10px 10px rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-modal-header {
|
.note-modal-header {
|
||||||
@ -859,9 +942,9 @@ body.note-modal-open {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-modal-actions-left > button,
|
.note-modal-actions-left>button,
|
||||||
.note-modal-actions-left > a,
|
.note-modal-actions-left>a,
|
||||||
.note-modal-actions-left > .note-modal-color-picker > button {
|
.note-modal-actions-left>.note-modal-color-picker>button {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -876,16 +959,16 @@ body.note-modal-open {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-modal-actions-left > button:hover,
|
.note-modal-actions-left>button:hover,
|
||||||
.note-modal-actions-left > a:hover,
|
.note-modal-actions-left>a:hover,
|
||||||
.note-modal-actions-left > .note-modal-color-picker > button:hover {
|
.note-modal-actions-left>.note-modal-color-picker>button:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background: rgba(0, 0, 0, 0.08);
|
background: rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-modal-actions-left > button:hover,
|
[data-theme="dark"] .note-modal-actions-left>button:hover,
|
||||||
[data-theme="dark"] .note-modal-actions-left > a:hover,
|
[data-theme="dark"] .note-modal-actions-left>a:hover,
|
||||||
[data-theme="dark"] .note-modal-actions-left > .note-modal-color-picker > button:hover {
|
[data-theme="dark"] .note-modal-actions-left>.note-modal-color-picker>button:hover {
|
||||||
background: rgba(255, 255, 255, 0.14);
|
background: rgba(255, 255, 255, 0.14);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1163,9 +1246,9 @@ body.note-modal-open {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-hover-actions > button,
|
.note-hover-actions>button,
|
||||||
.note-hover-actions > a,
|
.note-hover-actions>a,
|
||||||
.note-hover-actions > div > button {
|
.note-hover-actions>div>button {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@ -1182,17 +1265,17 @@ body.note-modal-open {
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-hover-actions > button:hover,
|
.note-hover-actions>button:hover,
|
||||||
.note-hover-actions > a:hover,
|
.note-hover-actions>a:hover,
|
||||||
.note-hover-actions > div > button:hover {
|
.note-hover-actions>div>button:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.08);
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-hover-actions > button:hover,
|
[data-theme="dark"] .note-hover-actions>button:hover,
|
||||||
[data-theme="dark"] .note-hover-actions > a:hover,
|
[data-theme="dark"] .note-hover-actions>a:hover,
|
||||||
[data-theme="dark"] .note-hover-actions > div > button:hover {
|
[data-theme="dark"] .note-hover-actions>div>button:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.14);
|
background-color: rgba(255, 255, 255, 0.14);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
@ -1204,7 +1287,7 @@ body.note-modal-open {
|
|||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-palette > button {
|
.bookmark-palette>button {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
width: 36px;
|
width: 36px;
|
||||||
@ -1219,7 +1302,7 @@ body.note-modal-open {
|
|||||||
transition: background-color 0.2s, color 0.2s;
|
transition: background-color 0.2s, color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-palette > button:hover {
|
.bookmark-palette>button:hover {
|
||||||
background: var(--primary-light);
|
background: var(--primary-light);
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
@ -1316,7 +1399,7 @@ body.note-modal-open {
|
|||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.palette-row + .palette-row {
|
.palette-row+.palette-row {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1499,7 +1582,7 @@ body.note-modal-open {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bg-studio-thumb-solid {
|
.bg-studio-thumb-solid {
|
||||||
background: linear-gradient(135deg, rgba(255,255,255,0.15), rgba(255,255,255,0.02));
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.02));
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-studio-tile {
|
.bg-studio-tile {
|
||||||
@ -1740,14 +1823,14 @@ body.note-modal-open {
|
|||||||
/* Reference: Keep Colors */
|
/* Reference: Keep Colors */
|
||||||
/* Default */
|
/* Default */
|
||||||
.note-card.note-color-default {
|
.note-card.note-color-default {
|
||||||
background-color: #20293a;
|
background-color: var(--bg-body);
|
||||||
border-color: transparent;
|
border-color: #000;
|
||||||
--note-card-fg: #dbe7ff;
|
--note-card-fg: var(--text-main, #111827);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-card.note-color-default {
|
[data-theme="dark"] .note-card.note-color-default {
|
||||||
background-color: #20293a;
|
background-color: #20293a;
|
||||||
border-color: transparent;
|
border-color: #dedfe2;
|
||||||
--note-card-fg: #dbe7ff;
|
--note-card-fg: #dbe7ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1883,25 +1966,25 @@ body.note-modal-open {
|
|||||||
|
|
||||||
/* Grey */
|
/* Grey */
|
||||||
.note-card.note-color-grey {
|
.note-card.note-color-grey {
|
||||||
background-color: #e8eaed;
|
background-color: #e8eaed;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
--note-card-fg: #2a2d31;
|
--note-card-fg: #2a2d31;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-card.note-has-bg,
|
.note-card.note-has-bg,
|
||||||
.note-modal.note-has-bg,
|
.note-modal.note-has-bg,
|
||||||
.note-input-container.note-has-bg,
|
.note-input-container.note-has-bg,
|
||||||
.link-outer.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-image: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16)), var(--note-bg-image);
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center bottom;
|
background-position: center bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-card.todo-card.note-has-bg[data-font-color="auto"] {
|
.note-card.todo-card.note-has-bg[data-font-color="auto"] {
|
||||||
--note-card-fg: rgba(255, 255, 255, 0.92);
|
--note-card-fg: rgba(255, 255, 255, 0.92);
|
||||||
color: var(--note-card-fg);
|
color: var(--note-card-fg);
|
||||||
background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image);
|
background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image);
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
||||||
background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image);
|
background-image: linear-gradient(rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.42)), var(--note-bg-image);
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
||||||
}
|
}
|
||||||
@ -1916,6 +1999,11 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
|
|
||||||
.note-card[class*="note-color-"] {
|
.note-card[class*="note-color-"] {
|
||||||
color: var(--note-card-fg, #202124);
|
color: var(--note-card-fg, #202124);
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .note-card[class*="note-color-"] {
|
||||||
|
border: 1px solid #dedfe2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-outer {
|
.link-outer {
|
||||||
@ -1994,13 +2082,14 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
|
|
||||||
/* Responsive: sur petits écrans, ajuster les backgrounds */
|
/* Responsive: sur petits écrans, ajuster les backgrounds */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
||||||
/* En mobile, les cards sont plus étroites, on ajuste */
|
/* En mobile, les cards sont plus étroites, on ajuste */
|
||||||
.notes-masonry .note-card.note-has-bg,
|
.notes-masonry .note-card.note-has-bg,
|
||||||
.view-grid .link-outer.note-has-bg {
|
.view-grid .link-outer.note-has-bg {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center bottom;
|
background-position: center bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vue liste en mobile: thumbnail passe en haut */
|
/* Vue liste en mobile: thumbnail passe en haut */
|
||||||
.view-list .link-outer.note-has-bg {
|
.view-list .link-outer.note-has-bg {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
@ -2052,21 +2141,17 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
.note-card.note-filter-lined,
|
.note-card.note-filter-lined,
|
||||||
.note-modal.note-filter-lined,
|
.note-modal.note-filter-lined,
|
||||||
.link-outer.note-filter-lined {
|
.link-outer.note-filter-lined {
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(transparent,
|
||||||
transparent,
|
transparent 29px,
|
||||||
transparent 29px,
|
rgba(0, 0, 0, 0.1) 30px) !important;
|
||||||
rgba(0, 0, 0, 0.1) 30px
|
|
||||||
) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-card.note-filter-lined,
|
[data-theme="dark"] .note-card.note-filter-lined,
|
||||||
[data-theme="dark"] .note-modal.note-filter-lined,
|
[data-theme="dark"] .note-modal.note-filter-lined,
|
||||||
[data-theme="dark"] .link-outer.note-filter-lined {
|
[data-theme="dark"] .link-outer.note-filter-lined {
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(transparent,
|
||||||
transparent,
|
transparent 29px,
|
||||||
transparent 29px,
|
rgba(255, 255, 255, 0.1) 30px) !important;
|
||||||
rgba(255, 255, 255, 0.1) 30px
|
|
||||||
) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4. Quadrillé - Grid */
|
/* 4. Quadrillé - Grid */
|
||||||
@ -2126,25 +2211,21 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
.note-card.note-filter-stripes,
|
.note-card.note-filter-stripes,
|
||||||
.note-modal.note-filter-stripes,
|
.note-modal.note-filter-stripes,
|
||||||
.link-outer.note-filter-stripes {
|
.link-outer.note-filter-stripes {
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(45deg,
|
||||||
45deg,
|
transparent,
|
||||||
transparent,
|
transparent 10px,
|
||||||
transparent 10px,
|
rgba(0, 0, 0, 0.05) 10px,
|
||||||
rgba(0, 0, 0, 0.05) 10px,
|
rgba(0, 0, 0, 0.05) 20px) !important;
|
||||||
rgba(0, 0, 0, 0.05) 20px
|
|
||||||
) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .note-card.note-filter-stripes,
|
[data-theme="dark"] .note-card.note-filter-stripes,
|
||||||
[data-theme="dark"] .note-modal.note-filter-stripes,
|
[data-theme="dark"] .note-modal.note-filter-stripes,
|
||||||
[data-theme="dark"] .link-outer.note-filter-stripes {
|
[data-theme="dark"] .link-outer.note-filter-stripes {
|
||||||
background-image: repeating-linear-gradient(
|
background-image: repeating-linear-gradient(45deg,
|
||||||
45deg,
|
transparent,
|
||||||
transparent,
|
transparent 10px,
|
||||||
transparent 10px,
|
rgba(255, 255, 255, 0.05) 10px,
|
||||||
rgba(255, 255, 255, 0.05) 10px,
|
rgba(255, 255, 255, 0.05) 20px) !important;
|
||||||
rgba(255, 255, 255, 0.05) 20px
|
|
||||||
) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =========================================
|
/* =========================================
|
||||||
@ -2284,7 +2365,7 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
border: 2px solid white;
|
border: 2px solid white;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.4), inset 0 0 0 1px rgba(0,0,0,0.2);
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4), inset 0 0 0 1px rgba(0, 0, 0, 0.2);
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@ -2312,7 +2393,7 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: white;
|
background: white;
|
||||||
border: 2px solid rgba(15, 23, 42, 0.3);
|
border: 2px solid rgba(15, 23, 42, 0.3);
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2322,7 +2403,7 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: white;
|
background: white;
|
||||||
border: 2px solid rgba(15, 23, 42, 0.3);
|
border: 2px solid rgba(15, 23, 42, 0.3);
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2478,12 +2559,12 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
|
|
||||||
.bg-studio-swatch:hover {
|
.bg-studio-swatch:hover {
|
||||||
transform: scale(1.12);
|
transform: scale(1.12);
|
||||||
box-shadow: 0 6px 16px rgba(0,0,0,0.3);
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-studio-swatch.is-active {
|
.bg-studio-swatch.is-active {
|
||||||
border: 2px solid rgba(255, 255, 255, 0.95);
|
border: 2px solid rgba(255, 255, 255, 0.95);
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-studio-swatch-custom {
|
.bg-studio-swatch-custom {
|
||||||
@ -2521,7 +2602,12 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
/* Custom note color style */
|
/* Custom note color style */
|
||||||
.note-card.note-color-custom,
|
.note-card.note-color-custom,
|
||||||
.note-modal.note-color-custom {
|
.note-modal.note-color-custom {
|
||||||
border-color: transparent;
|
border-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .note-card.note-color-custom,
|
||||||
|
[data-theme="dark"] .note-modal.note-color-custom {
|
||||||
|
border-color: #dedfe2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure Font section is properly sized */
|
/* Ensure Font section is properly sized */
|
||||||
@ -2533,14 +2619,13 @@ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --- ARCHIVE VIEW --- */
|
/* --- ARCHIVE VIEW --- */
|
||||||
|
/* Ensure archive view uses same background as notes view */
|
||||||
body.view-archive .content-container {
|
body.view-archive .content-container {
|
||||||
padding: 2rem;
|
background-color: var(--bg-body) !important;
|
||||||
background-color: var(--bg-body);
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] body.view-archive .content-container {
|
[data-theme="dark"] body.view-archive .content-container {
|
||||||
background-color: var(--bg-body);
|
background-color: #20293a !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Archive Title */
|
/* Archive Title */
|
||||||
@ -2579,25 +2664,20 @@ body.view-archive .content-container {
|
|||||||
color: #9aa0a6;
|
color: #9aa0a6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Archive wrapper */
|
|
||||||
.archive-wrapper {
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Archive top bar adjustments */
|
/* Archive top bar adjustments */
|
||||||
.archive-top-bar {
|
.archive-top-bar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.archive-top-bar .notes-tools {
|
.archive-top-bar .notes-tools {
|
||||||
position: relative;
|
position: absolute;
|
||||||
right: auto;
|
right: 1rem;
|
||||||
top: auto;
|
top: 50%;
|
||||||
transform: none;
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.view-todo .note-card.todo-card .note-body {
|
body.view-todo .note-card.todo-card .note-body {
|
||||||
@ -2747,12 +2827,12 @@ body.view-todo .note-card.todo-card .todo-checklist-preview-wrap {
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-item-checkbox:checked + .todo-checklist-box-ui {
|
.todo-item-checkbox:checked+.todo-checklist-box-ui {
|
||||||
background: currentColor;
|
background: currentColor;
|
||||||
box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.22);
|
box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.22);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .todo-item-checkbox:checked + .todo-checklist-box-ui {
|
[data-theme="dark"] .todo-item-checkbox:checked+.todo-checklist-box-ui {
|
||||||
box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.35);
|
box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -325,6 +325,7 @@ a:focus:not(:focus-visible) {
|
|||||||
.sidebar-add-segment span {
|
.sidebar-add-segment span {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-add-segment {
|
.sidebar-add-segment {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
}
|
}
|
||||||
@ -3246,6 +3247,7 @@ select:focus {
|
|||||||
.page-edit .toastui-editor-mode-switch {
|
.page-edit .toastui-editor-mode-switch {
|
||||||
background: var(--bookmark-input-bg);
|
background: var(--bookmark-input-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-edit .toastui-editor-defaultUI {
|
.page-edit .toastui-editor-defaultUI {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
@ -3266,6 +3268,10 @@ select:focus {
|
|||||||
background-color: rgba(126, 168, 255, 0.16);
|
background-color: rgba(126, 168, 255, 0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-edit .toastui-editor-toolbar-margin {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.page-edit .toastui-editor-toolbar-icons {
|
.page-edit .toastui-editor-toolbar-icons {
|
||||||
opacity: 0.96;
|
opacity: 0.96;
|
||||||
}
|
}
|
||||||
@ -3283,6 +3289,148 @@ select:focus {
|
|||||||
border-top: 1px solid var(--bookmark-input-border);
|
border-top: 1px solid var(--bookmark-input-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-defaultUI,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-md-container,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-ww-container,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-defaultUI,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-md-container,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-ww-container {
|
||||||
|
background: var(--toastui-panel-surface, #0a1429) !important;
|
||||||
|
color: var(--bookmark-text-main, var(--text-main)) !important;
|
||||||
|
border-color: var(--toastui-border, #1f3560) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-mode-switch,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-mode-switch {
|
||||||
|
background: var(--toastui-toolbar-bg, linear-gradient(180deg, rgba(28, 49, 86, 0.95) 0%, rgba(14, 26, 47, 0.96) 100%)) !important;
|
||||||
|
border-color: var(--toastui-border, #1f3560) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar {
|
||||||
|
border-bottom: 1px solid var(--toastui-border, #1f3560) !important;
|
||||||
|
box-shadow: inset 0 -1px 0 rgba(9, 12, 23, 0.6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-md-tab-container,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-mode-switch,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-md-tab-container,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-mode-switch {
|
||||||
|
border-top: 1px solid var(--toastui-border, #1f3560) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-mode-switch .tab-item,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-mode-switch .tab-item {
|
||||||
|
background: transparent !important;
|
||||||
|
color: var(--bookmark-text-muted, var(--text-secondary)) !important;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0.45rem 0.8rem;
|
||||||
|
transition: background-color 0.2s ease, color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-mode-switch .tab-item.active,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-mode-switch .tab-item.selected,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-mode-switch .tab-item.active,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-mode-switch .tab-item.selected {
|
||||||
|
background: var(--toastui-tab-hover, rgba(112, 160, 255, 0.24)) !important;
|
||||||
|
color: var(--bookmark-text-main, var(--text-main)) !important;
|
||||||
|
box-shadow: 0 4px 18px rgba(23, 40, 72, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button {
|
||||||
|
color: #e2e9ff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button:hover,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button.active,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button:focus-visible,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button:hover,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button.active,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button:focus-visible {
|
||||||
|
background-color: rgba(118, 164, 255, 0.26) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button:hover .toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button.active .toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button:focus-visible .toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button:hover .toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button.active .toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button:focus-visible .toastui-editor-toolbar-icons {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-icons {
|
||||||
|
opacity: 0.85 !important;
|
||||||
|
filter: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-icons::before,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-icons::after,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-icons::before,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-icons::after {
|
||||||
|
filter: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button.toastui-editor-toolbar-icons,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button.toastui-editor-toolbar-icons {
|
||||||
|
filter: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button svg,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button svg *,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button svg,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button svg * {
|
||||||
|
fill: rgba(255, 255, 255, 0.85) !important;
|
||||||
|
stroke: rgba(255, 255, 255, 0.85) !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-divider,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-divider {
|
||||||
|
background-color: rgba(255, 255, 255, 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar *,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar * {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-group,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-group {
|
||||||
|
background: transparent !important;
|
||||||
|
border-color: rgba(255, 255, 255, 0.12) !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-group:not(:last-child),
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-group:not(:last-child) {
|
||||||
|
border-right-color: rgba(255, 255, 255, 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar-item,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar-item {
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-toolbar button,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-toolbar button {
|
||||||
|
background-color: transparent !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-contents,
|
||||||
|
[data-theme="dark"] .page-add .toastui-editor-contents *,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-contents,
|
||||||
|
[data-theme="dark"] .page-edit .toastui-editor-contents * {
|
||||||
|
color: var(--bookmark-text-main, var(--text-main)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.page-edit .bookmark-tags-input {
|
.page-edit .bookmark-tags-input {
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -3534,6 +3682,11 @@ select:focus {
|
|||||||
--bookmark-tag-remove-bg: rgba(255, 255, 255, 0.16);
|
--bookmark-tag-remove-bg: rgba(255, 255, 255, 0.16);
|
||||||
--bookmark-tag-remove-bg-hover: rgba(255, 255, 255, 0.26);
|
--bookmark-tag-remove-bg-hover: rgba(255, 255, 255, 0.26);
|
||||||
--bookmark-save-bg: linear-gradient(135deg, #6fa8ff 0%, #4d82f0 100%);
|
--bookmark-save-bg: linear-gradient(135deg, #6fa8ff 0%, #4d82f0 100%);
|
||||||
|
--toastui-panel-bg: #101d38;
|
||||||
|
--toastui-panel-surface: #0a1429;
|
||||||
|
--toastui-toolbar-bg: linear-gradient(180deg, rgba(28, 49, 86, 0.95) 0%, rgba(14, 26, 47, 0.96) 100%);
|
||||||
|
--toastui-border: #1f3560;
|
||||||
|
--toastui-tab-hover: rgba(112, 160, 255, 0.24);
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-edit .bookmark-editor-card {
|
.page-edit .bookmark-editor-card {
|
||||||
@ -4018,7 +4171,7 @@ select:focus {
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row > [class*="col-"] {
|
.row>[class*="col-"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
float: none;
|
float: none;
|
||||||
@ -4577,4 +4730,4 @@ table {
|
|||||||
.search-results {
|
.search-results {
|
||||||
max-height: calc(90vh - 200px);
|
max-height: calc(90vh - 200px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,10 +17,10 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{$batchModeValue=empty($batch_mode) ? '0' : '1'}
|
{$batchModeValue=empty($batch_mode) ? '0' : '1'}
|
||||||
{function="($readLaterChecked = strpos(' ' . $link.tags . ' ', ' readitlater ') != false || strpos(' ' . $link.tags . ' ', ' readlater ') != false || strpos(' ' . $link.tags . ' ', ' toread ') != false) ? '' : ''"}
|
{function="($readLaterChecked = strpos(' ' . $link.tags . ' ', ' readitlater ') != false || strpos(' ' . $link.tags . ' ', ' readlater ') != false || strpos(' ' . $link.tags . ' ', ' toread ') != false) ? '' : ''"}
|
||||||
{function="($isNoteOrTodo = strpos(' ' . $link.tags . ' ', ' note ') != false || strpos(' ' . $link.tags . ' ', ' shaarli-todo ') != false || strpos(' ' . $link.tags . ' ', ' shaarli-todo ') != false) ? '' : ''"}
|
{function="($isNoteOrTodo = strpos(' ' . $link.tags . ' ', ' note ') != false || strpos(' ' . $link.tags . ' ', ' shaarli-note ') != false || strpos(' ' . $link.tags . ' ', ' todo ') != false || strpos(' ' . $link.tags . ' ', ' shaarli-todo ') != false) ? '' : ''"}
|
||||||
{function="($noteDefaultChecked = $link_is_new && empty($link.url) && !$isNoteOrTodo) ? '' : ''"}
|
{function="($noteDefaultChecked = $link_is_new && empty($link.url) && !$isNoteOrTodo) ? '' : ''"}
|
||||||
{function="($noteChecked = strpos(' ' . $link.tags . ' ', ' note ') != false || $noteDefaultChecked) ? '' : ''"}
|
{function="($noteChecked = strpos(' ' . $link.tags . ' ', ' note ') != false || strpos(' ' . $link.tags . ' ', ' shaarli-note ') != false || $noteDefaultChecked) ? '' : ''"}
|
||||||
{function="($todoChecked = strpos(' ' . $link.tags . ' ', ' shaarli-todo ') != false) ? '' : ''"}
|
{function="($todoChecked = strpos(' ' . $link.tags . ' ', ' todo ') != false || strpos(' ' . $link.tags . ' ', ' shaarli-todo ') != false) ? '' : ''"}
|
||||||
{$effectiveTags=$link.tags}
|
{$effectiveTags=$link.tags}
|
||||||
{if="$noteDefaultChecked && strpos(' ' . $effectiveTags . ' ', ' note ') == false"}
|
{if="$noteDefaultChecked && strpos(' ' . $effectiveTags . ' ', ' note ') == false"}
|
||||||
{$effectiveTags=trim($effectiveTags . ' note')}
|
{$effectiveTags=trim($effectiveTags . ' note')}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ visibility: '{$visibility}',
|
|||||||
untaggedonly: (function(){/*{if="$untaggedonly"}*/return true;/*{else}*/return false;/*{/if}*/})()
|
untaggedonly: (function(){/*{if="$untaggedonly"}*/return true;/*{else}*/return false;/*{/if}*/})()
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/shaarit-rules.js?v=1.0.0" defer></script>
|
||||||
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/script.js?v=1.0.5" defer></script>
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/script.js?v=1.0.5" defer></script>
|
||||||
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/custom_views.js?v=1.0.6" defer></script>
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/js/custom_views.js?v=1.0.6" defer></script>
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
// Check URL parameters for custom views
|
// Check URL parameters for custom views
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const searchTagsRaw = urlParams.get("searchtags") || urlParams.get("searchTags") || "";
|
const searchTagsRaw = urlParams.get("searchtags") || urlParams.get("searchTags") || "";
|
||||||
|
|
||||||
// Also check URL path for tag format (e.g., /tag/note)
|
// Also check URL path for tag format (e.g., /tag/note)
|
||||||
const urlPath = window.location.pathname;
|
const urlPath = window.location.pathname;
|
||||||
const pathMatch = urlPath.match(/\/tag\/(.+)$/);
|
const pathMatch = urlPath.match(/\/tag\/(.+)$/);
|
||||||
@ -10,17 +10,21 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
|
|
||||||
// Parse all active tags to safely detect the view
|
// Parse all active tags to safely detect the view
|
||||||
const activeTags = (searchTagsRaw + " " + pathTagRaw).toLowerCase().split(/[\s,]+/).filter(t => t);
|
const activeTags = (searchTagsRaw + " " + pathTagRaw).toLowerCase().split(/[\s,]+/).filter(t => t);
|
||||||
|
|
||||||
// Foolproof detection using sidebar active state and DOM rendered tags
|
// Foolproof detection using sidebar active state and DOM rendered tags
|
||||||
const hasNoteActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Notes"].active, .header-nav-link[aria-label="Notes"].active, .sidebar-link[href*="searchtags=note"].active, .sidebar-link[href*="searchtags=shaarli-note"].active');
|
const hasNoteActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Notes"].active, .header-nav-link[aria-label="Notes"].active, .sidebar-link[href*="searchtags=note"].active, .sidebar-link[href*="searchtags=shaarli-note"].active');
|
||||||
const hasTodoActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Mes tâches"].active, .header-nav-link[aria-label="Mes tâches"].active, .sidebar-link[href*="searchtags=shaarli-todo"].active');
|
const hasTodoActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Mes tâches"].active, .header-nav-link[aria-label="Mes tâches"].active, .sidebar-link[href*="searchtags=shaarli-todo"].active, .sidebar-link[href*="searchtags=todo"].active');
|
||||||
const hasArchiveActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Archive"].active, .header-nav-link[aria-label="Archive"].active, .sidebar-link[href*="searchtags=shaarli-archive"].active');
|
const hasArchiveActiveMenu = !!document.querySelector('.sidebar-link[aria-label="Archive"].active, .header-nav-link[aria-label="Archive"].active, .sidebar-link[href*="searchtags=shaarli-archive"].active, .sidebar-link[href*="searchtags=shaarli-archiver"].active');
|
||||||
|
|
||||||
const domChipTags = Array.from(document.querySelectorAll('.search-tag-chip')).map(el => (el.textContent || "").trim().toLowerCase());
|
const domChipTags = Array.from(document.querySelectorAll('.search-tag-chip')).map(el => (el.textContent || "").trim().toLowerCase());
|
||||||
|
|
||||||
const isNoteView = activeTags.includes("note") || activeTags.includes("shaarli-note") || hasNoteActiveMenu || domChipTags.includes("note") || domChipTags.includes("shaarli-note");
|
const isArchiveTag = (tag) => tag === "shaarli-archive" || tag === "shaarli-archiver";
|
||||||
const isTodoView = activeTags.includes("shaarli-todo") || hasTodoActiveMenu || domChipTags.includes("shaarli-todo");
|
const isNoteTag = (tag) => tag === "note" || tag === "shaarli-note" || tag === "#note";
|
||||||
const isArchiveView = activeTags.includes("shaarli-archive") || hasArchiveActiveMenu || domChipTags.includes("shaarli-archive");
|
const isTodoTag = (tag) => tag === "todo" || tag === "shaarli-todo" || tag === "#todo";
|
||||||
|
|
||||||
|
const isNoteView = activeTags.some(isNoteTag) || hasNoteActiveMenu || domChipTags.some(isNoteTag);
|
||||||
|
const isTodoView = activeTags.some(isTodoTag) || hasTodoActiveMenu || domChipTags.some(isTodoTag);
|
||||||
|
const isArchiveView = activeTags.some(isArchiveTag) || hasArchiveActiveMenu || domChipTags.some(isArchiveTag);
|
||||||
|
|
||||||
const linkList = document.getElementById("links-list");
|
const linkList = document.getElementById("links-list");
|
||||||
const container = document.querySelector(".content-container");
|
const container = document.querySelector(".content-container");
|
||||||
@ -194,9 +198,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const checked = String(todoMatch[1]).toLowerCase() === "x";
|
const checked = String(todoMatch[1]).toLowerCase() === "x";
|
||||||
html.push(
|
html.push(
|
||||||
`<li class="md-todo-item${checked ? " is-checked" : ""}">`
|
`<li class="md-todo-item${checked ? " is-checked" : ""}">`
|
||||||
+ `<span class="md-todo-box" aria-hidden="true"><i class="mdi mdi-check"></i></span>`
|
+ `<span class="md-todo-box" aria-hidden="true"><i class="mdi mdi-check"></i></span>`
|
||||||
+ `<span class="md-todo-text">${renderInline(todoMatch[2])}</span>`
|
+ `<span class="md-todo-text">${renderInline(todoMatch[2])}</span>`
|
||||||
+ "</li>",
|
+ "</li>",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -409,9 +413,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
initBookmarkPaletteButtons();
|
initBookmarkPaletteButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof organizePinnedBookmarks === "function") {
|
if (typeof organizePinnedBookmarks === "function") {
|
||||||
window.requestAnimationFrame(organizePinnedBookmarks);
|
window.requestAnimationFrame(organizePinnedBookmarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always init Pinned Items logic (sorting and listeners)
|
// Always init Pinned Items logic (sorting and listeners)
|
||||||
// This function is defined at the end of the file
|
// This function is defined at the end of the file
|
||||||
@ -466,7 +470,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
|
|
||||||
// Charger les backgrounds dynamiquement, puis initialiser les vues
|
// Charger les backgrounds dynamiquement, puis initialiser les vues
|
||||||
initThemeModeBackgroundSync();
|
initThemeModeBackgroundSync();
|
||||||
|
|
||||||
if (typeof loadBackgroundOptions === "function") {
|
if (typeof loadBackgroundOptions === "function") {
|
||||||
loadBackgroundOptions()
|
loadBackgroundOptions()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -500,7 +504,7 @@ const NOTE_COLOR_OPTIONS = [
|
|||||||
{
|
{
|
||||||
key: "default",
|
key: "default",
|
||||||
label: "Par défaut",
|
label: "Par défaut",
|
||||||
light: "#ffffff",
|
light: "#f8fafc",
|
||||||
dark: "#20293A"
|
dark: "#20293A"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -605,13 +609,15 @@ const NOTE_BACKGROUND_TAG_PREFIX = "notebg-";
|
|||||||
|
|
||||||
function isTechnicalTag(tag) {
|
function isTechnicalTag(tag) {
|
||||||
if (typeof tag !== "string") return false;
|
if (typeof tag !== "string") return false;
|
||||||
const t = tag.trim();
|
const t = tag.trim().toLowerCase();
|
||||||
if (!t) return false;
|
if (!t) return false;
|
||||||
|
|
||||||
if (t === "note") return true;
|
if (t === "note" || t === "#note") return true;
|
||||||
if (t === "shaarli-note") return true;
|
if (t === "shaarli-note") return true;
|
||||||
|
if (t === "todo" || t === "#todo") return true;
|
||||||
if (t === "shaarli-todo") return true;
|
if (t === "shaarli-todo") return true;
|
||||||
if (t === "shaarli-pin") return true;
|
if (t === "shaarli-pin") return true;
|
||||||
|
if (t === "brain-dump") return true;
|
||||||
if (t.startsWith(NOTE_FONT_COLOR_TAG_PREFIX)) return true;
|
if (t.startsWith(NOTE_FONT_COLOR_TAG_PREFIX)) return true;
|
||||||
if (t.startsWith(NOTE_COLOR_TAG_PREFIX)) return true;
|
if (t.startsWith(NOTE_COLOR_TAG_PREFIX)) return true;
|
||||||
if (t.startsWith(NOTE_FILTER_TAG_PREFIX)) return true;
|
if (t.startsWith(NOTE_FILTER_TAG_PREFIX)) return true;
|
||||||
@ -694,6 +700,16 @@ function removeTagFromEntity(editUrl, tag) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteEntitySilently(deleteUrl) {
|
||||||
|
if (!deleteUrl || deleteUrl === "#") return Promise.reject("Invalid delete URL");
|
||||||
|
|
||||||
|
return fetch(deleteUrl)
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) throw new Error("Delete request failed");
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let tagDisplayRemovalInitialized = false;
|
let tagDisplayRemovalInitialized = false;
|
||||||
function initTagDisplayAndRemoval() {
|
function initTagDisplayAndRemoval() {
|
||||||
if (tagDisplayRemovalInitialized) return;
|
if (tagDisplayRemovalInitialized) return;
|
||||||
@ -1136,7 +1152,7 @@ function getElementVisualFontColor(element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function refreshNoteFilterVisuals() {
|
function refreshNoteFilterVisuals() {
|
||||||
document.querySelectorAll(".note-card, .note-modal, .link-outer").forEach((element) => {
|
document.querySelectorAll(".note-card, .note-modal, .link-outer, .note-input-container").forEach((element) => {
|
||||||
applyNoteVisualState(element, {
|
applyNoteVisualState(element, {
|
||||||
color: getElementVisualColor(element),
|
color: getElementVisualColor(element),
|
||||||
filter: getElementVisualFilter(element),
|
filter: getElementVisualFilter(element),
|
||||||
@ -1238,7 +1254,7 @@ function initThemeModeBackgroundSync() {
|
|||||||
if (nextTheme === lastTheme) return;
|
if (nextTheme === lastTheme) return;
|
||||||
|
|
||||||
lastTheme = nextTheme;
|
lastTheme = nextTheme;
|
||||||
refreshNoteBackgroundVisuals();
|
refreshNoteFilterVisuals();
|
||||||
refreshBackgroundPalettes();
|
refreshBackgroundPalettes();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1388,17 +1404,12 @@ function ensureBackgroundStudioPanel() {
|
|||||||
if (action === "set-defaults") {
|
if (action === "set-defaults") {
|
||||||
if (mode === "draft") {
|
if (mode === "draft") {
|
||||||
panelEl.dataset.color = "default";
|
panelEl.dataset.color = "default";
|
||||||
panelEl.dataset.filter = "none";
|
applyDraft({ color: "default" });
|
||||||
panelEl.dataset.background = "none";
|
|
||||||
panelEl.dataset.fontColor = "auto";
|
|
||||||
applyDraft({ color: "default", filter: "none", background: "none", fontColor: "auto" });
|
|
||||||
renderBackgroundStudioPanel(panelEl);
|
renderBackgroundStudioPanel(panelEl);
|
||||||
} else if (mode === "modal") {
|
} else if (mode === "modal") {
|
||||||
setModalNoteColor("default");
|
setModalNoteColor("default");
|
||||||
setModalNoteFilter("none");
|
|
||||||
} else {
|
} else {
|
||||||
setNoteColor(entityId, "default", editUrl);
|
setNoteColor(entityId, "default", editUrl);
|
||||||
setNoteFilter(entityId, "none", editUrl);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1814,7 +1825,7 @@ function applyNoteVisualState(element, note) {
|
|||||||
|
|
||||||
if (colorValue) {
|
if (colorValue) {
|
||||||
element.style.backgroundColor = colorValue;
|
element.style.backgroundColor = colorValue;
|
||||||
element.style.borderColor = "transparent";
|
element.style.removeProperty("border-color");
|
||||||
} else {
|
} else {
|
||||||
element.style.removeProperty("background-color");
|
element.style.removeProperty("background-color");
|
||||||
}
|
}
|
||||||
@ -2323,7 +2334,7 @@ function initTodoView(linkList, container) {
|
|||||||
<div class="palette-popup note-modal-palette" id="todo-modal-color-popup"></div>
|
<div class="palette-popup note-modal-palette" id="todo-modal-color-popup"></div>
|
||||||
</div>
|
</div>
|
||||||
<a href="#" id="todo-modal-edit" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
<a href="#" id="todo-modal-edit" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
||||||
<button type="button" id="todo-modal-delete" title="Supprimer"><i class="mdi mdi-dots-vertical"></i></button>
|
<button type="button" id="todo-modal-delete" title="Supprimer"><i class="mdi mdi-delete-outline"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="note-modal-close-btn" id="todo-modal-close">Fermer</button>
|
<button type="button" class="note-modal-close-btn" id="todo-modal-close">Fermer</button>
|
||||||
</div>
|
</div>
|
||||||
@ -2403,10 +2414,19 @@ function initTodoView(linkList, container) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
modalOverlay.querySelector("#todo-modal-delete").addEventListener("click", () => {
|
modalOverlay.querySelector("#todo-modal-delete").addEventListener("click", () => {
|
||||||
|
if (!confirm("Supprimer cette tâche ?")) return;
|
||||||
const modalCard = modalOverlay.querySelector(".note-modal");
|
const modalCard = modalOverlay.querySelector(".note-modal");
|
||||||
const deleteUrl = modalCard.dataset.deleteUrl;
|
const deleteUrl = modalCard.dataset.deleteUrl;
|
||||||
|
const todoId = modalCard.dataset.todoId;
|
||||||
if (deleteUrl && deleteUrl !== "#") {
|
if (deleteUrl && deleteUrl !== "#") {
|
||||||
window.location.href = deleteUrl;
|
deleteEntitySilently(deleteUrl)
|
||||||
|
.then(() => {
|
||||||
|
window.location.href = "/?searchtags=shaarli-todo";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Delete failed:", err);
|
||||||
|
alert("Erreur lors de la suppression.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2884,6 +2904,13 @@ function renderTodos(container, todos, viewMode) {
|
|||||||
const actions = document.createElement("div");
|
const actions = document.createElement("div");
|
||||||
actions.className = "note-hover-actions";
|
actions.className = "note-hover-actions";
|
||||||
|
|
||||||
|
const pinCorner = document.createElement("a");
|
||||||
|
pinCorner.href = todo.pinUrl;
|
||||||
|
pinCorner.title = todo.isPinned ? "Unpin" : "Pin";
|
||||||
|
pinCorner.className = `note-pin-corner ${todo.isPinned ? "active" : ""}`;
|
||||||
|
pinCorner.innerHTML = `<i class="mdi mdi-pin${todo.isPinned ? "" : "-outline"}"></i>`;
|
||||||
|
inner.appendChild(pinCorner);
|
||||||
|
|
||||||
const paletteBtnId = `palette-${todo.id}`;
|
const paletteBtnId = `palette-${todo.id}`;
|
||||||
|
|
||||||
actions.innerHTML = `
|
actions.innerHTML = `
|
||||||
@ -2891,11 +2918,25 @@ function renderTodos(container, todos, viewMode) {
|
|||||||
<button title="Couleur" id="${paletteBtnId}"><i class="mdi mdi-palette-outline"></i></button>
|
<button title="Couleur" id="${paletteBtnId}"><i class="mdi mdi-palette-outline"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<a href="${todo.pinUrl}" title="${todo.isPinned ? "Unpin" : "Pin"}" class="${todo.isPinned ? "active" : ""}"><i class="mdi mdi-pin${todo.isPinned ? "" : "-outline"}"></i></a>
|
<a href="${todo.editUrl}" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
||||||
<a href="${todo.editUrl}" title="Edit"><i class="mdi mdi-pencil-outline"></i></a>
|
<button title="Supprimer" class="todo-delete-btn"><i class="mdi mdi-delete-outline"></i></button>
|
||||||
<button title="Plus" onclick="window.location.href='${todo.deleteUrl}'"><i class="mdi mdi-dots-vertical"></i></button>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const deleteBtn = actions.querySelector(".todo-delete-btn");
|
||||||
|
deleteBtn?.addEventListener("click", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!confirm("Supprimer cette tâche ?")) return;
|
||||||
|
deleteEntitySilently(todo.deleteUrl)
|
||||||
|
.then(() => {
|
||||||
|
window.location.href = "/?searchtags=shaarli-todo";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Delete failed:", err);
|
||||||
|
alert("Erreur lors de la suppression.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const paletteBtn = actions.querySelector(`#${paletteBtnId}`);
|
const paletteBtn = actions.querySelector(`#${paletteBtnId}`);
|
||||||
paletteBtn.addEventListener("click", (e) => {
|
paletteBtn.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -3841,7 +3882,7 @@ function initNoteView(linkList, container) {
|
|||||||
<button type="button" title="Image"><i class="mdi mdi-image-outline"></i></button>
|
<button type="button" title="Image"><i class="mdi mdi-image-outline"></i></button>
|
||||||
<button type="button" id="note-modal-archive" title="Archiver"><i class="mdi mdi-archive-arrow-down-outline"></i></button>
|
<button type="button" id="note-modal-archive" title="Archiver"><i class="mdi mdi-archive-arrow-down-outline"></i></button>
|
||||||
<a href="#" id="note-modal-edit" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
<a href="#" id="note-modal-edit" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
||||||
<button type="button" id="note-modal-delete" title="Supprimer"><i class="mdi mdi-dots-vertical"></i></button>
|
<button type="button" id="note-modal-delete" title="Supprimer"><i class="mdi mdi-delete-outline"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="note-modal-close-btn" id="note-modal-close">Fermer</button>
|
<button type="button" class="note-modal-close-btn" id="note-modal-close">Fermer</button>
|
||||||
</div>
|
</div>
|
||||||
@ -3945,10 +3986,19 @@ function initNoteView(linkList, container) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
modalOverlay.querySelector("#note-modal-delete").addEventListener("click", () => {
|
modalOverlay.querySelector("#note-modal-delete").addEventListener("click", () => {
|
||||||
|
if (!confirm("Supprimer cette note ?")) return;
|
||||||
const modalCard = modalOverlay.querySelector(".note-modal");
|
const modalCard = modalOverlay.querySelector(".note-modal");
|
||||||
const deleteUrl = modalCard.dataset.deleteUrl;
|
const deleteUrl = modalCard.dataset.deleteUrl;
|
||||||
|
const noteId = modalCard.dataset.noteId;
|
||||||
if (deleteUrl && deleteUrl !== "#") {
|
if (deleteUrl && deleteUrl !== "#") {
|
||||||
window.location.href = deleteUrl;
|
deleteEntitySilently(deleteUrl)
|
||||||
|
.then(() => {
|
||||||
|
window.location.href = "/?searchtags=note";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Delete failed:", err);
|
||||||
|
alert("Erreur lors de la suppression.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -4046,7 +4096,7 @@ function initArchiveView(linkList, container) {
|
|||||||
const notes = links.map((link) => parseNoteFromLink(link));
|
const notes = links.map((link) => parseNoteFromLink(link));
|
||||||
|
|
||||||
// Filter only archived notes
|
// Filter only archived notes
|
||||||
const archivedNotes = notes.filter((note) => (note.tags || []).includes("shaarli-archive"));
|
const archivedNotes = notes.filter((note) => (note.tags || []).some((t) => t === "shaarli-archive" || t === "shaarli-archiver"));
|
||||||
|
|
||||||
// Initial Render (Grid)
|
// Initial Render (Grid)
|
||||||
renderNotes(contentArea, archivedNotes, "grid", true); // true = archive mode
|
renderNotes(contentArea, archivedNotes, "grid", true); // true = archive mode
|
||||||
@ -4085,7 +4135,7 @@ function initArchiveView(linkList, container) {
|
|||||||
<button type="button" title="Image"><i class="mdi mdi-image-outline"></i></button>
|
<button type="button" title="Image"><i class="mdi mdi-image-outline"></i></button>
|
||||||
<button type="button" id="note-modal-unarchive" title="Désarchiver"><i class="mdi mdi-archive-arrow-up-outline"></i></button>
|
<button type="button" id="note-modal-unarchive" title="Désarchiver"><i class="mdi mdi-archive-arrow-up-outline"></i></button>
|
||||||
<a href="#" id="note-modal-edit" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
<a href="#" id="note-modal-edit" title="Modifier"><i class="mdi mdi-pencil-outline"></i></a>
|
||||||
<button type="button" id="note-modal-delete" title="Supprimer"><i class="mdi mdi-dots-vertical"></i></button>
|
<button type="button" id="note-modal-delete" title="Supprimer"><i class="mdi mdi-delete-outline"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="note-modal-close-btn" id="note-modal-close">Fermer</button>
|
<button type="button" class="note-modal-close-btn" id="note-modal-close">Fermer</button>
|
||||||
</div>
|
</div>
|
||||||
@ -4171,10 +4221,19 @@ function initArchiveView(linkList, container) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
modalOverlay.querySelector("#note-modal-delete").addEventListener("click", () => {
|
modalOverlay.querySelector("#note-modal-delete").addEventListener("click", () => {
|
||||||
|
if (!confirm("Supprimer cette note ?")) return;
|
||||||
const modalCard = modalOverlay.querySelector(".note-modal");
|
const modalCard = modalOverlay.querySelector(".note-modal");
|
||||||
const deleteUrl = modalCard.dataset.deleteUrl;
|
const deleteUrl = modalCard.dataset.deleteUrl;
|
||||||
|
const noteId = modalCard.dataset.noteId;
|
||||||
if (deleteUrl && deleteUrl !== "#") {
|
if (deleteUrl && deleteUrl !== "#") {
|
||||||
window.location.href = deleteUrl;
|
deleteEntitySilently(deleteUrl)
|
||||||
|
.then(() => {
|
||||||
|
window.location.href = "/?searchtags=shaarli-archive";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Delete failed:", err);
|
||||||
|
alert("Erreur lors de la suppression.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -4293,10 +4352,10 @@ function renderNotes(container, notes, viewMode, isArchiveMode = false) {
|
|||||||
let visibleNotes;
|
let visibleNotes;
|
||||||
if (isArchiveMode) {
|
if (isArchiveMode) {
|
||||||
// In archive mode: show only notes with shaarli-archive tag
|
// In archive mode: show only notes with shaarli-archive tag
|
||||||
visibleNotes = notes.filter((note) => (note.tags || []).includes("shaarli-archive"));
|
visibleNotes = notes.filter((note) => (note.tags || []).some((t) => t === "shaarli-archive" || t === "shaarli-archiver"));
|
||||||
} else {
|
} else {
|
||||||
// In normal notes mode: hide archived notes
|
// In normal notes mode: hide archived notes
|
||||||
visibleNotes = notes.filter((note) => !(note.tags || []).includes("shaarli-archive"));
|
visibleNotes = notes.filter((note) => !(note.tags || []).some((t) => t === "shaarli-archive" || t === "shaarli-archiver"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort: Pinned items first
|
// Sort: Pinned items first
|
||||||
@ -4348,7 +4407,7 @@ function renderNotes(container, notes, viewMode, isArchiveMode = false) {
|
|||||||
if (note.descHtml || note.descText || note._noteMarkdown) {
|
if (note.descHtml || note.descText || note._noteMarkdown) {
|
||||||
const body = document.createElement("div");
|
const body = document.createElement("div");
|
||||||
body.className = "note-body";
|
body.className = "note-body";
|
||||||
|
|
||||||
if (note._noteMarkdown !== undefined) {
|
if (note._noteMarkdown !== undefined) {
|
||||||
body.innerHTML = renderMarkdown(note._noteMarkdown);
|
body.innerHTML = renderMarkdown(note._noteMarkdown);
|
||||||
} else {
|
} else {
|
||||||
@ -4359,7 +4418,7 @@ function renderNotes(container, notes, viewMode, isArchiveMode = false) {
|
|||||||
body.innerHTML = renderMarkdown(textToRender);
|
body.innerHTML = renderMarkdown(textToRender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner.appendChild(body);
|
inner.appendChild(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4379,6 +4438,13 @@ function renderNotes(container, notes, viewMode, isArchiveMode = false) {
|
|||||||
const actions = document.createElement("div");
|
const actions = document.createElement("div");
|
||||||
actions.className = "note-hover-actions";
|
actions.className = "note-hover-actions";
|
||||||
|
|
||||||
|
const pinCorner = document.createElement("a");
|
||||||
|
pinCorner.href = note.pinUrl;
|
||||||
|
pinCorner.title = note.isPinned ? "Unpin" : "Pin";
|
||||||
|
pinCorner.className = `note-pin-corner ${note.isPinned ? "active" : ""}`;
|
||||||
|
pinCorner.innerHTML = `<i class="mdi mdi-pin${note.isPinned ? "" : "-outline"}"></i>`;
|
||||||
|
inner.appendChild(pinCorner);
|
||||||
|
|
||||||
// Palette Button Logic
|
// Palette Button Logic
|
||||||
const paletteBtnId = `palette-${note.id}`;
|
const paletteBtnId = `palette-${note.id}`;
|
||||||
const archiveBtnId = `archive-${note.id}`;
|
const archiveBtnId = `archive-${note.id}`;
|
||||||
@ -4393,11 +4459,25 @@ function renderNotes(container, notes, viewMode, isArchiveMode = false) {
|
|||||||
<button title="Archiver" id="${archiveBtnId}"><i class="mdi mdi-archive-arrow-down-outline"></i></button>
|
<button title="Archiver" id="${archiveBtnId}"><i class="mdi mdi-archive-arrow-down-outline"></i></button>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<!-- Real Actions -->
|
<!-- Real Actions -->
|
||||||
<a href="${note.pinUrl}" title="${note.isPinned ? "Unpin" : "Pin"}" class="${note.isPinned ? "active" : ""}"><i class="mdi mdi-pin${note.isPinned ? "" : "-outline"}"></i></a>
|
|
||||||
<button type="button" class="note-open-editor-btn" title="Modifier"><i class="mdi mdi-pencil-outline"></i></button>
|
<button type="button" class="note-open-editor-btn" title="Modifier"><i class="mdi mdi-pencil-outline"></i></button>
|
||||||
<button title="Plus" onclick="window.location.href='${note.deleteUrl}'"><i class="mdi mdi-dots-vertical"></i></button>
|
<button title="Supprimer" class="note-delete-btn"><i class="mdi mdi-delete-outline"></i></button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const deleteBtn = actions.querySelector(".note-delete-btn");
|
||||||
|
deleteBtn?.addEventListener("click", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!confirm("Supprimer cette note ?")) return;
|
||||||
|
deleteEntitySilently(note.deleteUrl)
|
||||||
|
.then(() => {
|
||||||
|
window.location.href = isArchiveMode ? "/?searchtags=shaarli-archive" : "/?searchtags=note";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Delete failed:", err);
|
||||||
|
alert("Erreur lors de la suppression.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const openEditorBtn = actions.querySelector(".note-open-editor-btn");
|
const openEditorBtn = actions.querySelector(".note-open-editor-btn");
|
||||||
openEditorBtn?.addEventListener("click", (e) => {
|
openEditorBtn?.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -5211,7 +5291,7 @@ function initPinnedItems() {
|
|||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
function (e) {
|
function (e) {
|
||||||
const btn = e.target.closest('a[href*="do=pin"], .note-hover-actions a[href*="pin"], .link-actions a[href*="pin"]');
|
const btn = e.target.closest('a[href*="do=pin"], .note-hover-actions a[href*="pin"], .note-pin-corner[href*="pin"], .link-actions a[href*="pin"]');
|
||||||
if (btn) {
|
if (btn) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -5496,15 +5576,15 @@ function openColorPickerPanel({ mode, entityId, editUrl, type }) {
|
|||||||
const bgPanel = document.getElementById("shaarli-bg-studio");
|
const bgPanel = document.getElementById("shaarli-bg-studio");
|
||||||
prevFontColorKey = bgPanel ? (bgPanel.dataset.fontColor || "auto") : "auto";
|
prevFontColorKey = bgPanel ? (bgPanel.dataset.fontColor || "auto") : "auto";
|
||||||
} else
|
} else
|
||||||
if ((mode || "entity") === "modal") {
|
if ((mode || "entity") === "modal") {
|
||||||
const modal = getOpenModalOverlay();
|
const modal = getOpenModalOverlay();
|
||||||
const modalCard = modal ? modal.querySelector(".note-modal") : null;
|
const modalCard = modal ? modal.querySelector(".note-modal") : null;
|
||||||
prevFontColorKey = (modalCard && modalCard.dataset.fontColor) ? modalCard.dataset.fontColor : "auto";
|
prevFontColorKey = (modalCard && modalCard.dataset.fontColor) ? modalCard.dataset.fontColor : "auto";
|
||||||
} else {
|
} else {
|
||||||
const noteCard = document.querySelector(`.note-card[data-id="${entityId}"]`);
|
const noteCard = document.querySelector(`.note-card[data-id="${entityId}"]`);
|
||||||
const bookmarkCard = document.querySelector(`.link-outer[data-id="${entityId}"]`);
|
const bookmarkCard = document.querySelector(`.link-outer[data-id="${entityId}"]`);
|
||||||
prevFontColorKey = (noteCard && noteCard.dataset.fontColor) ? noteCard.dataset.fontColor : ((bookmarkCard && bookmarkCard.dataset.fontColor) ? bookmarkCard.dataset.fontColor : "auto");
|
prevFontColorKey = (noteCard && noteCard.dataset.fontColor) ? noteCard.dataset.fontColor : ((bookmarkCard && bookmarkCard.dataset.fontColor) ? bookmarkCard.dataset.fontColor : "auto");
|
||||||
}
|
}
|
||||||
panel.dataset.prevFontColorKey = prevFontColorKey;
|
panel.dataset.prevFontColorKey = prevFontColorKey;
|
||||||
} else {
|
} else {
|
||||||
panel.dataset.prevFontColorKey = "";
|
panel.dataset.prevFontColorKey = "";
|
||||||
@ -5518,24 +5598,24 @@ function openColorPickerPanel({ mode, entityId, editUrl, type }) {
|
|||||||
prevColorKey = bgPanel.dataset.color || "default";
|
prevColorKey = bgPanel.dataset.color || "default";
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if ((mode || "entity") === "modal") {
|
if ((mode || "entity") === "modal") {
|
||||||
const modal = getOpenModalOverlay();
|
const modal = getOpenModalOverlay();
|
||||||
const modalCard = modal ? modal.querySelector(".note-modal") : null;
|
const modalCard = modal ? modal.querySelector(".note-modal") : null;
|
||||||
if (modalCard) {
|
if (modalCard) {
|
||||||
const isCustom = modalCard.dataset.color === "custom";
|
const isCustom = modalCard.dataset.color === "custom";
|
||||||
const cc = modalCard.dataset.customColor || "";
|
const cc = modalCard.dataset.customColor || "";
|
||||||
prevColorKey = isCustom && cc ? `custom:${cc}` : getElementVisualColor(modalCard);
|
prevColorKey = isCustom && cc ? `custom:${cc}` : getElementVisualColor(modalCard);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const noteCard = document.querySelector(`.note-card[data-id="${entityId}"]`);
|
||||||
|
const bookmarkCard = document.querySelector(`.link-outer[data-id="${entityId}"]`);
|
||||||
|
const el = noteCard || bookmarkCard;
|
||||||
|
if (el) {
|
||||||
|
const isCustom = el.dataset.color === "custom";
|
||||||
|
const cc = el.dataset.customColor || "";
|
||||||
|
prevColorKey = isCustom && cc ? `custom:${cc}` : getElementVisualColor(el);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
const noteCard = document.querySelector(`.note-card[data-id="${entityId}"]`);
|
|
||||||
const bookmarkCard = document.querySelector(`.link-outer[data-id="${entityId}"]`);
|
|
||||||
const el = noteCard || bookmarkCard;
|
|
||||||
if (el) {
|
|
||||||
const isCustom = el.dataset.color === "custom";
|
|
||||||
const cc = el.dataset.customColor || "";
|
|
||||||
prevColorKey = isCustom && cc ? `custom:${cc}` : getElementVisualColor(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panel.dataset.prevColorKey = prevColorKey;
|
panel.dataset.prevColorKey = prevColorKey;
|
||||||
} else {
|
} else {
|
||||||
panel.dataset.prevColorKey = "";
|
panel.dataset.prevColorKey = "";
|
||||||
@ -5732,10 +5812,11 @@ function openColorPickerPanel({ mode, entityId, editUrl, type }) {
|
|||||||
setFromHex(defaultColor);
|
setFromHex(defaultColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
panel.style.display = "block";
|
||||||
|
panel.style.visibility = "hidden";
|
||||||
// Position the color picker panel
|
// Position the color picker panel
|
||||||
positionColorPickerPanel(panel, mode);
|
positionColorPickerPanel(panel, mode);
|
||||||
|
panel.style.visibility = "visible";
|
||||||
panel.style.display = "block";
|
|
||||||
panel.classList.add("open");
|
panel.classList.add("open");
|
||||||
panel.setAttribute("aria-hidden", "false");
|
panel.setAttribute("aria-hidden", "false");
|
||||||
}
|
}
|
||||||
@ -5751,20 +5832,26 @@ function positionColorPickerPanel(panel, mode) {
|
|||||||
|
|
||||||
if (bgPanel && bgPanel.classList.contains("open")) {
|
if (bgPanel && bgPanel.classList.contains("open")) {
|
||||||
const bgRect = bgPanel.getBoundingClientRect();
|
const bgRect = bgPanel.getBoundingClientRect();
|
||||||
|
const panelRect = panel.getBoundingClientRect();
|
||||||
|
const panelWidth = Math.max(1, panelRect.width);
|
||||||
|
const panelHeight = Math.max(1, panelRect.height);
|
||||||
// Position to the right of the bg-studio panel
|
// Position to the right of the bg-studio panel
|
||||||
let left = bgRect.right + 10;
|
let left = bgRect.right + 10;
|
||||||
let top = bgRect.top;
|
let top = bgRect.top;
|
||||||
|
|
||||||
// Check if it fits on the right
|
// Check if it fits on the right
|
||||||
if (left + panel.offsetWidth > window.innerWidth - viewportPadding) {
|
if (left + panelWidth > window.innerWidth - viewportPadding) {
|
||||||
// Position to the left instead
|
// Position to the left instead
|
||||||
left = bgRect.left - panel.offsetWidth - 10;
|
left = bgRect.left - panelWidth - 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure it stays within viewport
|
// Ensure it stays within viewport
|
||||||
if (left < viewportPadding) left = viewportPadding;
|
if (left < viewportPadding) left = viewportPadding;
|
||||||
if (top + panel.offsetHeight > window.innerHeight - viewportPadding) {
|
if (left + panelWidth > window.innerWidth - viewportPadding) {
|
||||||
top = window.innerHeight - viewportPadding - panel.offsetHeight;
|
left = window.innerWidth - viewportPadding - panelWidth;
|
||||||
|
}
|
||||||
|
if (top + panelHeight > window.innerHeight - viewportPadding) {
|
||||||
|
top = window.innerHeight - viewportPadding - panelHeight;
|
||||||
}
|
}
|
||||||
if (top < viewportPadding) top = viewportPadding;
|
if (top < viewportPadding) top = viewportPadding;
|
||||||
|
|
||||||
@ -5775,8 +5862,10 @@ function positionColorPickerPanel(panel, mode) {
|
|||||||
} else {
|
} else {
|
||||||
// Center in viewport if bg panel not available
|
// Center in viewport if bg panel not available
|
||||||
const panelRect = panel.getBoundingClientRect();
|
const panelRect = panel.getBoundingClientRect();
|
||||||
const left = Math.max(viewportPadding, (window.innerWidth - panelRect.width) / 2);
|
const clampedWidth = Math.max(1, panelRect.width);
|
||||||
const top = Math.max(viewportPadding, (window.innerHeight - panelRect.height) / 2);
|
const clampedHeight = Math.max(1, panelRect.height);
|
||||||
|
const left = Math.max(viewportPadding, Math.min((window.innerWidth - clampedWidth) / 2, window.innerWidth - viewportPadding - clampedWidth));
|
||||||
|
const top = Math.max(viewportPadding, Math.min((window.innerHeight - clampedHeight) / 2, window.innerHeight - viewportPadding - clampedHeight));
|
||||||
panel.style.left = `${Math.round(left)}px`;
|
panel.style.left = `${Math.round(left)}px`;
|
||||||
panel.style.top = `${Math.round(top)}px`;
|
panel.style.top = `${Math.round(top)}px`;
|
||||||
}
|
}
|
||||||
@ -5899,7 +5988,7 @@ function setNoteColorVisual(noteId, colorKey) {
|
|||||||
});
|
});
|
||||||
element.classList.add("note-color-custom");
|
element.classList.add("note-color-custom");
|
||||||
element.style.backgroundColor = hex;
|
element.style.backgroundColor = hex;
|
||||||
element.style.borderColor = "transparent";
|
element.style.removeProperty("border-color");
|
||||||
element.dataset.color = "custom";
|
element.dataset.color = "custom";
|
||||||
element.dataset.customColor = hex;
|
element.dataset.customColor = hex;
|
||||||
const fg = getReadableForegroundForBackground(hex);
|
const fg = getReadableForegroundForBackground(hex);
|
||||||
@ -6038,7 +6127,7 @@ function setModalCustomNoteColor(color) {
|
|||||||
const modalCard = modal.querySelector(".note-modal");
|
const modalCard = modal.querySelector(".note-modal");
|
||||||
if (modalCard) {
|
if (modalCard) {
|
||||||
modalCard.style.backgroundColor = color;
|
modalCard.style.backgroundColor = color;
|
||||||
modalCard.style.borderColor = "transparent";
|
modalCard.style.removeProperty("border-color");
|
||||||
modalCard.dataset.color = "custom";
|
modalCard.dataset.color = "custom";
|
||||||
modalCard.dataset.customColor = color;
|
modalCard.dataset.customColor = color;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,20 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// ===== Add Todo Button Handler (Android convention) =====
|
||||||
|
const addTodoBtn = document.querySelector('.sidebar-add-todo');
|
||||||
|
if (addTodoBtn) {
|
||||||
|
addTodoBtn.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!window.ShaarItRules) {
|
||||||
|
console.warn('[shaarit] ShaarItRules not available, cannot generate todo URL');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const basePath = addTodoBtn.getAttribute('data-base-path') || '';
|
||||||
|
const todoUrl = window.ShaarItRules.generateTodoUrl();
|
||||||
|
const redirectUrl = `${basePath}/admin/shaare?post=${encodeURIComponent(todoUrl)}&tags=todo&title=%E2%9C%85%20`;
|
||||||
|
window.location.href = redirectUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ===== Theme Toggle =====
|
// ===== Theme Toggle =====
|
||||||
const themeCheckbox = document.getElementById('theme-toggle-checkbox');
|
const themeCheckbox = document.getElementById('theme-toggle-checkbox');
|
||||||
const themeIconLight = document.getElementById('theme-icon-light');
|
const themeIconLight = document.getElementById('theme-icon-light');
|
||||||
@ -88,14 +104,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const HIDDEN_TAGS_STORAGE_KEY = 'shaarli_hidden_tags';
|
const HIDDEN_TAGS_STORAGE_KEY = 'shaarli_hidden_tags';
|
||||||
|
|
||||||
// Default system tags that are hidden by default
|
// Default system tags that are hidden by default
|
||||||
|
// Harmonisé avec ShaarIt Android (PRESET_SYSTEM_TAGS).
|
||||||
const DEFAULT_HIDDEN_TAGS = [
|
const DEFAULT_HIDDEN_TAGS = [
|
||||||
'note',
|
'note',
|
||||||
'shaarli-pin',
|
'shaarli-note',
|
||||||
|
'todo',
|
||||||
'shaarli-todo',
|
'shaarli-todo',
|
||||||
|
'shaarli-pin',
|
||||||
'note-color-*',
|
'note-color-*',
|
||||||
'notebg-*',
|
'notebg-*',
|
||||||
'notefilter-*',
|
'notefilter-*',
|
||||||
|
'font-*',
|
||||||
'readitlater',
|
'readitlater',
|
||||||
|
'brain-dump',
|
||||||
'shaarli-archive'
|
'shaarli-archive'
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -1706,12 +1727,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
const syncNoteCheckbox = () => {
|
const syncNoteCheckbox = () => {
|
||||||
if (!noteCheckbox) return;
|
if (!noteCheckbox) return;
|
||||||
noteCheckbox.checked = tags.some((tag) => /^note$/i.test(tag));
|
// Reconnaît les conventions Android (`note`, `#note`) et legacy (`shaarli-note`).
|
||||||
|
noteCheckbox.checked = tags.some((tag) => /^(note|#note|shaarli-note)$/i.test(tag));
|
||||||
};
|
};
|
||||||
|
|
||||||
const syncTodoCheckbox = () => {
|
const syncTodoCheckbox = () => {
|
||||||
if (!todoCheckbox) return;
|
if (!todoCheckbox) return;
|
||||||
todoCheckbox.checked = tags.some((tag) => /^shaarli-todo$/i.test(tag));
|
// Reconnaît les conventions Android (`todo`, `#todo`) et legacy (`shaarli-todo`).
|
||||||
|
todoCheckbox.checked = tags.some((tag) => /^(todo|#todo|shaarli-todo)$/i.test(tag));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper functions to manage note emoji in title
|
// Helper functions to manage note emoji in title
|
||||||
@ -1956,6 +1979,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
form.addEventListener('submit', commitInputValue);
|
form.addEventListener('submit', commitInputValue);
|
||||||
|
|
||||||
|
// === Todo migration: shaarli-todo → todo + Android URL ===
|
||||||
|
// Lors de la sauvegarde d'un todo, remplacer le tag legacy par la norme Android
|
||||||
|
// et générer une URL Android si vide ou legacy.
|
||||||
|
form.addEventListener('submit', () => {
|
||||||
|
try {
|
||||||
|
if (!window.ShaarItRules) return;
|
||||||
|
const urlField = form.querySelector('input[name="lf_url"]');
|
||||||
|
const url = urlField ? (urlField.value || '').trim() : '';
|
||||||
|
|
||||||
|
// Vérifier si c'est un todo (tag shaarli-todo ou todo)
|
||||||
|
const hasTodoTag = tags.some((t) => /^(todo|shaarli-todo)$/i.test(t));
|
||||||
|
if (!hasTodoTag) return;
|
||||||
|
|
||||||
|
// 1. Remplacer shaarli-todo par todo
|
||||||
|
const hadLegacyTag = tags.some((t) => /^shaarli-todo$/i.test(t));
|
||||||
|
if (hadLegacyTag) {
|
||||||
|
tags = tags.filter((t) => !/^shaarli-todo$/i.test(t));
|
||||||
|
if (!tags.some((t) => /^todo$/i.test(t))) {
|
||||||
|
tags.push('todo');
|
||||||
|
}
|
||||||
|
updateHiddenTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Générer URL Android si vide ou legacy
|
||||||
|
if (!url || /^https?:\/\/shaarli-todo/.test(url) || url === 'http://shaarli-todo') {
|
||||||
|
const newUrl = window.ShaarItRules.generateTodoUrl();
|
||||||
|
urlField.value = newUrl;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[shaarit] todo migration failed:', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// === Content-type auto-tagging (harmonisation ShaarIt Android) ===
|
||||||
|
// À la soumission, détecte le type de contenu depuis l'URL et injecte
|
||||||
|
// les tags automatiques (video, podcast, radio, music, article, news,
|
||||||
|
// social, repository+dev, shopping, image, pdf...).
|
||||||
|
// Les tags déjà présents ne sont jamais dupliqués ; aucun tag n'est
|
||||||
|
// supprimé. Désactivé pour les notes/todos (URLs internes).
|
||||||
|
form.addEventListener('submit', () => {
|
||||||
|
try {
|
||||||
|
if (!window.ShaarItRules) return;
|
||||||
|
const urlField = form.querySelector('input[name="lf_url"]');
|
||||||
|
const url = urlField ? (urlField.value || '').trim() : '';
|
||||||
|
if (!url) return;
|
||||||
|
|
||||||
|
// Ne pas auto-tagger les notes/todos (URLs internes reconnues par ShaarItRules).
|
||||||
|
const fakeLink = { url: url, tags: tags };
|
||||||
|
if (window.ShaarItRules.isNote(fakeLink) || window.ShaarItRules.isTodo(fakeLink)) return;
|
||||||
|
|
||||||
|
const detection = window.ShaarItRules.detectContentType(url);
|
||||||
|
if (!detection || !detection.tags || detection.tags.length === 0) return;
|
||||||
|
|
||||||
|
tags = window.ShaarItRules.mergeAutoTags(tags, detection.tags);
|
||||||
|
updateHiddenTags();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[shaarit] content-type auto-tagging failed:', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
updateHiddenTags();
|
updateHiddenTags();
|
||||||
syncReadLaterCheckbox();
|
syncReadLaterCheckbox();
|
||||||
syncNoteCheckbox();
|
syncNoteCheckbox();
|
||||||
|
|||||||
377
shaarli-pro/js/shaarit-rules.js
Normal file
377
shaarli-pro/js/shaarit-rules.js
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/**
|
||||||
|
* shaarit-rules.js
|
||||||
|
*
|
||||||
|
* Règles métier partagées avec l'application Android ShaarIt.
|
||||||
|
* Source de vérité unique pour :
|
||||||
|
* - la détection des notes / todos / épinglés ;
|
||||||
|
* - les tags techniques cachés par défaut ;
|
||||||
|
* - la détection de type de contenu (video, podcast, radio, music, article,
|
||||||
|
* news, social, repository/dev, shopping, image, pdf, document) ;
|
||||||
|
* - la génération d'URLs internes (notes / todos).
|
||||||
|
*
|
||||||
|
* Non destructif : toutes les conventions existantes du thème web continuent
|
||||||
|
* d'être reconnues en lecture. Les règles Android viennent s'y ajouter.
|
||||||
|
*
|
||||||
|
* Exposé sur `window.ShaarItRules`.
|
||||||
|
*/
|
||||||
|
(function (global) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Tags système (cachés par défaut côté UI)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var PRESET_SYSTEM_TAGS = [
|
||||||
|
{ name: "note", desc: "Notes - Identifiant interne", hidden: true },
|
||||||
|
{ name: "shaarli-note", desc: "Notes - Alias legacy", hidden: true },
|
||||||
|
{ name: "todo", desc: "Tâches - Identifiant interne", hidden: true },
|
||||||
|
{ name: "shaarli-todo", desc: "Tâches - Alias legacy", hidden: true },
|
||||||
|
{ name: "shaarli-pin", desc: "Épinglé - Favoris en haut", hidden: true },
|
||||||
|
{ name: "note-color-*", desc: "Couleurs des notes (wildcard)", hidden: true },
|
||||||
|
{ name: "notebg-*", desc: "Fonds des notes (wildcard)", hidden: true },
|
||||||
|
{ name: "notefilter-*", desc: "Filtres des notes (wildcard)", hidden: true },
|
||||||
|
{ name: "font-*", desc: "Couleur de police (wildcard)", hidden: true },
|
||||||
|
{ name: "readitlater", desc: "À lire plus tard", hidden: true },
|
||||||
|
{ name: "brain-dump", desc: "Capture rapide d'idées", hidden: true },
|
||||||
|
{ name: "shaarli-archive", desc: "Archivé", hidden: false },
|
||||||
|
{ name: "shaarli-archiver",desc: "Archivé - Alias legacy", hidden: false }
|
||||||
|
];
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Détection d'entités (note / todo / pin) - compatibilité Android + legacy
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function toLower(x) { return String(x || "").toLowerCase(); }
|
||||||
|
|
||||||
|
function asTagArray(tags) {
|
||||||
|
if (Array.isArray(tags)) return tags.map(toLower);
|
||||||
|
if (typeof tags === "string") {
|
||||||
|
return tags.split(/[\s,|]+/).map(toLower).filter(Boolean);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Détection d'une note.
|
||||||
|
* Compatible avec les règles Android :
|
||||||
|
* - URL `note://` (mais pas `note://todo-`)
|
||||||
|
* - URL `http://shaare` / `/shaare`
|
||||||
|
* - URL `https://shaarit.app/note/...`
|
||||||
|
* - Tag `note`, `#note`, `shaarli-note`
|
||||||
|
*/
|
||||||
|
function isNote(link) {
|
||||||
|
if (!link) return false;
|
||||||
|
var url = String(link.url || "").trim();
|
||||||
|
var tags = asTagArray(link.tags);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
var u = url.toLowerCase();
|
||||||
|
if (u.indexOf("note://") === 0 && u.indexOf("note://todo-") !== 0) return true;
|
||||||
|
if (u.indexOf("http://shaare") === 0) return true;
|
||||||
|
if (u.indexOf("/shaare") === 0) return true;
|
||||||
|
if (u.indexOf("https://shaarit.app/note/") === 0) return true;
|
||||||
|
if (u.indexOf("http://shaarit.app/note/") === 0) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < tags.length; i++) {
|
||||||
|
if (tags[i] === "note" || tags[i] === "#note" || tags[i] === "shaarli-note") return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Détection d'une tâche.
|
||||||
|
* Compatible avec les règles Android :
|
||||||
|
* - URL `note://todo-...`
|
||||||
|
* - URL `https://shaarit.app/todo/...`
|
||||||
|
* - URL `http://shaarli-todo` (legacy web)
|
||||||
|
* - Tag `todo`, `#todo`, `shaarli-todo`
|
||||||
|
*/
|
||||||
|
function isTodo(link) {
|
||||||
|
if (!link) return false;
|
||||||
|
var url = String(link.url || "").trim();
|
||||||
|
var tags = asTagArray(link.tags);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
var u = url.toLowerCase();
|
||||||
|
if (u.indexOf("note://todo-") === 0) return true;
|
||||||
|
if (u.indexOf("https://shaarit.app/todo/") === 0) return true;
|
||||||
|
if (u.indexOf("http://shaarit.app/todo/") === 0) return true;
|
||||||
|
if (u.indexOf("http://shaarli-todo") === 0) return true;
|
||||||
|
if (u.indexOf("https://shaarli-todo") === 0) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < tags.length; i++) {
|
||||||
|
if (tags[i] === "todo" || tags[i] === "#todo" || tags[i] === "shaarli-todo") return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Détection épinglé via tag `shaarli-pin`. */
|
||||||
|
function isPinned(link) {
|
||||||
|
if (!link) return false;
|
||||||
|
var tags = asTagArray(link.tags);
|
||||||
|
return tags.indexOf("shaarli-pin") !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Détection archive (tag `shaarli-archive` ou legacy `shaarli-archiver`). */
|
||||||
|
function isArchived(link) {
|
||||||
|
if (!link) return false;
|
||||||
|
var tags = asTagArray(link.tags);
|
||||||
|
return tags.indexOf("shaarli-archive") !== -1 || tags.indexOf("shaarli-archiver") !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Génération d'URLs internes (style Android)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function randomId() {
|
||||||
|
// Identifiant court type base36, 12 caractères.
|
||||||
|
if (global.crypto && global.crypto.getRandomValues) {
|
||||||
|
var arr = new Uint8Array(9);
|
||||||
|
global.crypto.getRandomValues(arr);
|
||||||
|
var out = "";
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
out += ("0" + arr[i].toString(36)).slice(-2);
|
||||||
|
}
|
||||||
|
return out.substring(0, 12);
|
||||||
|
}
|
||||||
|
return (Date.now().toString(36) + Math.random().toString(36).slice(2, 10)).substring(0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateNoteUrl() {
|
||||||
|
return "https://shaarit.app/note/" + randomId();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateTodoUrl() {
|
||||||
|
return "https://shaarit.app/todo/" + randomId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Détection de type de contenu (ContentType, règles Android)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var CONTENT_TYPES = {
|
||||||
|
UNKNOWN: "unknown",
|
||||||
|
ARTICLE: "article",
|
||||||
|
VIDEO: "video",
|
||||||
|
PODCAST: "podcast",
|
||||||
|
IMAGE: "image",
|
||||||
|
PDF: "pdf",
|
||||||
|
REPOSITORY: "repository",
|
||||||
|
DOCUMENT: "document",
|
||||||
|
SOCIAL: "social",
|
||||||
|
SHOPPING: "shopping",
|
||||||
|
NEWSLETTER: "newsletter",
|
||||||
|
MUSIC: "music",
|
||||||
|
RADIO: "radio",
|
||||||
|
NEWS: "news"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tags auto-ajoutés par type de contenu (conformes règles Android UI).
|
||||||
|
var CONTENT_TYPE_TAGS = {
|
||||||
|
video: ["video"],
|
||||||
|
podcast: ["podcast"],
|
||||||
|
radio: ["radio"],
|
||||||
|
music: ["music"],
|
||||||
|
article: ["article"],
|
||||||
|
news: ["news"],
|
||||||
|
social: ["social"],
|
||||||
|
repository: ["repository", "dev"],
|
||||||
|
shopping: ["shopping"],
|
||||||
|
newsletter: ["newsletter"],
|
||||||
|
image: ["image"],
|
||||||
|
pdf: ["pdf"],
|
||||||
|
document: [],
|
||||||
|
unknown: []
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseHost(url) {
|
||||||
|
try {
|
||||||
|
var u = new URL(url);
|
||||||
|
return (u.hostname || "").toLowerCase();
|
||||||
|
} catch (e) {
|
||||||
|
// Fallback très simple si URL invalide
|
||||||
|
var m = String(url || "").match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]+)/i);
|
||||||
|
return m ? m[1].toLowerCase() : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hostContainsAny(host, list) {
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
if (host.indexOf(list[i]) !== -1) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Audio : RADIO > PODCAST > MUSIC ---
|
||||||
|
|
||||||
|
var RADIO_HOSTS = [
|
||||||
|
"playerservices.streamtheworld.com", "icecast", "shoutcast",
|
||||||
|
"fluxradios.com", "tunein.com", "radio.garden", "mytuner-radio.com",
|
||||||
|
"iheart.com", "onlineradiobox.com", "radio.net"
|
||||||
|
];
|
||||||
|
|
||||||
|
function isRadio(url, host) {
|
||||||
|
if (/\.(m3u|m3u8|pls)(\?|$)/i.test(url)) return true;
|
||||||
|
if (hostContainsAny(host, RADIO_HOSTS)) return true;
|
||||||
|
if (host.indexOf("stream.") === 0 || host.indexOf("live.") === 0) return true;
|
||||||
|
if (host.indexOf("ici.radio-canada.ca") !== -1 || host.indexOf("radio-canada.ca") !== -1) {
|
||||||
|
if (/\/balados(\/|$)/i.test(url)) return false;
|
||||||
|
if (/\/(direct|premiere|audio-fil)(\/|$)/i.test(url)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var PODCAST_HOSTS = [
|
||||||
|
"podcasts.apple.com", "overcast.fm", "pocketcasts.com", "castbox.fm",
|
||||||
|
"stitcher.com", "acast.com", "anchor.fm", "libsyn.com",
|
||||||
|
"simplecast.com", "buzzsprout.com"
|
||||||
|
];
|
||||||
|
|
||||||
|
function isPodcast(url, host) {
|
||||||
|
if (hostContainsAny(host, PODCAST_HOSTS)) return true;
|
||||||
|
if (/open\.spotify\.com\/(show|episode)\//i.test(url)) return true;
|
||||||
|
if (/\/balados(\/|$)|\/ohdio\/balados(\/|$)/i.test(url)) return true;
|
||||||
|
if (/\.(xml|rss)(\?|$)/i.test(url)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var MUSIC_HOSTS = [
|
||||||
|
"music.apple.com", "deezer.com", "tidal.com", "music.youtube.com",
|
||||||
|
"bandcamp.com", "soundcloud.com", "mixcloud.com", "beatport.com"
|
||||||
|
];
|
||||||
|
|
||||||
|
function isMusic(url, host) {
|
||||||
|
if (hostContainsAny(host, MUSIC_HOSTS)) return true;
|
||||||
|
if (/open\.spotify\.com\/(track|album|artist|playlist)\//i.test(url)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Catégories web ---
|
||||||
|
|
||||||
|
var VIDEO_HOSTS = ["youtube.com", "youtu.be", "vimeo.com", "dailymotion.com", "twitch.tv", "netflix.com"];
|
||||||
|
function isVideo(host) { return hostContainsAny(host, VIDEO_HOSTS); }
|
||||||
|
|
||||||
|
var SOCIAL_HOSTS = [
|
||||||
|
"facebook.com", "instagram.com", "tiktok.com", "twitter.com", "x.com",
|
||||||
|
"linkedin.com", "reddit.com", "snapchat.com", "pinterest.com", "mastodon"
|
||||||
|
];
|
||||||
|
function isSocial(host) { return hostContainsAny(host, SOCIAL_HOSTS); }
|
||||||
|
|
||||||
|
var REPO_HOSTS = ["github.com", "gitlab.com", "bitbucket.org", "stackoverflow.com"];
|
||||||
|
function isRepository(host) { return hostContainsAny(host, REPO_HOSTS); }
|
||||||
|
|
||||||
|
var SHOPPING_HOSTS = ["amazon", "ebay", "etsy.com", "aliexpress.com", "shopify"];
|
||||||
|
function isShopping(host) { return hostContainsAny(host, SHOPPING_HOSTS); }
|
||||||
|
|
||||||
|
var DOCUMENT_HOSTS = [
|
||||||
|
"docs.google.com", "drive.google.com", "notion.so", "trello.com",
|
||||||
|
"jira", "confluence"
|
||||||
|
];
|
||||||
|
function isDocument(host) { return hostContainsAny(host, DOCUMENT_HOSTS); }
|
||||||
|
|
||||||
|
var NEWS_HOSTS = [
|
||||||
|
"news", "nytimes", "lemonde", "bbc", "cnn", "reuters",
|
||||||
|
"theguardian", "lefigaro"
|
||||||
|
];
|
||||||
|
function isNews(host) { return hostContainsAny(host, NEWS_HOSTS); }
|
||||||
|
|
||||||
|
var NEWSLETTER_HOSTS = ["substack", "revue", "mailchimp"];
|
||||||
|
function isNewsletter(host) { return hostContainsAny(host, NEWSLETTER_HOSTS); }
|
||||||
|
|
||||||
|
var IMAGE_HOSTS = ["imgur.com", "flickr.com"];
|
||||||
|
function isImageUrl(url, host) {
|
||||||
|
if (/\.(jpe?g|png|gif|webp|bmp|svg)(\?|$)/i.test(url)) return true;
|
||||||
|
return hostContainsAny(host, IMAGE_HOSTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPdfUrl(url) {
|
||||||
|
return /\.pdf(\?|$)/i.test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Détecte le type de contenu d'une URL (règles Android).
|
||||||
|
* @returns {{type: string, tags: string[]}}
|
||||||
|
*/
|
||||||
|
function detectContentType(url) {
|
||||||
|
var raw = String(url || "").trim();
|
||||||
|
if (!raw) return { type: CONTENT_TYPES.UNKNOWN, tags: [] };
|
||||||
|
|
||||||
|
// URLs internes : pas de détection
|
||||||
|
var low = raw.toLowerCase();
|
||||||
|
if (low.indexOf("note://") === 0 ||
|
||||||
|
low.indexOf("https://shaarit.app/note/") === 0 ||
|
||||||
|
low.indexOf("https://shaarit.app/todo/") === 0 ||
|
||||||
|
low.indexOf("http://shaare") === 0 ||
|
||||||
|
low.indexOf("/shaare") === 0 ||
|
||||||
|
low.indexOf("http://shaarli-todo") === 0) {
|
||||||
|
return { type: CONTENT_TYPES.UNKNOWN, tags: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
var host = parseHost(raw);
|
||||||
|
|
||||||
|
// 1. Fichiers (priorité haute sur l'extension)
|
||||||
|
if (isPdfUrl(raw)) return { type: CONTENT_TYPES.PDF, tags: CONTENT_TYPE_TAGS.pdf };
|
||||||
|
if (isImageUrl(raw, host))return { type: CONTENT_TYPES.IMAGE, tags: CONTENT_TYPE_TAGS.image };
|
||||||
|
|
||||||
|
// 2. Audio : RADIO > PODCAST > MUSIC
|
||||||
|
if (isRadio(raw, host)) return { type: CONTENT_TYPES.RADIO, tags: CONTENT_TYPE_TAGS.radio };
|
||||||
|
if (isPodcast(raw, host)) return { type: CONTENT_TYPES.PODCAST, tags: CONTENT_TYPE_TAGS.podcast };
|
||||||
|
if (isMusic(raw, host)) return { type: CONTENT_TYPES.MUSIC, tags: CONTENT_TYPE_TAGS.music };
|
||||||
|
|
||||||
|
// 3. Vidéo
|
||||||
|
if (isVideo(host)) return { type: CONTENT_TYPES.VIDEO, tags: CONTENT_TYPE_TAGS.video };
|
||||||
|
|
||||||
|
// 4. Plateformes spécifiques
|
||||||
|
if (isRepository(host)) return { type: CONTENT_TYPES.REPOSITORY, tags: CONTENT_TYPE_TAGS.repository };
|
||||||
|
if (isDocument(host)) return { type: CONTENT_TYPES.DOCUMENT, tags: CONTENT_TYPE_TAGS.document };
|
||||||
|
if (isSocial(host)) return { type: CONTENT_TYPES.SOCIAL, tags: CONTENT_TYPE_TAGS.social };
|
||||||
|
if (isShopping(host)) return { type: CONTENT_TYPES.SHOPPING, tags: CONTENT_TYPE_TAGS.shopping };
|
||||||
|
if (isNewsletter(host)) return { type: CONTENT_TYPES.NEWSLETTER, tags: CONTENT_TYPE_TAGS.newsletter };
|
||||||
|
if (isNews(host)) return { type: CONTENT_TYPES.NEWS, tags: CONTENT_TYPE_TAGS.news };
|
||||||
|
|
||||||
|
return { type: CONTENT_TYPES.UNKNOWN, tags: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fusion d'un tableau de tags existants avec les tags auto-détectés.
|
||||||
|
* Conserve l'ordre existant, ajoute uniquement les tags manquants.
|
||||||
|
*/
|
||||||
|
function mergeAutoTags(existingTags, autoTags) {
|
||||||
|
var list = Array.isArray(existingTags) ? existingTags.slice() : [];
|
||||||
|
var lower = list.map(toLower);
|
||||||
|
(autoTags || []).forEach(function (t) {
|
||||||
|
var clean = String(t || "").trim();
|
||||||
|
if (!clean) return;
|
||||||
|
if (lower.indexOf(clean.toLowerCase()) === -1) {
|
||||||
|
list.push(clean);
|
||||||
|
lower.push(clean.toLowerCase());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Export
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var api = {
|
||||||
|
PRESET_SYSTEM_TAGS: PRESET_SYSTEM_TAGS,
|
||||||
|
CONTENT_TYPES: CONTENT_TYPES,
|
||||||
|
CONTENT_TYPE_TAGS: CONTENT_TYPE_TAGS,
|
||||||
|
|
||||||
|
isNote: isNote,
|
||||||
|
isTodo: isTodo,
|
||||||
|
isPinned: isPinned,
|
||||||
|
isArchived: isArchived,
|
||||||
|
|
||||||
|
generateNoteUrl: generateNoteUrl,
|
||||||
|
generateTodoUrl: generateTodoUrl,
|
||||||
|
|
||||||
|
detectContentType: detectContentType,
|
||||||
|
mergeAutoTags: mergeAutoTags
|
||||||
|
};
|
||||||
|
|
||||||
|
global.ShaarItRules = api;
|
||||||
|
})(typeof window !== "undefined" ? window : this);
|
||||||
@ -47,11 +47,16 @@
|
|||||||
|
|
||||||
<!-- {* ----- no links ----- *} -->
|
<!-- {* ----- no links ----- *} -->
|
||||||
{if="count($links)==0"}
|
{if="count($links)==0"}
|
||||||
|
{if="in_array('note', $active_search_tags) || in_array('shaarli-note', $active_search_tags) || in_array('todo', $active_search_tags) || in_array('shaarli-todo', $active_search_tags) || in_array('shaarli-archive', $active_search_tags) || in_array('shaarli-archiver', $active_search_tags)"}
|
||||||
|
<div class="links-list view-grid" id="links-list"></div>
|
||||||
|
{include="linklist.paging"}
|
||||||
|
{else}
|
||||||
<div class="empty-state" role="status" aria-live="polite">
|
<div class="empty-state" role="status" aria-live="polite">
|
||||||
<div class="empty-state-icon" aria-hidden="true"><i class="mdi mdi-bookmark-off-outline"></i></div>
|
<div class="empty-state-icon" aria-hidden="true"><i class="mdi mdi-bookmark-off-outline"></i></div>
|
||||||
<h2 class="empty-state-title">Aucun bookmark trouvé</h2>
|
<h2 class="empty-state-title">Aucun bookmark trouvé</h2>
|
||||||
<p class="empty-state-text">{if="!empty($search_term)"}Aucun résultat pour : <strong>{$search_term}</strong>{else}Commencez à ajouter des bookmarks pour les voir apparaître ici.{/if}</p>
|
<p class="empty-state-text">{if="!empty($search_term)"}Aucun résultat pour : <strong>{$search_term}</strong>{else}Commencez à ajouter des bookmarks pour les voir apparaître ici.{/if}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
{else}
|
{else}
|
||||||
<!-- {* ----- at least one link ----- *} -->
|
<!-- {* ----- at least one link ----- *} -->
|
||||||
<div class="links-list view-grid" id="links-list">
|
<div class="links-list view-grid" id="links-list">
|
||||||
|
|||||||
104
shaarli-pro/migrate-todos.php
Normal file
104
shaarli-pro/migrate-todos.php
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* migrate-todos.php
|
||||||
|
*
|
||||||
|
* Script de migration batch : remplace tous les todos legacy (shaarli-todo)
|
||||||
|
* par la norme Android (tag `todo` + URL `https://shaarit.app/todo/{uuid}`).
|
||||||
|
*
|
||||||
|
* À exécuter une seule fois via CLI ou interface web (si accessible).
|
||||||
|
* Usage: php migrate-todos.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Déterminer le chemin racine de Shaarli
|
||||||
|
$rootDir = dirname(dirname(dirname(__FILE__)));
|
||||||
|
require_once $rootDir . '/index.php';
|
||||||
|
|
||||||
|
// Vérifier que Shaarli est chargé
|
||||||
|
if (!isset($GLOBALS['shaarli'])) {
|
||||||
|
die("Erreur : Shaarli non chargé.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$linkDb = $GLOBALS['shaarli']->getContainer()->get('db');
|
||||||
|
if (!$linkDb) {
|
||||||
|
die("Erreur : base de données non accessible.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer tous les liens avec le tag shaarli-todo
|
||||||
|
$allLinks = $linkDb->getLinks();
|
||||||
|
$todosToMigrate = [];
|
||||||
|
|
||||||
|
foreach ($allLinks as $link) {
|
||||||
|
$tags = explode(' ', $link->getTags());
|
||||||
|
$hasTodoTag = in_array('shaarli-todo', $tags, true);
|
||||||
|
if ($hasTodoTag) {
|
||||||
|
$todosToMigrate[] = $link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($todosToMigrate)) {
|
||||||
|
echo "Aucun todo à migrer.\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Trouvé " . count($todosToMigrate) . " todo(s) à migrer.\n";
|
||||||
|
|
||||||
|
// Fonction pour générer un UUID court (style Android)
|
||||||
|
function generateTodoUuid() {
|
||||||
|
if (function_exists('random_bytes')) {
|
||||||
|
$bytes = random_bytes(9);
|
||||||
|
$out = '';
|
||||||
|
for ($i = 0; $i < 9; $i++) {
|
||||||
|
$out .= str_pad(base_convert(ord($bytes[$i]), 10, 36), 2, '0', STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
return substr($out, 0, 12);
|
||||||
|
}
|
||||||
|
return substr(base_convert(time(), 10, 36) . base_convert(mt_rand(), 10, 36), 0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrer chaque todo
|
||||||
|
$migrated = 0;
|
||||||
|
$errors = 0;
|
||||||
|
|
||||||
|
foreach ($todosToMigrate as $link) {
|
||||||
|
try {
|
||||||
|
$tags = explode(' ', $link->getTags());
|
||||||
|
|
||||||
|
// 1. Remplacer shaarli-todo par todo
|
||||||
|
$tags = array_filter($tags, function ($t) {
|
||||||
|
return $t !== 'shaarli-todo';
|
||||||
|
});
|
||||||
|
$tags = array_values($tags);
|
||||||
|
if (!in_array('todo', $tags, true)) {
|
||||||
|
$tags[] = 'todo';
|
||||||
|
}
|
||||||
|
$link->setTags($tags);
|
||||||
|
|
||||||
|
// 2. Générer URL Android si vide ou legacy
|
||||||
|
$url = $link->getUrl();
|
||||||
|
if (empty($url) || strpos($url, 'http://shaarli-todo') === 0 || strpos($url, 'https://shaarli-todo') === 0) {
|
||||||
|
$uuid = generateTodoUuid();
|
||||||
|
$link->setUrl('https://shaarit.app/todo/' . $uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sauvegarder
|
||||||
|
$linkDb->save($link);
|
||||||
|
$migrated++;
|
||||||
|
echo "✓ Migré : {$link->getTitle()} ({$link->getId()})\n";
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$errors++;
|
||||||
|
echo "✗ Erreur : {$link->getTitle()} - {$e->getMessage()}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n=== Résumé ===\n";
|
||||||
|
echo "Migrés : $migrated\n";
|
||||||
|
echo "Erreurs : $errors\n";
|
||||||
|
echo "Total : " . count($todosToMigrate) . "\n";
|
||||||
|
|
||||||
|
if ($errors === 0) {
|
||||||
|
echo "\n✓ Migration terminée avec succès !\n";
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
echo "\n⚠ Migration terminée avec $errors erreur(s).\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
@ -49,7 +49,7 @@ Bookmarklet detection logic
|
|||||||
<i class="mdi mdi-calendar-today" aria-hidden="true"></i>
|
<i class="mdi mdi-calendar-today" aria-hidden="true"></i>
|
||||||
<span>Quotidien</span>
|
<span>Quotidien</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{$base_path}/?searchtags=shaarli-todo" class="sidebar-link{if="isset($search_tags) && preg_match('/(^|[\s,])shaarli-todo([\s,]|$)/i', (string) $search_tags)"} active{/if}" aria-label="Mes tâches">
|
<a href="{$base_path}/?searchtags=todo" class="sidebar-link{if="isset($search_tags) && preg_match('/(^|[\s,])todo([\s,]|$)/i', (string) $search_tags)"} active{/if}" aria-label="Mes tâches">
|
||||||
<i class="mdi mdi-check-circle-outline" aria-hidden="true"></i>
|
<i class="mdi mdi-check-circle-outline" aria-hidden="true"></i>
|
||||||
<span>Mes tâches</span>
|
<span>Mes tâches</span>
|
||||||
</a>
|
</a>
|
||||||
@ -93,7 +93,7 @@ Bookmarklet detection logic
|
|||||||
<a href="{$base_path}/admin/shaare?tags=note" class="sidebar-add-segment" title="Note">
|
<a href="{$base_path}/admin/shaare?tags=note" class="sidebar-add-segment" title="Note">
|
||||||
<i class="mdi mdi-note-text-outline"></i>
|
<i class="mdi mdi-note-text-outline"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="{$base_path}/admin/shaare?post=http%3A%2F%2Fshaarli-todo&tags=shaarli-todo&title=%E2%9C%85%20" class="sidebar-add-segment" title="Todo">
|
<a href="#" class="sidebar-add-segment sidebar-add-todo" title="Todo" data-base-path="{$base_path}">
|
||||||
<i class="mdi mdi-check-circle-outline"></i>
|
<i class="mdi mdi-check-circle-outline"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -154,7 +154,7 @@ Bookmarklet detection logic
|
|||||||
<i class="mdi mdi-calendar" aria-hidden="true"></i>
|
<i class="mdi mdi-calendar" aria-hidden="true"></i>
|
||||||
<span>QUOTIDIEN</span>
|
<span>QUOTIDIEN</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{$base_path}/?searchtags=shaarli-todo" class="header-nav-link{if="isset($search_tags) && preg_match('/(^|[\s,])shaarli-todo([\s,]|$)/i', (string) $search_tags)"} active{/if}" aria-label="Mes tâches">
|
<a href="{$base_path}/?searchtags=todo" class="header-nav-link{if="isset($search_tags) && preg_match('/(^|[\s,])todo([\s,]|$)/i', (string) $search_tags)"} active{/if}" aria-label="Mes tâches">
|
||||||
<i class="mdi mdi-check-circle-outline" aria-hidden="true"></i>
|
<i class="mdi mdi-check-circle-outline" aria-hidden="true"></i>
|
||||||
<span>TÂCHES</span>
|
<span>TÂCHES</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -430,13 +430,19 @@
|
|||||||
(function() {
|
(function() {
|
||||||
const STORAGE_KEY = 'shaarli_hidden_tags';
|
const STORAGE_KEY = 'shaarli_hidden_tags';
|
||||||
|
|
||||||
|
// Harmonisé avec ShaarIt Android (PRESET_SYSTEM_TAGS).
|
||||||
const PRESET_TAGS = [
|
const PRESET_TAGS = [
|
||||||
{ name: 'note', desc: 'Notes - Internal note identifier' },
|
{ name: 'note', desc: 'Notes - Internal note identifier' },
|
||||||
|
{ name: 'shaarli-note', desc: 'Notes - Legacy alias' },
|
||||||
|
{ name: 'todo', desc: 'Tasks - Internal todo identifier' },
|
||||||
|
{ name: 'shaarli-todo', desc: 'Tasks - Legacy alias' },
|
||||||
{ name: 'shaarli-pin', desc: 'Pinned - Keeps bookmarks at top' },
|
{ name: 'shaarli-pin', desc: 'Pinned - Keeps bookmarks at top' },
|
||||||
{ name: 'note-color-*', desc: 'Note Colors - Wildcard for color tags' },
|
{ name: 'note-color-*', desc: 'Note Colors - Wildcard for color tags' },
|
||||||
{ name: 'notebg-*', desc: 'Note Backgrounds - Wildcard for background tags' },
|
{ name: 'notebg-*', desc: 'Note Backgrounds - Wildcard for background tags' },
|
||||||
{ name: 'notefilter-*', desc: 'Note Filters - Wildcard for filter tags' },
|
{ name: 'notefilter-*', desc: 'Note Filters - Wildcard for filter tags' },
|
||||||
|
{ name: 'font-*', desc: 'Note Font Colors - Wildcard' },
|
||||||
{ name: 'readitlater', desc: 'Read Later - Temporary reading list' },
|
{ name: 'readitlater', desc: 'Read Later - Temporary reading list' },
|
||||||
|
{ name: 'brain-dump', desc: 'Brain dump - Quick idea capture' },
|
||||||
{ name: 'shaarli-archive', desc: 'Archived - Archived notes' }
|
{ name: 'shaarli-archive', desc: 'Archived - Archived notes' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user