Files
Momento/memento-note/lib/publish/shared-css.ts
Antigravity 96e7902f01
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m22s
CI / Deploy production (on server) (push) Has been skipped
feat: publication IA (magazine/brief/essay) + fixes critique
Publication IA:
- 4 templates (magazine, brief, essay, simple) avec CSS riche
- Rewrite IA (article/exercises/tutorial/reference/mixed)
- Modération avec timeout 12s + fallback safe
- Quotas publish_enhance par tier (basic=2, pro=15, business=100)
- Détection contenu stale (hash)
- Migration DB publishedContent/publishedTemplate/publishedSourceHash

Fixes:
- cheerio v1.2: Element -> AnyNode (domhandler), decodeEntities cast
- _isShared ajouté au type Note (champ virtuel serveur)
- callout colors PDF export: extraction fonction pure testable
- admin/published: guard note.userId null
- Cmd+S fonctionne en mode dialog (pas seulement fullPage)

i18n:
- 23 clés publish* traduites dans les 15 locales
- Extension Web Clipper: 13 locales mise à jour

Tests:
- callout-colors.test.ts (6 tests)
- note-visible-in-view.test.ts (5 tests)
- entitlements.test.ts + byok-entitlements.test.ts: mock usageLog + unstubAllEnvs
- 199/199 tests passent

Tracker: user-stories.md sync avec sprint-status.yaml
2026-06-28 07:32:57 +00:00

