Browse Source

style(editor): align typography and tables with Nuxt UI prose theme

- Switch table from border-collapse to border-separate border-spacing-0
  with rounded corner cells (matching Nuxt UI prose table slots)
- Update headings (h1-h4) to Nuxt UI prose sizes, weights, margins
- Update paragraphs to leading-7 text-pretty with zero margin
- Update links to bordered style (border-b transparent→primary on hover)
- Update blockquotes to left border bar (border-s-4)
- Update callouts from background tint to left border bar in accent color
- Update inline code to bg-muted border-muted (Nuxt UI neutral variant)
- Update code blocks to bg-muted border-muted rounded-md my-5
- Update properties key to font-semibold text-primary (Nuxt UI Field style)
- Update properties value to text-muted
- Update demo app example containers to dark:bg-neutral-950/50
Zander Hawke 4 days ago
parent
commit
baf00eded8

+ 2 - 2
apps/dev/src/components/LiveExample.vue

@@ -26,7 +26,7 @@ const content = ref(props.content)
       <p v-if="description" class="text-sm text-muted mt-0.5">{{ description }}</p>
     </div>
 
-    <div class="rounded-lg border border-default bg-elevated overflow-hidden">
+    <div class="rounded-lg border border-default dark:bg-neutral-950/50 overflow-hidden">
       <div class="p-4">
         <EditorBlock
           v-model:content="content"
@@ -46,7 +46,7 @@ const content = ref(props.content)
           Source
         </summary>
         <pre
-          class="px-4 py-3 overflow-x-auto text-xs leading-relaxed font-mono bg-elevated/50 border-t border-default text-muted"
+          class="px-4 py-3 overflow-x-auto text-xs leading-relaxed font-mono dark:bg-neutral-950/50 border-t border-default text-muted"
         ><code>{{ template ?? content }}</code></pre>
       </details>
     </div>

+ 2 - 2
apps/dev/src/pages/editor-shell.vue

