feat(content): v4.6.0 Content Blocks enrichis — Callout, TOC, Math (KaTeX), Toggle, Multi-colonnes
FlowDeck CI / test (push) Failing after 20s
FlowDeck CI / docker (push) Skipped

- Ajout blocs enrichis dans l'éditeur: callout (avec sélecteur d'emoji), table of contents (ancres), math (LaTeX/KaTeX), toggle lists (enfants collapsibles), multi-colonnes
- Intégration KaTeX 0.16.11 self-hosté (JS/CSS/fonts) — aucun CDN externe
- Rendu des nouveaux blocs dans les pages publiques (/p/<slug>): TOC, KaTeX, colonnes, toggle <details>
- Persistance 'children' (colonnes/toggle) + export Markdown étendu
- Sidebar customization par utilisateur (config API + colonne sidebar_config)
- Correctif test_views_calendar: parsing des query params year/month (le défaut ouvrait sur le mois courant)
- Tests: 184 passing
This commit is contained in:
2026-09-03 00:05:33 -04:00
parent d12681720d
commit 814dbe8c2e
77 changed files with 1141 additions and 88 deletions
+429 -9
View File
@@ -380,39 +380,85 @@ input, select, textarea { font-family: inherit; color: inherit; }
justify-content: space-between;
padding: 4px 6px;
border-radius: var(--radius-sm);
cursor: pointer;
transition: background var(--transition);
user-select: none;
}
.sidebar-section-header:hover {
background: var(--bg-hover);
}
.sidebar-section-header:active {
background: var(--bg-active);
transform: scale(0.995);
}
.sidebar-section-title {
display: flex;
align-items: center;
gap: var(--space-xs);
gap: 3px;
font-size: 12px;
font-weight: 600;
color: var(--text-dim);
text-transform: none;
letter-spacing: 0;
min-width: 0;
}
.sidebar-section-title .chevron {
font-size: 10px;
transition: transform var(--transition);
font-size: 8px;
width: 14px;
height: 14px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-muted);
transition: transform 180ms ease, color var(--transition);
will-change: transform;
}
.sidebar-section-title .chevron.open {
transform: rotate(90deg);
color: var(--text-secondary);
}
.sidebar-section-title .section-icon {
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--text-muted);
transition: color var(--transition);
}
.sidebar-section-header:hover .section-icon {
color: var(--text-secondary);
}
.sidebar-section-title .section-label {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-dim);
transition: color var(--transition);
}
.sidebar-section-header:hover .section-label {
color: var(--text-secondary);
}
.sidebar-section-actions {
display: flex;
align-items: center;
gap: 2px;
gap: 1px;
opacity: 0;
transition: opacity var(--transition);
transition: opacity 120ms ease;
}
.sidebar-section-header:hover .sidebar-section-actions {
@@ -426,15 +472,185 @@ input, select, textarea { font-family: inherit; color: inherit; }
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
color: var(--text-muted);
font-size: 14px;
transition: background var(--transition);
background: none;
border: none;
cursor: pointer;
transition: background var(--transition), color var(--transition);
}
.section-action-btn:hover {
background: var(--bg-tertiary);
color: var(--text);
}
/* Section menu (⋮) button */
.section-menu-btn {
font-size: 16px;
font-weight: 700;
letter-spacing: 1px;
opacity: 0.6;
}
.section-menu-btn:hover {
opacity: 1;
}
/* Section menu dropdown */
.section-menu-overlay {
position: fixed;
inset: 0;
z-index: 999;
}
.section-menu {
position: fixed;
z-index: 1000;
min-width: 200px;
background: var(--bg-modal);
border: 1px solid var(--border);
border-radius: 8px;
padding: 4px;
box-shadow: 0 8px 24px rgba(0,0,0,0.3), 0 2px 6px rgba(0,0,0,0.15);
}
.section-menu-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
border-radius: 5px;
cursor: pointer;
font-size: 13px;
color: var(--text);
transition: background 120ms;
}
.section-menu-item:hover {
background: var(--bg-hover);
}
.section-menu-item .smi-icon {
width: 18px;
text-align: center;
font-size: 14px;
flex-shrink: 0;
}
.section-menu-item .smi-label {
flex: 1;
}
.section-menu-item .smi-check {
color: var(--accent);
font-size: 14px;
}
.section-menu-sep {
height: 1px;
background: var(--border);
margin: 4px 8px;
}
.section-menu-customize {
border-top: 1px solid var(--border);
margin-top: 2px;
padding-top: 8px;
}
/* Customize Sidebar Panel */
.sidebar-customize-panel {
padding: 8px 12px;
}
.scp-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
padding: 4px 0;
}
.scp-title {
font-size: 14px;
font-weight: 600;
color: var(--text);
}
.scp-done {
font-size: 13px;
color: var(--accent);
background: none;
border: none;
cursor: pointer;
padding: 4px 12px;
border-radius: 6px;
transition: background 120ms;
font-weight: 500;
}
.scp-done:hover {
background: var(--bg-hover);
}
.scp-list {
display: flex;
flex-direction: column;
gap: 1px;
}
.scp-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 8px;
border-radius: 6px;
cursor: pointer;
transition: background 120ms;
}
.scp-item:hover {
background: var(--bg-hover);
}
.scp-item-left {
display: flex;
align-items: center;
gap: 8px;
}
.scp-item-icon {
font-size: 16px;
width: 22px;
text-align: center;
flex-shrink: 0;
}
.scp-item-name {
font-size: 13px;
color: var(--text);
}
.scp-item-eye {
font-size: 16px;
opacity: 0.7;
}
.scp-item-eye-off {
opacity: 0.3;
}
.customize-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.3);
z-index: 998;
}
/* x-cloak for Alpine.js */
[x-cloak] { display: none !important; }
/* Sidebar items (pages) */
.sidebar-items {
list-style: none;
@@ -2197,6 +2413,12 @@ button.breadcrumb-current { max-width: 260px; }
/* Toggle */
.block-toggle {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 2px;
}
.toggle-title-row {
display: flex;
align-items: flex-start;
gap: 4px;
@@ -2221,7 +2443,7 @@ button.breadcrumb-current { max-width: 260px; }
.toggle-chevron:hover {
background: var(--bg-hover);
}
.block-toggle div {
.block-toggle .toggle-title {
flex: 1;
outline: none;
font-size: 16px;
@@ -2289,18 +2511,216 @@ button.breadcrumb-current { max-width: 260px; }
padding: 14px 16px;
border-radius: 4px;
margin: 4px 0;
position: relative;
}
.block-callout .callout-icon {
font-size: 20px;
flex-shrink: 0;
cursor: pointer;
transition: transform .1s ease;
}
.block-callout div {
.block-callout .callout-icon:hover {
transform: scale(1.1);
}
.block-callout > div[data-bid] {
flex: 1;
outline: none;
font-size: 16px;
line-height: 1.6;
min-height: 24px;
}
.callout-icon-picker {
position: absolute;
top: calc(100% + 4px);
left: 12px;
z-index: 50;
display: flex;
flex-wrap: wrap;
gap: 2px;
width: 236px;
max-width: 90%;
padding: 8px;
background: var(--bg-modal);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: var(--shadow-modal);
}
.callout-icon-opt {
background: transparent;
border: none;
font-size: 18px;
width: 34px;
height: 34px;
border-radius: 5px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.callout-icon-opt:hover {
background: var(--bg-hover);
}
/* Toggle children */
.toggle-children {
margin-left: 22px;
padding-left: 12px;
border-left: 1px solid var(--border);
margin-top: 2px;
}
/* Table of Contents */
.block-toc {
border: 1px solid var(--border);
border-radius: 8px;
padding: 16px 20px;
margin: 4px 0;
}
.block-toc-title {
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .5px;
color: var(--text-dim);
margin-bottom: 10px;
}
.block-toc-item {
font-size: 14px;
color: var(--text-primary);
padding: 5px 8px;
border-radius: 4px;
cursor: pointer;
line-height: 1.4;
}
.block-toc-item:hover {
background: var(--bg-hover);
color: var(--accent);
}
.block-toc-empty {
color: var(--text-dim);
font-size: 14px;
font-style: italic;
padding: 12px 16px;
}
/* Math block */
.block-math {
margin: 8px 0;
}
.math-display {
min-height: 40px;
padding: 10px 14px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 6px;
overflow-x: auto;
font-size: 15px;
}
.math-editor {
width: 100%;
margin-top: 6px;
padding: 8px 10px;
background: var(--bg-tertiary);
border: 1px dashed var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: 'SF Mono', 'Fira Code', monospace;
font-size: 13px;
outline: none;
resize: vertical;
min-height: 40px;
box-sizing: border-box;
}
.math-editor:focus {
border-color: var(--accent);
}
/* Column list */
.block-columns {
margin: 8px 0 16px;
}
.columns-add-bar {
margin-bottom: 4px;
}
.columns-add-btn {
background: transparent;
border: 1px dashed var(--border);
color: var(--text-dim);
padding: 6px 14px;
border-radius: 6px;
font-size: 13px;
cursor: pointer;
transition: border-color .15s, color .15s;
}
.columns-add-btn:hover {
border-color: var(--accent);
color: var(--accent);
}
.columns-row {
display: flex;
gap: 12px;
align-items: stretch;
}
.column-cell {
flex: 1;
min-width: 0;
}
.block-column-wrapper {
position: relative;
padding: 10px 12px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
height: 100%;
box-sizing: border-box;
}
.block-column-wrapper:hover .block-handle {
opacity: 1;
}
.block-column-wrapper .block-actions {
right: -8px;
top: -8px;
}
.block-column-wrapper .block-add-btn {
background: var(--bg-modal);
border: 1px solid var(--border);
width: 20px;
height: 20px;
font-size: 13px;
border-radius: 50%;
line-height: 1;
}
.block-column {
outline: none;
min-height: 24px;
font-size: 15px;
line-height: 1.6;
color: var(--text-primary);
word-break: break-word;
}
.block-columns .block-wrapper {
margin: 0;
background: transparent;
}
.block-columns .block-handle {
opacity: 0;
}
.block-nested {
outline: none;
min-height: 24px;
font-size: 15px;
line-height: 1.6;
color: var(--text-primary);
word-break: break-word;
}
.nested-block {
margin: 2px 0;
}
.nested-block .block-handle {
display: none;
}
/* Image block */
.block-image-wrapper {
+1
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
File diff suppressed because one or more lines are too long