287 lines
8.1 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** CSS KaTeX commun aux pages publiées */
export const KATEX_PUBLISH_CSS = `
.r-math-display {
margin: 1.75em 0;
text-align: center;
overflow-x: auto;
overflow-y: hidden;
padding: 0.25em 0;
}
.r-math-inline { display: inline; }
.r-math-inline .katex { font-size: 1.05em; }
.r-math-fallback {
font-family: 'SF Mono', Menlo, monospace;
font-size: 0.9em;
opacity: 0.85;
}
.pub-rewrite-body .katex-display { margin: 0; }
.katex { font-size: 1.1em; }
.katex-display { margin: 0; overflow-x: auto; overflow-y: hidden; }
`
export const REWRITE_SHARED_CSS = `
${KATEX_PUBLISH_CSS}
/* ─── Résumé introductif ─────────────────────────────── */
.pub-rewrite-summary {
font-size: 1.2em;
line-height: 1.7;
font-style: italic;
color: var(--pub-summary-color, #444);
margin-bottom: 2em;
padding-bottom: 1.5em;
border-bottom: 2px solid var(--pub-accent, #A47148);
}
/* ─── Exercices ──────────────────────────────────────── */
.pub-rewrite-body .pub-exercise {
border: 2px solid var(--pub-exercise-border, #e0d4c3);
border-radius: 12px;
margin: 1.75em 0;
overflow: hidden;
}
.pub-rewrite-body .pub-exercise-header {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 18px;
background: var(--pub-exercise-header-bg, #f6f1ea);
border-bottom: 1px solid var(--pub-exercise-border, #e0d4c3);
}
.pub-rewrite-body .pub-exercise-num {
font-weight: 700;
font-size: 0.82em;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--pub-accent, #A47148);
}
.pub-rewrite-body .pub-exercise-meta {
margin-left: auto;
font-size: 0.82em;
font-weight: 600;
color: #666;
}
.pub-rewrite-body .pub-exercise-body {
padding: 16px 20px;
color: #1a1a1a;
background: #fff;
}
.pub-rewrite-body .pub-exercise-body p:first-child { margin-top: 0; }
.pub-rewrite-body .pub-exercise-body p:last-child { margin-bottom: 0; }
/* Corps réécrit : texte toujours sombre sur fond clair */
.pub-rewrite-body {
color: #1a1a1a;
}
.pub-rewrite-body p,
.pub-rewrite-body li,
.pub-rewrite-body td,
.pub-rewrite-body th {
color: inherit;
}
/* Solution collapsible */
.pub-rewrite-body .pub-solution {
border-top: 1px dashed var(--pub-exercise-border, #e0d4c3);
}
.pub-rewrite-body .pub-solution > summary {
list-style: none;
cursor: pointer;
padding: 10px 20px;
font-size: 0.85em;
font-weight: 600;
color: var(--pub-accent, #A47148);
user-select: none;
display: flex;
align-items: center;
gap: 6px;
}
.pub-rewrite-body .pub-solution > summary::before { content: '▶'; font-size: 10px; transition: transform 0.2s; }
.pub-rewrite-body .pub-solution[open] > summary::before { transform: rotate(90deg); }
.pub-rewrite-body .pub-solution-body {
padding: 14px 20px 18px;
background: var(--pub-solution-bg, rgba(164,113,72,0.04));
border-top: 1px solid var(--pub-exercise-border, #e0d4c3);
color: #1a1a1a;
}
/* ─── Étapes tutoriel ────────────────────────────────── */
.pub-rewrite-body .pub-step {
display: grid;
grid-template-columns: 36px 1fr;
gap: 14px;
align-items: start;
margin: 1.5em 0;
}
.pub-rewrite-body .pub-step-num {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--pub-accent, #A47148);
color: #fff;
font-weight: 700;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 2px;
}
.pub-rewrite-body .pub-step-body p:first-child { margin-top: 0; }
/* ─── Définitions / Concepts ─────────────────────────── */
.pub-rewrite-body .pub-definition {
margin: 1.5em 0;
border-radius: 10px;
overflow: hidden;
border: 1px solid var(--pub-definition-border, #ddd);
}
.pub-rewrite-body .pub-definition-term {
padding: 8px 16px;
background: var(--pub-accent, #A47148);
color: #fff;
font-weight: 700;
font-size: 0.88em;
letter-spacing: 0.04em;
}
.pub-rewrite-body .pub-definition-body {
padding: 12px 16px;
background: var(--pub-definition-bg, #fafaf8);
color: #1a1a1a;
}
.pub-rewrite-body .pub-definition-body p { margin: 0.4em 0; color: #1a1a1a; }
.pub-rewrite-body .pub-definition-body p:first-child { margin-top: 0; }
/* ─── Toggle / Collapsible ───────────────────────────── */
.pub-rewrite-body .pub-toggle {
border: 1px solid var(--pub-toggle-border, #e5e5e5);
border-radius: 10px;
margin: 1.2em 0;
overflow: hidden;
}
.pub-rewrite-body .pub-toggle > .pub-toggle-trigger {
list-style: none;
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
cursor: pointer;
font-weight: 600;
font-size: 0.92em;
background: var(--pub-toggle-header-bg, #f7f7f5);
user-select: none;
}
.pub-rewrite-body .pub-toggle > .pub-toggle-trigger::before {
content: '▶';
font-size: 10px;
color: var(--pub-accent, #A47148);
transition: transform 0.2s;
flex-shrink: 0;
}
.pub-rewrite-body .pub-toggle[open] > .pub-toggle-trigger::before { transform: rotate(90deg); }
.pub-rewrite-body .pub-toggle-body {
padding: 14px 18px;
border-top: 1px solid var(--pub-toggle-border, #e5e5e5);
color: #1a1a1a;
background: #fff;
}
.pub-rewrite-body .pub-toggle-body p:first-child { margin-top: 0; }
/* ─── Mise en avant ──────────────────────────────────── */
.pub-rewrite-body .pub-highlight {
margin: 1.5em 0;
padding: 16px 20px;
background: var(--pub-highlight-bg, #fffbf5);
border-left: 4px solid var(--pub-accent, #A47148);
border-radius: 0 10px 10px 0;
font-weight: 600;
color: #1a1a1a;
}
.pub-rewrite-body .pub-highlight p { margin: 0; color: #1a1a1a; }
/* ─── Callouts ───────────────────────────────────────── */
.pub-rewrite-body .pub-callout {
margin: 1.4em 0;
padding: 14px 18px 14px 52px;
border-radius: 10px;
position: relative;
font-size: 0.93em;
line-height: 1.65;
}
.pub-rewrite-body .pub-callout::before {
position: absolute;
left: 16px;
top: 14px;
font-size: 18px;
}
.pub-rewrite-body .pub-callout strong {
display: block;
font-weight: 700;
margin-bottom: 4px;
font-size: 0.9em;
letter-spacing: 0.04em;
text-transform: uppercase;
color: inherit;
}
.pub-rewrite-body .pub-callout p { margin: 0.3em 0; color: inherit; }
.pub-rewrite-body .pub-callout p:first-of-type { margin-top: 0; }
.pub-rewrite-body .pub-callout-info {
background: #eff6ff;
border: 1px solid #93c5fd;
color: #1e3a8a;
}
.pub-rewrite-body .pub-callout-info::before { content: ''; }
.pub-rewrite-body .pub-callout-tip {
background: #ecfdf5;
border: 1px solid #6ee7b7;
color: #065f46;
}
.pub-rewrite-body .pub-callout-tip::before { content: '💡'; }
.pub-rewrite-body .pub-callout-warning {
background: #fffbeb;
border: 1px solid #fbbf24;
color: #78350f;
}
.pub-rewrite-body .pub-callout-warning::before { content: '⚠️'; }
/* ─── Checklist ──────────────────────────────────────── */
.pub-rewrite-body .pub-checklist {
list-style: none;
padding: 0;
margin: 1em 0;
}
.pub-rewrite-body .pub-checklist li {
padding: 8px 12px 8px 36px;
position: relative;
border-radius: 6px;
margin: 4px 0;
background: var(--pub-checklist-bg, rgba(0,0,0,0.02));
color: #1a1a1a;
}
.pub-rewrite-body .pub-checklist li::before {
content: '✓';
position: absolute;
left: 10px;
top: 8px;
font-weight: 700;
color: var(--pub-accent, #A47148);
}
/* ─── Code ───────────────────────────────────────────── */
.pub-rewrite-body .pub-code {
margin: 1.5em 0;
border-radius: 10px;
overflow: hidden;
}
.pub-rewrite-body .pub-code code {
display: block;
padding: 20px 22px;
font-family: 'SF Mono', 'Fira Code', Menlo, Consolas, monospace;
font-size: 13.5px;
line-height: 1.65;
overflow-x: auto;
}
`