@@ -39,7 +39,7 @@ watch(content, (val) => {
             <kbd class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">Tab</kbd> / <kbd class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">Shift+Tab</kbd> to change depth.
           </p>
 
-          <div class="rounded-lg border border-default bg-elevated overflow-hidden">
+          <div class="rounded-lg border border-default dark:bg-neutral-950/50 overflow-hidden">
             <div class="p-4">
               <Editor
                 v-model:content="content"
@@ -56,7 +56,7 @@ watch(content, (val) => {
             The <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">v-model:content</code> binding updates with the full serialized markdown.
             Try splitting, merging, or reordering blocks above.
           </p>
-          <div class="rounded-lg border border-default bg-elevated overflow-hidden">
+          <div class="rounded-lg border border-default dark:bg-neutral-950/50 overflow-hidden">
             <pre class="p-4 overflow-x-auto text-xs leading-relaxed font-mono text-muted"><code>{{ serialized }}</code></pre>
           </div>
         </section>

+ 1 - 1
apps/dev/src/pages/index.vue

@@ -28,7 +28,7 @@ Try editing any of the examples on the left.
             The editor is a headless engine — each <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">Block</code> component manages a single paragraph with its own ProseMirror instance.
             Markdown syntax is rendered as rich decorations in live-preview mode: delimiters fade when blurred, syntax elements get contextual styling.
           </p>
-          <div class="rounded-lg border border-default bg-elevated p-4">
+          <div class="rounded-lg border border-default dark:bg-neutral-950/50 p-4">
             <EditorBlock
               v-model:content="example"
               :focused="true"

+ 1 - 1
apps/dev/src/pages/themes.vue

@@ -78,7 +78,7 @@ const isCustom = computed(() => currentTheme.value === "custom")
         <section class="space-y-4">
           <h2 class="text-lg font-semibold text-highlighted">Editor Preview</h2>
 
-          <div class="rounded-lg border border-default bg-elevated overflow-hidden">
+          <div class="rounded-lg border border-default dark:bg-neutral-950/50 overflow-hidden">
             <div class="p-4">
               <Editor
                 v-model:content="content"

+ 1 - 1
apps/dev/src/pages/toolbar.vue

@@ -29,7 +29,7 @@ const content =
             The Editor provides <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">handlers</code> and <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">selectionVersion</code> to the slot scope.
           </p>
 
-          <div class="flex flex-col gap-3 rounded-lg border border-default bg-elevated p-4">
+          <div class="flex flex-col gap-3 rounded-lg border border-default dark:bg-neutral-950/50 p-4">
             <Editor v-model:content="content" :focused="true" marker-mode="always-visible">
               <template #toolbar="{ handlers, selectionVersion }">
                 <EditorToolbar :handlers="handlers" :selection-version="selectionVersion" />

+ 56 - 31
packages/editor/src/assets/style.css

@@ -4,11 +4,11 @@
 /* ── Base Editor ─────────────────────────────────────────────────── */
 
 .ProseMirror {
-  @apply outline-none min-h-7 whitespace-pre-wrap break-words text-(--ui-text-main) leading-relaxed px-1;
+  @apply outline-none min-h-7 whitespace-pre-wrap break-words text-(--ui-text-main) leading-7 px-1;
 }
 
 .ProseMirror p {
-  @apply m-0;
+  @apply m-0 text-pretty;
 }
 
 /* ── Decorators (Markdown syntax) ────────────────────────────────── */
@@ -55,7 +55,7 @@
   @apply italic;
 }
 .md-code {
-  @apply font-mono bg-(--ui-bg-elevated) text-(--ui-text-highlight) px-1.5 py-0.5 rounded-md text-[0.85em] border border-(--ui-border) shadow-sm;
+  @apply font-mono font-medium bg-muted text-highlighted px-1.5 py-0.5 rounded-md text-sm border border-muted;
 }
 .md-strike {
   @apply line-through text-(--ui-text-muted);
@@ -64,7 +64,7 @@
   @apply bg-yellow-400/20 dark:bg-yellow-400/30 px-1 py-0.5 rounded-sm;
 }
 .md-link {
-  @apply text-(--ui-primary) underline underline-offset-4 decoration-(--ui-primary)/30 hover:decoration-(--ui-primary) transition-all duration-200 cursor-pointer;
+  @apply text-(--ui-primary) border-b border-transparent hover:border-(--ui-primary) font-medium rounded-xs cursor-pointer transition-colors;
 }
 
 /* ── Chips (Page Refs, Block Refs, Tags) ─────────────────────────── */
@@ -94,33 +94,33 @@
 /* ── Properties ──────────────────────────────────────────────────── */
 
 .md-property-key {
-  @apply text-(--ui-text-muted) font-medium text-[0.85em] uppercase tracking-wider;
+  @apply font-semibold text-(--ui-primary);
 }
 .md-property-delimiter {
-  @apply text-(--ui-border) mx-1.5 select-none;
+  @apply text-(--ui-border) mx-1 select-none;
 }
 .md-property-value {
-  @apply text-(--ui-text-main);
+  @apply text-(--ui-text-muted);
 }
 
 /* ── Headings ────────────────────────────────────────────────────── */
 
 .md-heading-content {
-  @apply text-(--ui-text-highlight) transition-colors duration-200;
+  @apply text-(--ui-text-highlight) font-bold transition-colors duration-200;
 }
 .md-heading-content[data-heading-level="1"] {
-  @apply text-3xl font-bold tracking-tight mt-4 mb-2;
+  @apply text-4xl mb-8;
 }
 .md-heading-content[data-heading-level="2"] {
-  @apply text-2xl font-semibold tracking-tight mt-3 mb-1;
+  @apply text-2xl mt-12 mb-6;
 }
 .md-heading-content[data-heading-level="3"] {
-  @apply text-xl font-medium mt-2;
+  @apply text-xl mt-8 mb-3;
 }
 .md-heading-content[data-heading-level="4"],
 .md-heading-content[data-heading-level="5"],
 .md-heading-content[data-heading-level="6"] {
-  @apply text-lg font-medium;
+  @apply text-lg mt-6 mb-2;
 }
 
 /* Keep the hash marks smaller and perfectly centered with the heading text */
@@ -171,36 +171,39 @@
 }
 
 /* ── Blockquote && Callouts ──────────────────────────────────────── */
+.md-blockquote {
+  @apply border-s-4 border-(--ui-border-accented) ps-4 italic my-5;
+}
+
+.md-callout {
+  @apply border-s-4 ps-4 my-5;
+}
+
 .md-blockquote .md-marker,
 .md-callout .md-marker {
   @apply text-(--ui-text-muted) opacity-40 font-mono text-[0.8em] px-1.5 py-px rounded-sm select-none;
 }
 
 [data-callout-type="NOTE"] {
-  @apply bg-blue-500/8 text-blue-600 dark:text-blue-400;
+  @apply border-blue-500/50 text-blue-600 dark:text-blue-400;
 }
 [data-callout-type="WARNING"] {
-  @apply bg-yellow-500/8 text-yellow-600 dark:text-yellow-400;
+  @apply border-yellow-500/50 text-yellow-600 dark:text-yellow-400;
 }
 [data-callout-type="TIP"] {
-  @apply bg-green-500/8 text-green-600 dark:text-green-400;
+  @apply border-green-500/50 text-green-600 dark:text-green-400;
 }
 [data-callout-type="DANGER"] {
-  @apply bg-red-500/8 text-red-600 dark:text-red-400;
+  @apply border-red-500/50 text-red-600 dark:text-red-400;
 }
 [data-callout-type="INFO"] {
-  @apply bg-(--ui-primary)/8 text-(--ui-primary);
+  @apply border-(--ui-primary)/50 text-(--ui-primary);
 }
 
 /* ── Code Blocks (CM6 Node View) ──────────────────────────────────── */
 
 .cm-code-block {
-  @apply my-2 rounded-lg overflow-hidden border border-(--ui-border) bg-(--ui-bg-elevated);
-  font-size: 0.875em;
-}
-
-.cm-code-block {
-  @apply my-2 rounded-lg overflow-hidden border border-(--ui-border) bg-(--ui-bg-elevated);
+  @apply my-5 rounded-md overflow-hidden border border-muted bg-muted;
   font-size: 0.875em;
 }
 
@@ -230,7 +233,7 @@
 }
 
 .cm-code-block .cm-content {
-  @apply px-4 py-3;
+  @apply px-4 py-3 whitespace-pre-wrap;
   caret-color: currentColor;
 }
 
@@ -396,25 +399,47 @@
 }
 
 .md-table-rendered table {
-  @apply w-full border-collapse text-sm;
+  @apply w-full border-separate border-spacing-0 text-sm rounded-md;
   table-layout: fixed;
 }
 
 .md-table-rendered th,
 .md-table-rendered td {
-  @apply border border-(--ui-border) px-3 py-2 text-left;
+  @apply py-3 px-4 text-left border-e border-b border-t border-(--ui-border);
+}
+
+.md-table-rendered th:first-child,
+.md-table-rendered td:first-child {
+  @apply border-s border-(--ui-border);
+}
+
+.md-table-rendered thead {
+  @apply bg-(--ui-bg-elevated);
 }
 
 .md-table-rendered th {
-  @apply bg-(--ui-bg-elevated) font-semibold;
+  @apply font-semibold;
 }
 
-.md-table-rendered tbody tr:nth-child(even) td {
-  @apply bg-(--ui-bg-elevated)/50;
+.md-table-rendered td {
+  @apply align-top;
 }
 
-.md-table-rendered tbody tr:hover td {
-  @apply bg-(--ui-bg-elevated)/80;
+/* Rounded corners on corner cells (matches Nuxt UI prose style) */
+.md-table-rendered thead tr:first-child th:first-child {
+  @apply rounded-tl-md;
+}
+
+.md-table-rendered thead tr:first-child th:last-child {
+  @apply rounded-tr-md;
+}
+
+.md-table-rendered tbody tr:last-child td:first-child {
+  @apply rounded-bl-md;
+}
+
+.md-table-rendered tbody tr:last-child td:last-child {
+  @apply rounded-br-md;
 }
 
 /* ── Inline Math ────────────────────────────────────────────────── */