diff --git a/src/app.css b/src/app.css index d844ce3..c5169f6 100644 --- a/src/app.css +++ b/src/app.css @@ -560,715 +560,3 @@ a.hover-underline-animation:hover::after { .shaker:hover { animation: shaker 0.5s ease; } - -.prose { - --tw-prose-body: var(--color-text); - --tw-prose-headings: var(--color-text); - --tw-prose-lead: var(--color-text); - --tw-prose-links: var(--color-blue); - --tw-prose-bold: var(--color-text); - --tw-prose-counters: var(--color-subtext1); - --tw-prose-bullets: var(--color-subtext1); - --tw-prose-hr: var(--color-surface2); - --tw-prose-quotes: var(--color-text); - --tw-prose-quote-borders: var(--color-surface2); - --tw-prose-captions: var(--color-subtext1); - --tw-prose-code: var(--color-text); - --tw-prose-pre-code: var(--color-text); - --tw-prose-pre-bg: var(--color-surface0); - --tw-prose-th-borders: var(--color-surface2); - --tw-prose-td-borders: var(--color-surface1); -} - -.prose-invert { - --tw-prose-body: var(--color-text); - --tw-prose-headings: var(--color-text); - --tw-prose-lead: var(--color-text); - --tw-prose-links: var(--color-blue); - --tw-prose-bold: var(--color-text); - --tw-prose-counters: var(--color-subtext1); - --tw-prose-bullets: var(--color-subtext1); - --tw-prose-hr: var(--color-surface2); - --tw-prose-quotes: var(--color-text); - --tw-prose-quote-borders: var(--color-surface2); - --tw-prose-captions: var(--color-subtext1); - --tw-prose-code: var(--color-text); - --tw-prose-pre-code: var(--color-text); - --tw-prose-pre-bg: var(--color-surface0); - --tw-prose-th-borders: var(--color-surface2); - --tw-prose-td-borders: var(--color-surface1); -} -.code-block { - position: relative; - - select { - position: absolute; - right: 0.5rem; - top: 0.5rem; - } -} -.ProseMirror { - > * + * { - margin-top: 0.75em; - } - - ul, - ol { - padding: 0 1rem; - margin-left: 2rem; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - line-height: 1.1; - } - a { - color: #70cff8; - } - - img { - max-width: 100%; - height: auto; - } - - blockquote { - padding-left: 1rem; - border-left: 2px solid rgba(#0d0d0d, 0.1); - } - - hr { - border: none; - border-top: 2px solid var(--color-text); - margin: 2rem 0; - } - - pre { - background: #0d0d0d; - color: #fff; - font-family: "JetBrainsMono", monospace; - padding: 0.75rem 1rem; - border-radius: 0.5rem; - - code { - color: inherit; - padding: 0; - background: none; - font-size: 0.8rem; - } - - .hljs-comment, - .hljs-quote { - color: #616161; - } - - .hljs-variable, - .hljs-template-variable, - .hljs-attribute, - .hljs-tag, - .hljs-name, - .hljs-regexp, - .hljs-link, - .hljs-name, - .hljs-selector-id, - .hljs-selector-class { - color: #f98181; - } - - .hljs-number, - .hljs-meta, - .hljs-built_in, - .hljs-builtin-name, - .hljs-literal, - .hljs-type, - .hljs-params { - color: #fbbc88; - } - - .hljs-string, - .hljs-symbol, - .hljs-bullet { - color: #b9f18d; - } - - .hljs-title, - .hljs-section { - color: #faf594; - } - - .hljs-keyword, - .hljs-selector-tag { - color: #70cff8; - } - - .hljs-emphasis { - font-style: italic; - } - - .hljs-strong { - font-weight: 700; - } - } -} - -/* Table styles for TipTap editor */ -.tiptap-table { - border-collapse: collapse; - table-layout: fixed; - width: 100%; - max-width: 100%; - margin: 1rem 0; - overflow: auto; - display: block; -} - -.tiptap-table td, -.tiptap-table th { - min-width: 1em; - border: 2px solid var(--color-surface2); - padding: 0.5rem; - vertical-align: top; - box-sizing: border-box; - position: relative; -} - -.tiptap-table th { - font-weight: bold; - text-align: left; - background-color: var(--color-surface0); -} - -.tiptap-table .selectedCell { - background-color: var(--color-surface1); -} - -.tiptap-table p { - margin: 0; -} - -/* Additional table styles for ProseMirror */ -.ProseMirror table { - border-collapse: collapse; - table-layout: fixed; - width: 100%; - max-width: 100%; - margin: 1rem 0; - overflow: auto; - display: block; -} - -.ProseMirror table td, -.ProseMirror table th { - min-width: 3em; - border: 2px solid var(--color-text); - padding: 0.5rem; - vertical-align: top; - box-sizing: border-box; - position: relative; - background-color: var(--color-mantle); -} - -.ProseMirror table th { - font-weight: bold; - text-align: left; - background-color: var(--color-surface0); -} - -.ProseMirror table .selectedCell:after { - z-index: 2; - position: absolute; - content: ""; - left: 0; - right: 0; - top: 0; - bottom: 0; - background-color: var(--color-blue); - opacity: 0.2; - pointer-events: none; -} - -.ProseMirror table .column-resize-handle { - position: absolute; - right: -2px; - top: 0; - bottom: 0; - width: 4px; - z-index: 20; - background-color: var(--color-blue); - pointer-events: none; -} - -ul[data-type="taskList"] { - list-style: none; - padding: 0; - margin: 1rem 0; -} - -ul[data-type="taskList"] li { - display: flex; - align-items: center; - gap: 0.5rem; - line-height: 0; -} - -/* Collapsible section (details/summary) styles */ -details { - margin: 1.5rem 0; - padding: 1rem; - border: 1px solid var(--color-surface2); - border-radius: 0.5rem; - background-color: var(--color-surface0); -} - -summary { - cursor: pointer; - font-weight: 600; - user-select: none; - padding: 0.5rem; - margin: -1rem -1rem 0 -1rem; - background-color: var(--color-surface1); - border-radius: 0.5rem 0.5rem 0 0; - transition: background-color 0.2s; - list-style: none; -} - -summary::-webkit-details-marker { - display: none; -} - -summary::before { - content: "▶ "; - color: var(--color-blue); - display: inline-block; - transition: transform 0.2s; -} - -details[open] summary::before { - transform: rotate(90deg); - color: var(--color-green); -} - -summary:hover { - background-color: var(--color-surface2); -} - -details[open] summary { - margin-bottom: 1rem; - border-bottom: 1px solid var(--color-surface2); - border-radius: 0.5rem 0.5rem 0 0; -} - -/* Content inside details */ -details div[data-type="details-content"] { - padding: 0.5rem; -} - -/* Nested details */ -details details { - margin: 1rem 0; - border-color: var(--color-surface1); -} - -/* Animation */ -details[open] div[data-type="details-content"] { - animation: slideDown 0.2s ease-out; -} - -/* TipTap Details/Summary nodes - using data-type attributes */ -.ProseMirror [data-type="details"] { - margin: 1.5rem 0; - padding: 1rem; - border: 1px solid var(--color-surface2); - border-radius: 0.5rem; - background-color: var(--color-surface0); - position: relative; -} - -/* Hide the empty button that TipTap creates */ -.ProseMirror [data-type="details"] > button { - display: none; -} - -.ProseMirror [data-type="details"] summary { - cursor: pointer; - font-weight: 600; - user-select: none; - padding: 0.5rem; - margin: -1rem -1rem 0 -1rem; - background-color: var(--color-surface1); - border-radius: 0.5rem 0.5rem 0 0; - transition: background-color 0.2s; - list-style: none; -} - -.ProseMirror [data-type="details"] summary::-webkit-details-marker { - display: none; -} - -.ProseMirror [data-type="details"] summary::before { - content: "▶ "; - color: var(--color-blue); - display: inline-block; - transition: transform 0.2s; - margin-right: 0.25rem; -} - -.ProseMirror [data-type="details"][open] summary::before { - transform: rotate(90deg); - color: var(--color-green); -} - -.ProseMirror [data-type="details"] summary:hover { - background-color: var(--color-surface2); -} - -.ProseMirror [data-type="details"][open] summary { - margin-bottom: 1rem; - border-bottom: 1px solid var(--color-surface2); - border-radius: 0.5rem 0.5rem 0 0; -} - -.ProseMirror [data-type="detailsContent"] { - padding: 0.5rem; -} - -.ProseMirror [data-type="detailsContent"][hidden] { - display: none; -} - -.ProseMirror - [data-type="details"][open] - [data-type="detailsContent"]:not([hidden]) { - display: block; - animation: slideDown 0.2s ease-out; -} - -@keyframes slideDown { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Mermaid diagram styles */ -.mermaid-diagram, -pre[data-type="mermaid"] { - margin: 2rem 0; - padding: 1rem; - background-color: var(--color-surface0); - border-radius: 0.5rem; - border: 1px solid var(--color-surface2); - overflow: visible; -} - -.mermaid-diagram code, -pre[data-type="mermaid"] code { - display: block; - white-space: pre; - font-family: "JetBrainsMono", monospace; - color: var(--color-text); - background: transparent; -} - -/* Rendered mermaid SVG container */ -.mermaid-rendered { - display: flex; - justify-content: center; - align-items: center; - min-height: 100px; -} - -.mermaid-rendered svg { - max-width: 100%; - height: auto; -} - -/* Mermaid theme adjustments */ -.mermaid .node rect, -.mermaid .node circle, -.mermaid .node polygon, -.mermaid .node ellipse, -.mermaid .node path { - fill: var(--color-surface1) !important; - stroke: var(--color-blue) !important; - stroke-width: 2px; -} - -.mermaid .node .label, -.mermaid .nodeLabel { - color: var(--color-text) !important; - fill: var(--color-text) !important; -} - -.mermaid .edgePath .path, -.mermaid .flowchart-link { - stroke: var(--color-blue) !important; - stroke-width: 2px; -} - -.mermaid .edgeLabel, -.mermaid .edgeLabel rect { - background-color: var(--color-surface0) !important; - fill: var(--color-surface0) !important; -} - -.mermaid .edgeLabel span { - color: var(--color-text) !important; -} - -.mermaid .cluster rect { - fill: var(--color-surface0) !important; - stroke: var(--color-surface2) !important; -} - -.mermaid .cluster-label { - fill: var(--color-text) !important; -} - -/* Class diagram styles */ -.mermaid .classGroup rect, -.mermaid .classGroup line { - stroke: var(--color-blue) !important; - fill: var(--color-surface1) !important; -} - -.mermaid .classLabel { - fill: var(--color-text) !important; -} - -/* State diagram styles */ -.mermaid .statediagram-state rect { - fill: var(--color-surface1) !important; - stroke: var(--color-blue) !important; -} - -.mermaid .statediagram-state text { - fill: var(--color-text) !important; -} - -/* Sequence diagram styles */ -.mermaid .actor { - fill: var(--color-surface1) !important; - stroke: var(--color-blue) !important; -} - -.mermaid .actor text, -.mermaid .messageText { - fill: var(--color-text) !important; - stroke: none !important; -} - -.mermaid .activation0, -.mermaid .activation1, -.mermaid .activation2 { - fill: var(--color-surface2) !important; - stroke: var(--color-blue) !important; -} - -/* ER diagram styles */ -.mermaid .er.entityBox { - fill: var(--color-surface1) !important; - stroke: var(--color-blue) !important; -} - -.mermaid .er.entityLabel { - fill: var(--color-text) !important; -} - -.mermaid .er.relationshipLabel { - fill: var(--color-text) !important; -} - -/* Gantt chart styles */ -.mermaid .grid .tick line { - stroke: var(--color-surface2) !important; -} - -.mermaid .grid .tick text { - fill: var(--color-text) !important; -} - -.mermaid .task { - fill: var(--color-blue) !important; - stroke: var(--color-blue) !important; -} - -.mermaid .taskText { - fill: var(--color-text) !important; -} - -.mermaid .taskTextOutsideRight, -.mermaid .taskTextOutsideLeft { - fill: var(--color-text) !important; -} - -/* Pie chart styles */ -.mermaid .pieCircle { - stroke: var(--color-surface2) !important; -} - -.mermaid .pieTitleText { - fill: var(--color-text) !important; -} - -.mermaid .slice { - stroke-width: 2px; - stroke: var(--color-surface0) !important; -} - -.mermaid .legend rect { - fill: var(--color-blue) !important; - stroke: var(--color-blue) !important; -} - -/* Override all text elements in mermaid SVG for high contrast */ -.mermaid-rendered svg text, -.mermaid svg text, -svg.mermaid text { - fill: #ffffff !important; - color: #ffffff !important; - stroke: #000000 !important; - stroke-width: 0.25px !important; -} - -/* Ensure percentage labels in pie charts are visible */ -.mermaid text.slice, -.mermaid .slice { - fill: #ffffff !important; - font-weight: bold !important; - font-size: 14px !important; - stroke: #000000 !important; - stroke-width: 0.75px !important; - paint-order: stroke fill !important; -} - -/* Text alignment styles */ -.ProseMirror [style*="text-align: left"], -.ProseMirror p[style*="text-align: left"], -.ProseMirror h1[style*="text-align: left"], -.ProseMirror h2[style*="text-align: left"], -.ProseMirror h3[style*="text-align: left"], -.ProseMirror h4[style*="text-align: left"], -.ProseMirror h5[style*="text-align: left"], -.ProseMirror h6[style*="text-align: left"] { - text-align: left; -} - -.ProseMirror [style*="text-align: center"], -.ProseMirror p[style*="text-align: center"], -.ProseMirror h1[style*="text-align: center"], -.ProseMirror h2[style*="text-align: center"], -.ProseMirror h3[style*="text-align: center"], -.ProseMirror h4[style*="text-align: center"], -.ProseMirror h5[style*="text-align: center"], -.ProseMirror h6[style*="text-align: center"] { - text-align: center; -} - -.ProseMirror [style*="text-align: right"], -.ProseMirror p[style*="text-align: right"], -.ProseMirror h1[style*="text-align: right"], -.ProseMirror h2[style*="text-align: right"], -.ProseMirror h3[style*="text-align: right"], -.ProseMirror h4[style*="text-align: right"], -.ProseMirror h5[style*="text-align: right"], -.ProseMirror h6[style*="text-align: right"] { - text-align: right; -} - -.ProseMirror [style*="text-align: justify"], -.ProseMirror p[style*="text-align: justify"], -.ProseMirror h1[style*="text-align: justify"], -.ProseMirror h2[style*="text-align: justify"], -.ProseMirror h3[style*="text-align: justify"], -.ProseMirror h4[style*="text-align: justify"], -.ProseMirror h5[style*="text-align: justify"], -.ProseMirror h6[style*="text-align: justify"] { - text-align: justify; -} - -/* Image alignment */ -.ProseMirror img[style*="text-align: center"] { - display: block; - margin-left: auto; - margin-right: auto; -} - -.ProseMirror img[style*="text-align: right"] { - display: block; - margin-left: auto; -} - -.ProseMirror img[style*="text-align: left"] { - display: block; - margin-right: auto; -} -.reference-item > span.ml-2 { - font-style: italic; -} - -/* Conditional Block Styling in Editor */ -.ProseMirror .conditional-block { - border: 2px dashed rgba(69, 112, 122, 0.5); - border-radius: 4px; - padding: 12px; - margin: 8px 0; - position: relative; - background: rgba(69, 112, 122, 0.05); -} - -.ProseMirror .conditional-block::before { - content: "🔒 " attr(data-condition-type) ": " attr(data-condition-value); - position: absolute; - top: -12px; - left: 8px; - background: var(--color-blue); - color: var(--color-base); - padding: 2px 8px; - border-radius: 4px; - font-size: 11px; - font-weight: 600; - z-index: 1; -} - -.ProseMirror .conditional-block[data-show-when="false"]::before { - content: "🔒 NOT " attr(data-condition-type) ": " attr(data-condition-value); -} - -.ProseMirror .conditional-content { - position: relative; -} - -/* Inline conditional styling */ -.ProseMirror .conditional-inline { - display: inline; - background: rgba(69, 112, 122, 0.15); - border-bottom: 2px dotted rgba(69, 112, 122, 0.6); - padding: 2px 4px; - border-radius: 3px; - position: relative; - cursor: pointer; -} - -.ProseMirror .conditional-inline::after { - content: "🔒"; - font-size: 10px; - margin-left: 2px; - opacity: 0.7; -} - -.ProseMirror .conditional-inline[data-show-when="false"] { - background: rgba(193, 74, 74, 0.15); - border-bottom-color: rgba(193, 74, 74, 0.6); -} - -.ProseMirror .conditional-inline[data-show-when="false"]::after { - content: "🔒❌"; -} diff --git a/src/components/blog/TextEditor.tsx b/src/components/blog/TextEditor.tsx index e7feea2..3a23ad1 100644 --- a/src/components/blog/TextEditor.tsx +++ b/src/components/blog/TextEditor.tsx @@ -423,6 +423,18 @@ export default function TextEditor(props: TextEditorProps) { return alignment === "left"; }; + // Helper for mobile-optimized button classes + const getButtonClasses = ( + isActive: boolean, + includeHover: boolean = false + ) => { + const baseClasses = + "rounded px-2 py-1 text-xs select-none touch-manipulation active:scale-95 transition-transform"; + const activeClass = isActive ? "bg-surface2" : ""; + const hoverClass = includeHover && !isActive ? "hover:bg-surface1" : ""; + return `${baseClasses} ${activeClass} ${hoverClass}`.trim(); + }; + const editor = createTiptapEditor(() => ({ element: editorRef, extensions: [ @@ -1762,6 +1774,7 @@ export default function TextEditor(props: TextEditorProps) { {/* Main Toolbar - Pinned at top in fullscreen */}
instance().chain().focus().toggleBold().run()} - class={`${ - isActive("bold") && "bg-surface2" - } touch-manipulation rounded px-2 py-1 text-xs select-none`} + class={getButtonClasses(isActive("bold"))} title="Bold" > B @@ -1826,9 +1837,7 @@ export default function TextEditor(props: TextEditorProps) { onClick={() => instance().chain().focus().toggleItalic().run() } - class={`${ - isActive("italic") && "bg-surface2" - } touch-manipulation rounded px-2 py-1 text-xs select-none`} + class={getButtonClasses(isActive("italic"))} title="Italic" > I @@ -1838,9 +1847,7 @@ export default function TextEditor(props: TextEditorProps) { onClick={() => instance().chain().focus().toggleStrike().run() } - class={`${ - isActive("strike") && "bg-surface2" - } touch-manipulation rounded px-2 py-1 text-xs select-none`} + class={getButtonClasses(isActive("strike"))} title="Strikethrough" > S diff --git a/src/routes/blog/[title]/index.tsx b/src/routes/blog/[title]/index.tsx index b24acbe..fe98495 100644 --- a/src/routes/blog/[title]/index.tsx +++ b/src/routes/blog/[title]/index.tsx @@ -17,6 +17,7 @@ import PostBodyClient from "~/components/blog/PostBodyClient"; import type { Comment, CommentReaction, UserPublicData } from "~/types/comment"; import { TerminalSplash } from "~/components/TerminalSplash"; import { api } from "~/lib/api"; +import "../post.css"; const getPostByTitle = query( async ( diff --git a/src/routes/blog/create/index.tsx b/src/routes/blog/create/index.tsx index 0a9f44b..848c24b 100644 --- a/src/routes/blog/create/index.tsx +++ b/src/routes/blog/create/index.tsx @@ -4,6 +4,7 @@ import { Title, Meta } from "@solidjs/meta"; import { createAsync } from "@solidjs/router"; import { getRequestEvent } from "solid-js/web"; import PostForm from "~/components/blog/PostForm"; +import "../post.css"; const getAuthState = query(async () => { "use server"; diff --git a/src/routes/blog/edit/[id].tsx b/src/routes/blog/edit/[id].tsx index 995c8fb..f16bed0 100644 --- a/src/routes/blog/edit/[id].tsx +++ b/src/routes/blog/edit/[id].tsx @@ -4,6 +4,7 @@ import { Title, Meta } from "@solidjs/meta"; import { createAsync } from "@solidjs/router"; import { getRequestEvent } from "solid-js/web"; import PostForm from "~/components/blog/PostForm"; +import "../post.css"; const getPostForEdit = query(async (id: string) => { "use server"; diff --git a/src/routes/blog/post.css b/src/routes/blog/post.css new file mode 100644 index 0000000..383bc49 --- /dev/null +++ b/src/routes/blog/post.css @@ -0,0 +1,729 @@ +.prose { + --tw-prose-body: var(--color-text); + --tw-prose-headings: var(--color-text); + --tw-prose-lead: var(--color-text); + --tw-prose-links: var(--color-blue); + --tw-prose-bold: var(--color-text); + --tw-prose-counters: var(--color-subtext1); + --tw-prose-bullets: var(--color-subtext1); + --tw-prose-hr: var(--color-surface2); + --tw-prose-quotes: var(--color-text); + --tw-prose-quote-borders: var(--color-surface2); + --tw-prose-captions: var(--color-subtext1); + --tw-prose-code: var(--color-text); + --tw-prose-pre-code: var(--color-text); + --tw-prose-pre-bg: var(--color-surface0); + --tw-prose-th-borders: var(--color-surface2); + --tw-prose-td-borders: var(--color-surface1); +} + +.prose-invert { + --tw-prose-body: var(--color-text); + --tw-prose-headings: var(--color-text); + --tw-prose-lead: var(--color-text); + --tw-prose-links: var(--color-blue); + --tw-prose-bold: var(--color-text); + --tw-prose-counters: var(--color-subtext1); + --tw-prose-bullets: var(--color-subtext1); + --tw-prose-hr: var(--color-surface2); + --tw-prose-quotes: var(--color-text); + --tw-prose-quote-borders: var(--color-surface2); + --tw-prose-captions: var(--color-subtext1); + --tw-prose-code: var(--color-text); + --tw-prose-pre-code: var(--color-text); + --tw-prose-pre-bg: var(--color-surface0); + --tw-prose-th-borders: var(--color-surface2); + --tw-prose-td-borders: var(--color-surface1); +} +.code-block { + position: relative; + + select { + position: absolute; + right: 0.5rem; + top: 0.5rem; + } +} +.ProseMirror { + > * + * { + margin-top: 0.75em; + } + + ul, + ol { + padding: 0 1rem; + margin-left: 2rem; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + line-height: 1.1; + } + a { + color: #70cff8; + } + + img { + max-width: 100%; + height: auto; + } + + blockquote { + padding-left: 1rem; + border-left: 2px solid rgba(#0d0d0d, 0.1); + } + + hr { + border: none; + border-top: 2px solid var(--color-text); + margin: 2rem 0; + } + + pre { + background: #0d0d0d; + color: #fff; + font-family: "JetBrainsMono", monospace; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + + code { + color: inherit; + padding: 0; + background: none; + font-size: 0.8rem; + } + + .hljs-comment, + .hljs-quote { + color: #616161; + } + + .hljs-variable, + .hljs-template-variable, + .hljs-attribute, + .hljs-tag, + .hljs-name, + .hljs-regexp, + .hljs-link, + .hljs-name, + .hljs-selector-id, + .hljs-selector-class { + color: #f98181; + } + + .hljs-number, + .hljs-meta, + .hljs-built_in, + .hljs-builtin-name, + .hljs-literal, + .hljs-type, + .hljs-params { + color: #fbbc88; + } + + .hljs-string, + .hljs-symbol, + .hljs-bullet { + color: #b9f18d; + } + + .hljs-title, + .hljs-section { + color: #faf594; + } + + .hljs-keyword, + .hljs-selector-tag { + color: #70cff8; + } + + .hljs-emphasis { + font-style: italic; + } + + .hljs-strong { + font-weight: 700; + } + } +} + +/* Table styles for TipTap editor */ +.tiptap-table { + border-collapse: collapse; + table-layout: fixed; + width: 100%; + max-width: 100%; + margin: 1rem 0; + overflow: auto; + display: block; +} + +.tiptap-table td, +.tiptap-table th { + min-width: 1em; + border: 2px solid var(--color-surface2); + padding: 0.5rem; + vertical-align: top; + box-sizing: border-box; + position: relative; +} + +.tiptap-table th { + font-weight: bold; + text-align: left; + background-color: var(--color-surface0); +} + +.tiptap-table .selectedCell { + background-color: var(--color-surface1); +} + +.tiptap-table p { + margin: 0; +} + +/* Additional table styles for ProseMirror */ +.ProseMirror table { + border-collapse: collapse; + table-layout: fixed; + width: 100%; + max-width: 100%; + margin: 1rem 0; + overflow: auto; + display: block; +} + +.ProseMirror table td, +.ProseMirror table th { + min-width: 3em; + border: 2px solid var(--color-text); + padding: 0.5rem; + vertical-align: top; + box-sizing: border-box; + position: relative; + background-color: var(--color-mantle); +} + +.ProseMirror table th { + font-weight: bold; + text-align: left; + background-color: var(--color-surface0); +} + +.ProseMirror table .selectedCell:after { + z-index: 2; + position: absolute; + content: ""; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: var(--color-blue); + opacity: 0.2; + pointer-events: none; +} + +.ProseMirror table .column-resize-handle { + position: absolute; + right: -2px; + top: 0; + bottom: 0; + width: 4px; + z-index: 20; + background-color: var(--color-blue); + pointer-events: none; +} + +ul[data-type="taskList"] { + list-style: none; + padding: 0; + margin: 1rem 0; +} + +ul[data-type="taskList"] li { + display: flex; + align-items: center; + gap: 0.5rem; + line-height: 0; +} + +/* Collapsible section (details/summary) styles */ +details { + margin: 1.5rem 0; + padding: 1rem; + border: 1px solid var(--color-surface2); + border-radius: 0.5rem; + background-color: var(--color-surface0); +} + +summary { + cursor: pointer; + font-weight: 600; + user-select: none; + padding: 0.5rem; + margin: -1rem -1rem 0 -1rem; + background-color: var(--color-surface1); + border-radius: 0.5rem 0.5rem 0 0; + transition: background-color 0.2s; + list-style: none; +} + +summary::-webkit-details-marker { + display: none; +} + +summary::before { + content: "▶ "; + color: var(--color-blue); + display: inline-block; + transition: transform 0.2s; +} + +details[open] summary::before { + transform: rotate(90deg); + color: var(--color-green); +} + +summary:hover { + background-color: var(--color-surface2); +} + +details[open] summary { + margin-bottom: 1rem; + border-bottom: 1px solid var(--color-surface2); + border-radius: 0.5rem 0.5rem 0 0; +} + +/* Content inside details */ +details div[data-type="details-content"] { + padding: 0.5rem; +} + +/* Nested details */ +details details { + margin: 1rem 0; + border-color: var(--color-surface1); +} + +/* Animation */ +details[open] div[data-type="details-content"] { + animation: slideDown 0.2s ease-out; +} + +/* TipTap Details/Summary nodes - using data-type attributes */ +.ProseMirror [data-type="details"] { + margin: 1.5rem 0; + padding: 1rem; + border: 1px solid var(--color-surface2); + border-radius: 0.5rem; + background-color: var(--color-surface0); + position: relative; +} + +/* Hide the empty button that TipTap creates */ +.ProseMirror [data-type="details"] > button { + display: none; +} + +.ProseMirror [data-type="details"] summary { + cursor: pointer; + font-weight: 600; + user-select: none; + padding: 0.5rem; + margin: -1rem -1rem 0 -1rem; + background-color: var(--color-surface1); + border-radius: 0.5rem 0.5rem 0 0; + transition: background-color 0.2s; + list-style: none; +} + +.ProseMirror [data-type="details"] summary::-webkit-details-marker { + display: none; +} + +.ProseMirror [data-type="details"] summary::before { + content: "▶ "; + color: var(--color-blue); + display: inline-block; + transition: transform 0.2s; + margin-right: 0.25rem; +} + +.ProseMirror [data-type="details"][open] summary::before { + transform: rotate(90deg); + color: var(--color-green); +} + +.ProseMirror [data-type="details"] summary:hover { + background-color: var(--color-surface2); +} + +.ProseMirror [data-type="details"][open] summary { + margin-bottom: 1rem; + border-bottom: 1px solid var(--color-surface2); + border-radius: 0.5rem 0.5rem 0 0; +} + +.ProseMirror [data-type="detailsContent"] { + padding: 0.5rem; +} + +.ProseMirror [data-type="detailsContent"][hidden] { + display: none; +} + +.ProseMirror + [data-type="details"][open] + [data-type="detailsContent"]:not([hidden]) { + display: block; + animation: slideDown 0.2s ease-out; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Mermaid diagram styles */ +.mermaid-diagram, +pre[data-type="mermaid"] { + margin: 2rem 0; + padding: 1rem; + background-color: var(--color-surface0); + border-radius: 0.5rem; + border: 1px solid var(--color-surface2); + overflow: visible; +} + +.mermaid-diagram code, +pre[data-type="mermaid"] code { + display: block; + white-space: pre; + font-family: "JetBrainsMono", monospace; + color: var(--color-text); + background: transparent; +} + +/* Rendered mermaid SVG container */ +.mermaid-rendered { + display: flex; + justify-content: center; + align-items: center; + min-height: 100px; +} + +.mermaid-rendered svg { + max-width: 100%; + height: auto; +} + +/* Mermaid theme adjustments */ +.mermaid .node rect, +.mermaid .node circle, +.mermaid .node polygon, +.mermaid .node ellipse, +.mermaid .node path { + fill: var(--color-surface1) !important; + stroke: var(--color-blue) !important; + stroke-width: 2px; +} + +.mermaid .node .label, +.mermaid .nodeLabel { + color: var(--color-text) !important; + fill: var(--color-text) !important; +} + +.mermaid .edgePath .path, +.mermaid .flowchart-link { + stroke: var(--color-blue) !important; + stroke-width: 2px; +} + +.mermaid .edgeLabel, +.mermaid .edgeLabel rect { + background-color: var(--color-surface0) !important; + fill: var(--color-surface0) !important; +} + +.mermaid .edgeLabel span { + color: var(--color-text) !important; +} + +.mermaid .cluster rect { + fill: var(--color-surface0) !important; + stroke: var(--color-surface2) !important; +} + +.mermaid .cluster-label { + fill: var(--color-text) !important; +} + +/* Class diagram styles */ +.mermaid .classGroup rect, +.mermaid .classGroup line { + stroke: var(--color-blue) !important; + fill: var(--color-surface1) !important; +} + +.mermaid .classLabel { + fill: var(--color-text) !important; +} + +/* State diagram styles */ +.mermaid .statediagram-state rect { + fill: var(--color-surface1) !important; + stroke: var(--color-blue) !important; +} + +.mermaid .statediagram-state text { + fill: var(--color-text) !important; +} + +/* Sequence diagram styles */ +.mermaid .actor { + fill: var(--color-surface1) !important; + stroke: var(--color-blue) !important; +} + +.mermaid .actor text, +.mermaid .messageText { + fill: var(--color-text) !important; + stroke: none !important; +} + +.mermaid .activation0, +.mermaid .activation1, +.mermaid .activation2 { + fill: var(--color-surface2) !important; + stroke: var(--color-blue) !important; +} + +/* ER diagram styles */ +.mermaid .er.entityBox { + fill: var(--color-surface1) !important; + stroke: var(--color-blue) !important; +} + +.mermaid .er.entityLabel { + fill: var(--color-text) !important; +} + +.mermaid .er.relationshipLabel { + fill: var(--color-text) !important; +} + +/* Gantt chart styles */ +.mermaid .grid .tick line { + stroke: var(--color-surface2) !important; +} + +.mermaid .grid .tick text { + fill: var(--color-text) !important; +} + +.mermaid .task { + fill: var(--color-blue) !important; + stroke: var(--color-blue) !important; +} + +.mermaid .taskText { + fill: var(--color-text) !important; +} + +.mermaid .taskTextOutsideRight, +.mermaid .taskTextOutsideLeft { + fill: var(--color-text) !important; +} + +/* Pie chart styles */ +.mermaid .pieCircle { + stroke: var(--color-surface2) !important; +} + +.mermaid .pieTitleText { + fill: var(--color-text) !important; +} + +.mermaid .slice { + stroke-width: 2px; + stroke: var(--color-surface0) !important; +} + +.mermaid .legend rect { + fill: var(--color-blue) !important; + stroke: var(--color-blue) !important; +} + +/* Override all text elements in mermaid SVG for high contrast */ +.mermaid-rendered svg text, +.mermaid svg text, +svg.mermaid text { + fill: #ffffff !important; + color: #ffffff !important; + stroke: #000000 !important; + stroke-width: 0.25px !important; +} + +/* Ensure percentage labels in pie charts are visible */ +.mermaid text.slice, +.mermaid .slice { + fill: #ffffff !important; + font-weight: bold !important; + font-size: 14px !important; + stroke: #000000 !important; + stroke-width: 0.75px !important; + paint-order: stroke fill !important; +} + +/* Text alignment styles */ +.ProseMirror [style*="text-align: left"], +.ProseMirror p[style*="text-align: left"], +.ProseMirror h1[style*="text-align: left"], +.ProseMirror h2[style*="text-align: left"], +.ProseMirror h3[style*="text-align: left"], +.ProseMirror h4[style*="text-align: left"], +.ProseMirror h5[style*="text-align: left"], +.ProseMirror h6[style*="text-align: left"] { + text-align: left; +} + +.ProseMirror [style*="text-align: center"], +.ProseMirror p[style*="text-align: center"], +.ProseMirror h1[style*="text-align: center"], +.ProseMirror h2[style*="text-align: center"], +.ProseMirror h3[style*="text-align: center"], +.ProseMirror h4[style*="text-align: center"], +.ProseMirror h5[style*="text-align: center"], +.ProseMirror h6[style*="text-align: center"] { + text-align: center; +} + +.ProseMirror [style*="text-align: right"], +.ProseMirror p[style*="text-align: right"], +.ProseMirror h1[style*="text-align: right"], +.ProseMirror h2[style*="text-align: right"], +.ProseMirror h3[style*="text-align: right"], +.ProseMirror h4[style*="text-align: right"], +.ProseMirror h5[style*="text-align: right"], +.ProseMirror h6[style*="text-align: right"] { + text-align: right; +} + +.ProseMirror [style*="text-align: justify"], +.ProseMirror p[style*="text-align: justify"], +.ProseMirror h1[style*="text-align: justify"], +.ProseMirror h2[style*="text-align: justify"], +.ProseMirror h3[style*="text-align: justify"], +.ProseMirror h4[style*="text-align: justify"], +.ProseMirror h5[style*="text-align: justify"], +.ProseMirror h6[style*="text-align: justify"] { + text-align: justify; +} + +/* Image alignment */ +.ProseMirror img[style*="text-align: center"] { + display: block; + margin-left: auto; + margin-right: auto; +} + +.ProseMirror img[style*="text-align: right"] { + display: block; + margin-left: auto; +} + +.ProseMirror img[style*="text-align: left"] { + display: block; + margin-right: auto; +} +.reference-item > span.ml-2 { + font-style: italic; +} + +/* Conditional Block Styling in Editor */ +.ProseMirror .conditional-block { + border: 2px dashed rgba(69, 112, 122, 0.5); + border-radius: 4px; + padding: 12px; + margin: 8px 0; + position: relative; + background: rgba(69, 112, 122, 0.05); +} + +.ProseMirror .conditional-block::before { + content: "🔒 " attr(data-condition-type) ": " attr(data-condition-value); + position: absolute; + top: -12px; + left: 8px; + background: var(--color-blue); + color: var(--color-base); + padding: 2px 8px; + border-radius: 4px; + font-size: 11px; + font-weight: 600; + z-index: 1; +} + +.ProseMirror .conditional-block[data-show-when="false"]::before { + content: "🔒 NOT " attr(data-condition-type) ": " attr(data-condition-value); +} + +.ProseMirror .conditional-content { + position: relative; +} + +/* Inline conditional styling */ +.ProseMirror .conditional-inline { + display: inline; + background: rgba(69, 112, 122, 0.15); + border-bottom: 2px dotted rgba(69, 112, 122, 0.6); + padding: 2px 4px; + border-radius: 3px; + position: relative; + cursor: pointer; +} + +.ProseMirror .conditional-inline::after { + content: "🔒"; + font-size: 10px; + margin-left: 2px; + opacity: 0.7; +} + +.ProseMirror .conditional-inline[data-show-when="false"] { + background: rgba(193, 74, 74, 0.15); + border-bottom-color: rgba(193, 74, 74, 0.6); +} + +.ProseMirror .conditional-inline[data-show-when="false"]::after { + content: "🔒❌"; +} + +#main-toolbar button, +[role="button"] { + z-index: 150; + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; +} + +/* Prevent double-tap zoom on buttons */ +.touch-manipulation { + touch-action: manipulation; +} + +/* Ensure active states work properly on mobile */ +button:active, +[role="button"]:active { + opacity: 0.8; +}