@miragon/slidev-toolkit 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The Miragon-branded [Slidev](https://sli.dev) design system: a fixed brand theme, twelve layout archetypes, reusable components (`Card`, `CardGrid`, `StepList`, `Figure`, `SplitView`, `Agenda`), the animated `BrandMeshBackground`, and always-on progress chrome (a stepper bar and a chapter footer). One source of design truth, so a Miragon deck stays on-brand without hand-written HTML or CSS.
4
4
 
5
- > Building a **new** deck? The easiest path is the [template repository](https://github.com/Miragon/slidev-deck-template) ("Use this template") — it ships this toolkit together with a demo deck, authoring guidance, and CI. Use the npm package below when you want the brand in an **existing** or standalone Slidev project.
5
+ > Building a **new** deck? The easiest path is `npm create @miragon/slidev-deck@latest my-talk` (from the [template repository](https://github.com/Miragon/slidev-deck-template)) — it scaffolds this toolkit together with a demo deck, authoring guidance, and CI. Use the npm package below when you want the brand in an **existing** or standalone Slidev project.
6
6
 
7
7
  ## Install
8
8
 
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ withDefaults(
3
+ defineProps<{
4
+ padding?: 'compact' | 'standard' | 'generous'
5
+ height?: string
6
+ }>(),
7
+ { padding: 'standard' },
8
+ )
9
+ </script>
10
+
11
+ <template>
12
+ <div
13
+ class="mg-frame"
14
+ :class="`mg-frame--${padding}`"
15
+ :style="height ? { height } : undefined"
16
+ >
17
+ <slot />
18
+ </div>
19
+ </template>
20
+
21
+ <style scoped>
22
+ .mg-frame {
23
+ box-sizing: border-box;
24
+ background: var(--miragon-white);
25
+ border: 1px solid #e5e7eb;
26
+ border-radius: 1.1rem;
27
+ box-shadow: 0 8px 20px rgba(51, 93, 229, 0.08);
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ overflow: hidden;
32
+ }
33
+ .mg-frame--compact { padding: 0.75rem; }
34
+ .mg-frame--standard { padding: 1rem 1.25rem; }
35
+ .mg-frame--generous { padding: 1.75rem 2rem; }
36
+ </style>
package/layouts/bpmn.vue CHANGED
@@ -21,6 +21,7 @@
21
21
  * default — optional caption / explanatory line below the diagram
22
22
  */
23
23
  import { computed } from 'vue'
24
+ import DiagramFrame from '../components/DiagramFrame.vue'
24
25
 
25
26
  const props = withDefaults(
26
27
  defineProps<{
@@ -59,14 +60,14 @@ const diagramSrc = computed(() => withBase(props.diagram))
59
60
  <h2 v-if="title" class="bpmn-title">{{ title }}</h2>
60
61
  </header>
61
62
 
62
- <div class="bpmn-canvas">
63
+ <DiagramFrame class="bpmn-canvas" padding="compact">
63
64
  <BpmnTokenSimulation
64
65
  v-if="diagram"
65
66
  :bpmnFilePath="diagramSrc"
66
67
  width="100%"
67
68
  :height="height"
68
69
  />
69
- </div>
70
+ </DiagramFrame>
70
71
 
71
72
  <div v-if="$slots.default" class="bpmn-caption">
72
73
  <slot />
@@ -129,15 +130,7 @@ const diagramSrc = computed(() => withBase(props.diagram))
129
130
  .bpmn-canvas {
130
131
  flex: 1 1 auto;
131
132
  min-height: 0;
132
- background: var(--miragon-white);
133
- border: 1px solid #E5E7EB;
134
- border-radius: 1.1rem;
135
- padding: 0.75rem;
136
- box-shadow: 0 8px 20px rgba(51, 93, 229, 0.08);
137
- overflow: hidden;
138
- display: flex;
139
- align-items: center;
140
- justify-content: center;
133
+ width: 100%;
141
134
  }
142
135
 
143
136
  .bpmn-caption {
package/layouts/dmn.vue CHANGED
@@ -26,6 +26,7 @@
26
26
  * default — optional caption / explanatory line below the table
27
27
  */
28
28
  import { computed } from 'vue'
29
+ import DiagramFrame from '../components/DiagramFrame.vue'
29
30
 
30
31
  const props = withDefaults(
31
32
  defineProps<{
@@ -67,7 +68,7 @@ const diagramSrc = computed(() => withBase(props.diagram))
67
68
  <h2 v-if="title" class="dmn-title">{{ title }}</h2>
68
69
  </header>
69
70
 
70
- <div class="dmn-canvas">
71
+ <DiagramFrame class="dmn-canvas" padding="compact">
71
72
  <DmnTable
72
73
  v-if="diagram"
73
74
  :dmnFilePath="diagramSrc"
@@ -77,7 +78,7 @@ const diagramSrc = computed(() => withBase(props.diagram))
77
78
  :fontSize="fontSize"
78
79
  :showAnnotations="showAnnotations"
79
80
  />
80
- </div>
81
+ </DiagramFrame>
81
82
 
82
83
  <div v-if="$slots.default" class="dmn-caption">
83
84
  <slot />
@@ -140,19 +141,11 @@ const diagramSrc = computed(() => withBase(props.diagram))
140
141
  .dmn-canvas {
141
142
  flex: 1 1 auto;
142
143
  min-height: 0;
143
- background: var(--miragon-white);
144
- border: 1px solid #E5E7EB;
145
- border-radius: 1.1rem;
146
- padding: 0.75rem;
147
- box-shadow: 0 8px 20px rgba(51, 93, 229, 0.08);
148
- overflow: hidden;
149
- display: flex;
150
- align-items: center;
151
- justify-content: center;
144
+ width: 100%;
152
145
  }
153
146
  /* dmn-js ships its own decision-table CSS (imported by the addon). We keep that
154
- rendering intact and only frame it in the branded card above, exactly like the
155
- bpmn archetype frames bpmn-js. */
147
+ rendering intact and only frame it in the branded DiagramFrame card, exactly
148
+ like the bpmn archetype frames bpmn-js. */
156
149
 
157
150
  .dmn-caption {
158
151
  flex: 0 0 auto;
@@ -0,0 +1,131 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import DiagramFrame from '../components/DiagramFrame.vue'
4
+
5
+ const props = withDefaults(
6
+ defineProps<{
7
+ eyebrow?: string
8
+ accent?: 'blue' | 'green' | 'mixed'
9
+ diagram?: string
10
+ alt?: string
11
+ frontmatter?: Record<string, unknown>
12
+ }>(),
13
+ { accent: 'blue' },
14
+ )
15
+
16
+ const title = computed(() => props.frontmatter?.title as string | undefined)
17
+ const gradientVar = computed(() => `var(--miragon-gradient-${props.accent})`)
18
+ const accentVar = computed(() =>
19
+ props.accent === 'green' ? 'var(--miragon-green-deep)' : 'var(--miragon-blue)',
20
+ )
21
+
22
+ function withBase(path?: string) {
23
+ if (!path) return path
24
+ if (/^https?:\/\//.test(path)) return path
25
+ return import.meta.env.BASE_URL.replace(/\/$/, '') + '/' + path.replace(/^\//, '')
26
+ }
27
+ const imageSrc = computed(() => withBase(props.diagram))
28
+ </script>
29
+
30
+ <template>
31
+ <div class="excalidraw-layout" :style="{ '--ex-grad': gradientVar, '--ex-accent': accentVar }">
32
+ <div class="excalidraw-inner">
33
+ <header v-if="title || eyebrow" class="excalidraw-head">
34
+ <span class="excalidraw-bar" aria-hidden="true"></span>
35
+ <div v-if="eyebrow" class="excalidraw-eyebrow">{{ eyebrow }}</div>
36
+ <h2 v-if="title" class="excalidraw-title">{{ title }}</h2>
37
+ </header>
38
+
39
+ <DiagramFrame class="excalidraw-canvas" padding="generous">
40
+ <img v-if="imageSrc" :src="imageSrc" :alt="alt" class="excalidraw-img" />
41
+ </DiagramFrame>
42
+
43
+ <div v-if="$slots.default" class="excalidraw-caption">
44
+ <slot />
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </template>
49
+
50
+ <style scoped>
51
+ .excalidraw-layout {
52
+ position: relative;
53
+ width: 100%;
54
+ height: 100%;
55
+ overflow: hidden;
56
+ background: var(--miragon-gray-bg);
57
+ color: var(--miragon-text-primary);
58
+ display: flex;
59
+ align-items: stretch;
60
+ }
61
+
62
+ .excalidraw-inner {
63
+ position: relative;
64
+ z-index: 1;
65
+ width: 100%;
66
+ max-width: 78rem;
67
+ margin: 0 auto;
68
+ padding: 2.5rem 4rem;
69
+ display: flex;
70
+ flex-direction: column;
71
+ }
72
+
73
+ .excalidraw-head {
74
+ flex: 0 0 auto;
75
+ margin-bottom: 1.25rem;
76
+ }
77
+ .excalidraw-bar {
78
+ display: block;
79
+ width: 3.5rem;
80
+ height: 0.35rem;
81
+ border-radius: 999px;
82
+ background: var(--ex-grad);
83
+ margin-bottom: 0.9rem;
84
+ }
85
+ .excalidraw-eyebrow {
86
+ font-size: 0.9rem;
87
+ font-weight: 600;
88
+ letter-spacing: 0.18em;
89
+ text-transform: uppercase;
90
+ color: var(--ex-accent);
91
+ margin-bottom: 0.55rem;
92
+ }
93
+ .excalidraw-title {
94
+ font-size: clamp(1.7rem, 2.7vw, 2.2rem);
95
+ line-height: 1.15;
96
+ font-weight: 800;
97
+ letter-spacing: -0.02em;
98
+ margin: 0;
99
+ }
100
+
101
+ .excalidraw-canvas {
102
+ flex: 1 1 auto;
103
+ min-height: 0;
104
+ width: 100%;
105
+ }
106
+ .excalidraw-img {
107
+ max-width: 100%;
108
+ max-height: 100%;
109
+ height: auto;
110
+ }
111
+
112
+ .excalidraw-caption {
113
+ flex: 0 0 auto;
114
+ margin-top: 1rem;
115
+ font-size: 0.95rem;
116
+ color: var(--miragon-text-muted);
117
+ text-align: center;
118
+ }
119
+ .excalidraw-caption :deep(p) {
120
+ margin: 0;
121
+ line-height: 1.5;
122
+ }
123
+ .excalidraw-caption :deep(:not(pre) > code) {
124
+ font-family: var(--miragon-font-mono);
125
+ font-size: 0.9em;
126
+ background: var(--miragon-blue-light);
127
+ color: var(--miragon-blue-darker);
128
+ padding: 0.1em 0.4em;
129
+ border-radius: 0.35rem;
130
+ }
131
+ </style>
@@ -0,0 +1,130 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import DiagramFrame from '../components/DiagramFrame.vue'
4
+
5
+ const props = withDefaults(
6
+ defineProps<{
7
+ eyebrow?: string
8
+ accent?: 'blue' | 'green' | 'mixed'
9
+ frontmatter?: Record<string, unknown>
10
+ }>(),
11
+ { accent: 'blue' },
12
+ )
13
+
14
+ const title = computed(() => props.frontmatter?.title as string | undefined)
15
+ const gradientVar = computed(() => `var(--miragon-gradient-${props.accent})`)
16
+ const accentVar = computed(() =>
17
+ props.accent === 'green' ? 'var(--miragon-green-deep)' : 'var(--miragon-blue)',
18
+ )
19
+ </script>
20
+
21
+ <template>
22
+ <div class="mermaid-layout" :style="{ '--mm-grad': gradientVar, '--mm-accent': accentVar }">
23
+ <div class="mermaid-inner">
24
+ <header v-if="title || eyebrow" class="mermaid-head">
25
+ <span class="mermaid-bar" aria-hidden="true"></span>
26
+ <div v-if="eyebrow" class="mermaid-eyebrow">{{ eyebrow }}</div>
27
+ <h2 v-if="title" class="mermaid-title">{{ title }}</h2>
28
+ </header>
29
+
30
+ <DiagramFrame class="mermaid-canvas">
31
+ <slot />
32
+ </DiagramFrame>
33
+
34
+ <div v-if="$slots.caption" class="mermaid-caption">
35
+ <slot name="caption" />
36
+ </div>
37
+ </div>
38
+ </div>
39
+ </template>
40
+
41
+ <style scoped>
42
+ .mermaid-layout {
43
+ position: relative;
44
+ width: 100%;
45
+ height: 100%;
46
+ overflow: hidden;
47
+ background: var(--miragon-gray-bg);
48
+ color: var(--miragon-text-primary);
49
+ display: flex;
50
+ align-items: stretch;
51
+ }
52
+
53
+ .mermaid-inner {
54
+ position: relative;
55
+ z-index: 1;
56
+ width: 100%;
57
+ max-width: 78rem;
58
+ margin: 0 auto;
59
+ padding: 2.5rem 4rem;
60
+ display: flex;
61
+ flex-direction: column;
62
+ }
63
+
64
+ .mermaid-head {
65
+ flex: 0 0 auto;
66
+ margin-bottom: 1.25rem;
67
+ }
68
+ .mermaid-bar {
69
+ display: block;
70
+ width: 3.5rem;
71
+ height: 0.35rem;
72
+ border-radius: 999px;
73
+ background: var(--mm-grad);
74
+ margin-bottom: 0.9rem;
75
+ }
76
+ .mermaid-eyebrow {
77
+ font-size: 0.9rem;
78
+ font-weight: 600;
79
+ letter-spacing: 0.18em;
80
+ text-transform: uppercase;
81
+ color: var(--mm-accent);
82
+ margin-bottom: 0.55rem;
83
+ }
84
+ .mermaid-title {
85
+ font-size: clamp(1.7rem, 2.7vw, 2.2rem);
86
+ line-height: 1.15;
87
+ font-weight: 800;
88
+ letter-spacing: -0.02em;
89
+ margin: 0;
90
+ }
91
+
92
+ .mermaid-canvas {
93
+ flex: 1 1 auto;
94
+ min-height: 0;
95
+ width: 100%;
96
+ }
97
+ .mermaid-canvas :deep(.mermaid),
98
+ .mermaid-canvas :deep(.mermaid-svg-wrapper) {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ width: 100%;
103
+ height: 100%;
104
+ }
105
+ .mermaid-canvas :deep(svg) {
106
+ max-width: 100%;
107
+ max-height: 100%;
108
+ height: auto;
109
+ }
110
+
111
+ .mermaid-caption {
112
+ flex: 0 0 auto;
113
+ margin-top: 1rem;
114
+ font-size: 0.95rem;
115
+ color: var(--miragon-text-muted);
116
+ text-align: center;
117
+ }
118
+ .mermaid-caption :deep(p) {
119
+ margin: 0;
120
+ line-height: 1.5;
121
+ }
122
+ .mermaid-caption :deep(:not(pre) > code) {
123
+ font-family: var(--miragon-font-mono);
124
+ font-size: 0.9em;
125
+ background: var(--miragon-blue-light);
126
+ color: var(--miragon-blue-darker);
127
+ padding: 0.1em 0.4em;
128
+ border-radius: 0.35rem;
129
+ }
130
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miragon/slidev-toolkit",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Miragon Slidev toolkit: the brand theme, the layout archetypes, the reusable components (Card, CardGrid, StepList, Figure, SplitView) and the BrandMeshBackground animation. Single source of design truth, consumed by the reference deck in this repo.",
5
5
  "keywords": [
6
6
  "slidev-theme",
package/setup/mermaid.ts CHANGED
@@ -1,32 +1,25 @@
1
1
  import { defineMermaidSetup } from '@slidev/types'
2
2
 
3
- // Brand-styles every ```mermaid diagram with the Miragon palette and Geist, so
4
- // text-generated diagrams stay on-brand. Slidev collects setup/* from every root
5
- // (theme included), so shipping this in the theme package means every deck that
6
- // sets `theme: '@miragon/slidev-toolkit'` inherits it with zero config. A deck can
7
- // still override by adding its own setup/mermaid.ts, but never has to.
8
- // The hex values mirror the tokens in ../styles/theme.css; they live here (config),
9
- // never in slide markdown, so the "no hardcoded hex in markdown" rule stays intact.
10
- // Excalidraw remains the default for diagrams; Mermaid is for text-generated flows.
11
3
  export default defineMermaidSetup(() => ({
12
4
  theme: 'base',
13
5
  themeVariables: {
14
- // Nodes: light-blue fill, Miragon-blue border, black label text
15
- primaryColor: '#F0F4FF', // --miragon-blue-light
16
- primaryBorderColor: '#335DE5', // --miragon-blue
17
- primaryTextColor: '#000000', // --miragon-text-primary
6
+ primaryColor: '#F0F4FF',
7
+ primaryBorderColor: '#335DE5',
8
+ primaryTextColor: '#000000',
18
9
 
19
- // Edges and their labels
20
- lineColor: '#335DE5', // --miragon-blue
21
- edgeLabelBackground: '#F5F7FF', // --miragon-blue-soft
10
+ lineColor: '#335DE5',
11
+ edgeLabelBackground: '#F5F7FF',
22
12
 
23
- // Secondary / tertiary surfaces (sequence actor boxes, alt-blocks, notes)
24
- secondaryColor: '#F5F7FF', // --miragon-blue-soft
25
- secondaryBorderColor: '#2B4ACB', // --miragon-blue-mid
13
+ secondaryColor: '#F5F7FF',
14
+ secondaryBorderColor: '#2B4ACB',
26
15
  tertiaryColor: '#FFFFFF',
27
16
  tertiaryBorderColor: '#335DE5',
28
17
 
29
- // Typography: Geist, matching the theme's body font
30
18
  fontFamily: "'Geist', 'Inter', 'Helvetica Neue', Arial, sans-serif",
31
19
  },
20
+ themeCSS: `
21
+ .node rect, .node polygon, .cluster rect { rx: 8px; ry: 8px; }
22
+ rect.actor, .actor rect, rect.note, .note rect,
23
+ .classGroup rect, .stateGroup rect, .entityBox { rx: 8px; ry: 8px; }
24
+ `,
32
25
  }))