forked from mirror/crumbs-original
Restore portal dropdown test IDs so the formatting e2e suite can find heading and link controls again. Let the mobile formatting toolbar pan horizontally, keep dropdown portals from drifting by closing them on scroll or resize, and use visualViewport height for keyboard-aware positioning. Remove the app-wide maximum-scale lock, keep editor focus targets at 16px on mobile to avoid input auto-zoom, and move toolbar scrollbar styling to a top-level scoped style block. Align the remove-link action with the destructive design token, use the standard 150ms editor slide-up animation, and replace save/restore body overflow locking with a resilient body class.
256 lines
5.3 KiB
CSS
256 lines
5.3 KiB
CSS
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
|
|
|
|
@import 'tailwindcss';
|
|
@plugin '@tailwindcss/typography';
|
|
|
|
:root {
|
|
--bg-base: #f0e6d3;
|
|
--bg-surface: #faf5eb;
|
|
--primary: #C8860A;
|
|
--primary-hover: #E8A020;
|
|
--text: #1a1a2e;
|
|
--text-muted: #6b6272;
|
|
--border: #1a1a2e;
|
|
--border-subtle: #d4cabb;
|
|
--destructive: #a63d2f;
|
|
--error-bg: #f5e0db;
|
|
--error-border: #d4a69e;
|
|
--error-text: #8b2e1f;
|
|
--success-bg: #dce8d4;
|
|
--success-text: #3a5a2e;
|
|
--card-shadow: 2px 2px 0px var(--border-subtle);
|
|
--card-shadow-hover: 3px 3px 0px var(--primary);
|
|
--grid-dot: #1a1a2e;
|
|
}
|
|
|
|
[data-theme="dark"] {
|
|
--bg-base: #1a1715;
|
|
--bg-surface: #2a2520;
|
|
--text: #e8dcc8;
|
|
--text-muted: #9a8e7e;
|
|
--border: #e8dcc8;
|
|
--border-subtle: #3a3530;
|
|
--destructive: #d4604e;
|
|
--error-bg: #3a2020;
|
|
--error-border: #5a3030;
|
|
--error-text: #e8a090;
|
|
--success-bg: #203020;
|
|
--success-text: #90c880;
|
|
--card-shadow: 2px 2px 0px var(--border-subtle);
|
|
--card-shadow-hover: 3px 3px 0px var(--primary);
|
|
--grid-dot: #e8dcc8;
|
|
}
|
|
|
|
html, body {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
accent-color: var(--primary);
|
|
overscroll-behavior-y: none;
|
|
}
|
|
|
|
body.editor-scroll-locked {
|
|
overflow: hidden;
|
|
}
|
|
|
|
body::before {
|
|
content: '';
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
opacity: 0.03;
|
|
background-image: repeating-conic-gradient(var(--grid-dot) 0% 25%, transparent 0% 50%);
|
|
background-size: 4px 4px;
|
|
z-index: 0;
|
|
}
|
|
|
|
/* Editor entrance animations */
|
|
@keyframes fade-in {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
@keyframes pop-in {
|
|
from { opacity: 0; transform: scale(0.95) translateY(8px); }
|
|
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
}
|
|
|
|
@keyframes slide-up {
|
|
from { transform: translateY(100%); }
|
|
to { transform: translateY(0); }
|
|
}
|
|
|
|
/* Prose overrides for parchment theme */
|
|
.prose {
|
|
--tw-prose-body: var(--text);
|
|
--tw-prose-headings: var(--text);
|
|
--tw-prose-links: var(--primary);
|
|
--tw-prose-code: var(--text);
|
|
--tw-prose-pre-bg: var(--bg-surface);
|
|
--tw-prose-pre-code: var(--text);
|
|
}
|
|
|
|
.prose :where(code):not(:where([class~="not-prose"] *)) {
|
|
background-color: var(--bg-surface);
|
|
border-radius: 2px;
|
|
padding: 0.125rem 0.25rem;
|
|
}
|
|
|
|
.prose :where(a):not(:where([class~="not-prose"] *)) {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.prose :where(a):not(:where([class~="not-prose"] *)):hover {
|
|
color: var(--primary-hover);
|
|
}
|
|
|
|
/* Table styles for TipTap editor */
|
|
.tiptap table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
.tiptap th,
|
|
.tiptap td {
|
|
border: 1px solid var(--border-subtle);
|
|
padding: 0.375rem 0.625rem;
|
|
text-align: left;
|
|
vertical-align: top;
|
|
min-width: 4rem;
|
|
}
|
|
|
|
.tiptap th {
|
|
font-weight: 600;
|
|
background-color: color-mix(in srgb, var(--bg-base) 60%, transparent);
|
|
}
|
|
|
|
.tiptap td p,
|
|
.tiptap th p {
|
|
margin: 0;
|
|
}
|
|
|
|
.tiptap .selectedCell {
|
|
background-color: color-mix(in srgb, var(--primary) 12%, transparent);
|
|
}
|
|
|
|
/* Task list styles — shared between TipTap editor and markdown-it preview */
|
|
|
|
/* TipTap: ul[data-type="taskList"] | markdown-it: ul.task-list */
|
|
.tiptap ul[data-type="taskList"],
|
|
.prose ul.task-list {
|
|
list-style: none;
|
|
padding-left: 0;
|
|
margin: 0.25rem 0;
|
|
}
|
|
|
|
.tiptap ul[data-type="taskList"] li,
|
|
.prose ul.task-list li {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
flex-wrap: wrap;
|
|
gap: 0.375rem;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Nested task lists take full width below the parent item */
|
|
.tiptap ul[data-type="taskList"] li > ul[data-type="taskList"],
|
|
.prose ul.task-list li > ul.task-list {
|
|
flex-basis: 100%;
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
.tiptap ul[data-type="taskList"] li::marker,
|
|
.prose ul.task-list li::marker {
|
|
content: none;
|
|
}
|
|
|
|
/* TipTap: checkbox is inside a label */
|
|
.tiptap ul[data-type="taskList"] li label {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
margin-top: 0.125rem;
|
|
}
|
|
|
|
/* Shared checkbox styles */
|
|
.tiptap ul[data-type="taskList"] li label input[type="checkbox"],
|
|
.prose ul.task-list .task-checkbox {
|
|
cursor: pointer;
|
|
margin: 0;
|
|
margin-top: 0.2em;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* TipTap: text content is in a div>p */
|
|
.tiptap ul[data-type="taskList"] li > div {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.tiptap ul[data-type="taskList"] li > div p {
|
|
margin: 0;
|
|
}
|
|
|
|
/* Checked item styling */
|
|
.tiptap ul[data-type="taskList"] li[data-checked="true"] > div {
|
|
text-decoration: line-through;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Override prose spacing for task lists */
|
|
.prose ul[data-type="taskList"],
|
|
.prose ul.task-list {
|
|
padding-left: 0;
|
|
margin-top: 0.25rem;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.prose ul[data-type="taskList"] li,
|
|
.prose ul.task-list li {
|
|
padding-left: 0;
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.prose ul.task-list li p {
|
|
margin: 0;
|
|
}
|
|
|
|
/* Checklist link styles */
|
|
.checklist-link {
|
|
color: var(--primary);
|
|
text-decoration: underline;
|
|
text-underline-offset: 2px;
|
|
}
|
|
|
|
.checklist-link:hover {
|
|
color: var(--primary-hover);
|
|
}
|
|
|
|
[data-placeholder]:empty::before {
|
|
content: attr(data-placeholder);
|
|
color: var(--text-muted);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Custom tooltips */
|
|
.tooltip-popup {
|
|
position: fixed;
|
|
z-index: 9999;
|
|
padding: 0.25rem 0.5rem;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 0.7rem;
|
|
line-height: 1.2;
|
|
color: var(--bg-surface);
|
|
background: var(--text);
|
|
border-radius: 2px;
|
|
pointer-events: none;
|
|
white-space: nowrap;
|
|
opacity: 0;
|
|
transition: opacity 100ms ease-out;
|
|
}
|
|
|
|
.tooltip-visible {
|
|
opacity: 1;
|
|
}
|