slidev-theme-kotlin 0.13.1 → 0.13.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ### Added
6
+
7
+ - An `arrow` modifier on a Kotlin fence, `` ```kotlin arrow ``, marks the code window with the [Arrow](https://arrow-kt.io) brand icon and outlines it in Arrow blue (`--code-window-arrow-color`, light `#2455cf`, dark `#497bf7`), next to the existing `gradle`, `jdbc`, and `r2dbc` modifiers. It is for slides whose Kotlin is really about `Raise`, `Resource`, `SuspendApp`, or another Arrow library; plain Kotlin keeps the Kotlin mark.
8
+ - A `ktor` modifier, `` ```kotlin ktor ``, marks the code window with the Ktor icon and outlines it in Ktor purple (`--code-window-ktor-color`, light `#7f52ff`, dark `#a578ff`), for Ktor routing, plugin, and client code.
9
+
10
+ ### Changed
11
+
12
+ - `TypeHint` draws its `this: …` and `context(…)` pill as an inlay attached to the matched token even when the `{` ends its line, instead of a floating message. A floating message hides while Magic Move runs; the inlay travels with its token and stays visible through the transition. The pill still pushes trailing code to the right as it did.
13
+
14
+ ### Fixed
15
+
16
+ - Explicit `:connect="true"` creates an editable connector from matched text even with no label, target, or saved geometry. Empty labels are supported too.
17
+
18
+ - `DrawnAnnotation` renders and edits an explicit `geometry.connector` without a `label` or `target`, including curved lines and arrowheads.
19
+
3
20
  ## 0.13.1
4
21
 
5
22
  ### Added
package/README.md CHANGED
@@ -117,7 +117,11 @@ SELECT * FROM presentations;
117
117
  ````
118
118
 
119
119
  `kotlin`, `kt`, and `kts` use the Kotlin icon; each with a `gradle`, `jdbc`,
120
- or `r2dbc` modifier uses the Gradle, JDBC, or R2DBC identity respectively.
120
+ or `r2dbc` modifier uses the Gradle, JDBC, or R2DBC identity respectively, and
121
+ with an `arrow` modifier the [Arrow](https://arrow-kt.io) icon, for Kotlin
122
+ code that is really about `Raise`, `Resource`, or another Arrow library.
123
+ Use `kotlin ktor` (also `kt ktor` or `kts ktor`) for the Ktor icon and purple
124
+ border on Ktor code. These modifiers also work with Magic Move.
121
125
  `yaml toolchain`, `java`, `bash`, `xml maven`, and `sql` use the Amper, Java,
122
126
  Terminal, Maven, and PostgreSQL icons respectively. All other fences remain plain
123
127
  code surfaces.
@@ -153,6 +157,8 @@ value:
153
157
  --code-window-kotlin-color: #834df0;
154
158
  --code-window-gradle-color: #6c707e;
155
159
  --code-window-amper-color: #087cfa;
160
+ --code-window-arrow-color: #2455cf;
161
+ --code-window-ktor-color: #7f52ff;
156
162
  --code-window-java-color: #e66d17;
157
163
  --code-window-terminal-color: #6c707e;
158
164
  --code-window-maven-color: #3574f0;
@@ -0,0 +1,6 @@
1
+ <svg width="40" height="41" viewBox="0 0 40 41" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M0 41L20 0V30L0 41Z" fill="#2455CF"/>
3
+ <path d="M40 41L20 0V30L40 41Z" fill="#497BF7"/>
4
+ <path d="M20 37L13.9766 33.3086L20 30L26 33.2969L20 37Z" fill="#E88D15"/>
5
+ <path d="M26 33.2969L20 37V30L26 33.2969Z" fill="#FAA73A"/>
6
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M47.9995 31.9981L31.9975 48.0001L0 15.996L16.002 0L47.9995 31.9981Z" fill="url(#paint0_linear_1328_4995)"/>
3
+ <path d="M32.0103 15.9961H16.0083V31.9981H32.0103V15.9961Z" fill="black"/>
4
+ <defs>
5
+ <linearGradient id="paint0_linear_1328_4995" x1="5.51834" y1="21.4563" x2="26.1201" y2="42.1597" gradientUnits="userSpaceOnUse">
6
+ <stop stop-color="#7F52FF"/>
7
+ <stop offset="0.506725" stop-color="#C711E1"/>
8
+ <stop offset="1" stop-color="#FF6D3F"/>
9
+ </linearGradient>
10
+ </defs>
11
+ </svg>
@@ -390,7 +390,7 @@ const transitionInkIdentity = computed(() => JSON.stringify([
390
390
  ]))
391
391
  // A source-only mark exposes no visual-editor operation. It remains valid:
392
392
  // only labels and connectors have geometry that an editor can manipulate.
393
- const editorRelevant = computed(() => hasLabel.value || (connect.value && hasTarget.value))
393
+ const editorRelevant = computed(() => hasLabel.value || (connect.value && (hasTarget.value || props.connect === true || !!manualConnector())))
394
394
 
395
395
  if (props.on !== undefined && (props.at !== undefined || props.until !== undefined))
396
396
  warn('`on` is `at` and `until` in one, so the separate `at` / `until` given here are ignored. Use either `on` alone, or `at` and `until`.')
@@ -592,7 +592,7 @@ const LABEL_HEAD_START = 0.1
592
592
  const LABEL_FADE_DURATION = 250
593
593
 
594
594
  // Whether a leader line is drawn at all: it needs somewhere to go.
595
- const connectsLine = computed(() => connect.value && (hasTarget.value || hasLabel.value))
595
+ const connectsLine = computed(() => connect.value && (hasTarget.value || hasLabel.value || props.connect === true || !!manualConnector()))
596
596
  const hasTargetStage = computed(() => hasTarget.value && targetMarkType.value !== 'none')
597
597
 
598
598
  // A label that waits for a click of its own starts writing straight away. One
@@ -1289,7 +1289,10 @@ function measureGeometry(root: HTMLElement, overlayBox: DOMRect, width: number,
1289
1289
  ? Array.from(match.range.getClientRects()).filter(rect => rect.width > 0.5 && rect.height > 0.5)
1290
1290
  : source
1291
1291
  ? [source.getBoundingClientRect()]
1292
- : []
1292
+ // A geometry-only line needs a canvas, but no source element to mark.
1293
+ : sourceMarkType.value === 'none' && !props.text && props.selector === '[data-annotate]' && manualConnector()
1294
+ ? [root.getBoundingClientRect()]
1295
+ : []
1293
1296
 
1294
1297
  if (!rects.length) {
1295
1298
  // The text is not on the slide right now — a Magic Move step that does not
@@ -1541,10 +1544,22 @@ function paintDestinationInto(
1541
1544
  placedLabelRegistry.delete(placementToken)
1542
1545
  }
1543
1546
 
1544
- if (!destination || !connect.value)
1545
- return
1546
-
1547
+ // Explicitly enabling a connector also works without a label or target.
1548
+ // Seed a short route from the mark; dragging materializes its endpoints in
1549
+ // geometry.connector through the same editor path as labelled connectors.
1547
1550
  const savedConnector = manualConnector()
1551
+ if (!destination && !savedConnector && props.connect === true) {
1552
+ const slide = slideRoot()
1553
+ const bounds = toLocal(slide ? slideRect(slide) : root.getBoundingClientRect())
1554
+ const distance = Math.max(28, props.gap * 2)
1555
+ const x = clamp(markBox.cx + (markBox.cx < bounds.cx ? distance : -distance), bounds.left + 8, bounds.right - 8)
1556
+ const y = markBox.cy < bounds.cy
1557
+ ? Math.min(markBox.bottom + distance, bounds.bottom - 8)
1558
+ : Math.max(markBox.top - distance, bounds.top + 8)
1559
+ destination = makeBox(x, y, x, y)
1560
+ }
1561
+ if (!connect.value || (!destination && !savedConnector))
1562
+ return
1548
1563
  let start: Point
1549
1564
  let end: Point
1550
1565
  let c2x: number
@@ -1575,6 +1590,8 @@ function paintDestinationInto(
1575
1590
  }
1576
1591
  }
1577
1592
  else {
1593
+ if (!destination)
1594
+ return
1578
1595
  const route = routeLeader(markBox, destination, endPoint)
1579
1596
  if (!route)
1580
1597
  return
@@ -109,6 +109,37 @@ Mono stack instead of the label's sans face:
109
109
  </DrawnAnnotation>
110
110
  ```
111
111
 
112
+ ## Connectors without labels
113
+
114
+ To start a connector at matched text without a label, explicitly enable it:
115
+
116
+ ```vue
117
+ <DrawnAnnotation text="body" :connect="true" />
118
+ ```
119
+
120
+ Place the annotation before the content containing `body`, or wrap that
121
+ content in its default slot. An omitted or empty `label` works. The line starts
122
+ with a short automatic route from the matched text; drag its handles in the
123
+ visual editor to position it and save `geometry.connector`. Plain text marks
124
+ without an explicit `:connect="true"` keep their mark-only behavior.
125
+
126
+ Omit `label` and supply `geometry.connector` to draw a connector with fixed
127
+ endpoints, without a target element. Coordinates are fractions of the slide's
128
+ width and height. Use `type="none"` to hide the source mark and `:connect="true"`
129
+ to enable the line even when the deck disables connectors by default.
130
+
131
+ ```vue
132
+ <DrawnAnnotation
133
+ type="none"
134
+ :connect="true"
135
+ :geometry="{ connector: { start: { x: 0.3, y: 0.4 }, end: { x: 0.7, y: 0.6 } } }"
136
+ />
137
+ ```
138
+
139
+ An optional `control: { x, y }` inside `connector` curves the line. These
140
+ connectors support the same click timing and visual-editor handles as labelled
141
+ connectors. To connect to an element instead, use `target` without `label`.
142
+
112
143
  ## Where the label goes
113
144
 
114
145
  A label is placed out of the slide's normal flow. Automatic placement is
@@ -28,11 +28,10 @@ if (import.meta.env.MODE === 'development' && !props.receiver && !props.context
28
28
  if (import.meta.env.MODE === 'development' && props.type && !props.text)
29
29
  console.warn('[TypeHint] A `type` hint needs `text`: the name it follows, such as `text="customer"`.')
30
30
 
31
- // The same exact-text match and message placement as `SmartCast` and
32
- // `Warning`, with nothing painted: the hint sits after the `{` that ends
33
- // its line. When more code follows the brace, it is drawn inside the line
34
- // instead, right after the match, as is a `type` hint (the `.type-hint-inlay`
35
- // rule below), so the rest of the line moves right as it does in the IDE.
31
+ // Use token-attached inlays even when the opening brace ends the line.
32
+ // Floating messages are hidden during Magic Move, while an inlay travels
33
+ // with its token and stays visible throughout the transition. When code
34
+ // follows the match, the inlay also pushes it right as it does in the IDE.
36
35
  const highlightProps = reactive({
37
36
  ...toRefs(props),
38
37
  text: computed(() => props.text ?? (props.type ? undefined : '{')),
@@ -41,7 +40,7 @@ const highlightProps = reactive({
41
40
  const { message, messageShown, messageStyle, inlaid } = useCodeHighlight(highlightProps, container, {
42
41
  component: 'TypeHint',
43
42
  highlightClass: props.type ? 'type-hint-inlay' : 'type-hint-lambda',
44
- inlay: ({ endsLine }) => props.type ? `: ${props.type}` : endsLine ? undefined : highlightProps.message,
43
+ inlay: () => props.type ? `: ${props.type}` : highlightProps.message,
45
44
  })
46
45
  </script>
47
46
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidev-theme-kotlin",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./annotation-editor": {
@@ -11,6 +11,10 @@ export function codeWindowIcon(language: string, meta = ''): string | undefined
11
11
  return 'amper'
12
12
  if (language === 'xml' && modifier === 'maven')
13
13
  return 'maven'
14
+ if (['kotlin', 'kt', 'kts'].includes(language) && modifier === 'ktor')
15
+ return 'ktor'
16
+ if (['kotlin', 'kt', 'kts'].includes(language) && modifier === 'arrow')
17
+ return 'arrow'
14
18
  if (['kotlin', 'kt', 'kts'].includes(language))
15
19
  return 'kotlin'
16
20
  if (language === 'java')
package/styles/layout.css CHANGED
@@ -12,6 +12,8 @@
12
12
  --code-window-r2dbc-color: #06b6d4;
13
13
  --code-window-gradle-color: #6c707e;
14
14
  --code-window-amper-color: #087cfa;
15
+ --code-window-arrow-color: #2455cf;
16
+ --code-window-ktor-color: #7f52ff;
15
17
  --code-window-java-color: #e66d17;
16
18
  --code-window-terminal-color: #6c707e;
17
19
  --code-window-maven-color: #3574f0;
@@ -57,6 +59,8 @@ html.dark {
57
59
  --code-window-r2dbc-color: #06b6d4;
58
60
  --code-window-gradle-color: #ced0d6;
59
61
  --code-window-amper-color: #087cfa;
62
+ --code-window-arrow-color: #497bf7;
63
+ --code-window-ktor-color: #a578ff;
60
64
  --code-window-java-color: #c77d55;
61
65
  --code-window-terminal-color: #ced0d6;
62
66
  --code-window-maven-color: #548af7;
@@ -143,6 +147,20 @@ html.dark {
143
147
  --code-window-border: var(--code-window-amper-color);
144
148
  }
145
149
 
150
+ /* `kotlin arrow`: Kotlin code that is really about an Arrow library. The mark
151
+ is Arrow's brand icon and the outline its blue; the same icon serves both
152
+ colour schemes. */
153
+ .slidev-code-wrapper:is(.code-window-icon--arrow, :has(code.code-window-icon--arrow)) {
154
+ --code-window-icon: url('../assets/code-window/arrow.svg');
155
+ --code-window-border: var(--code-window-arrow-color);
156
+ }
157
+
158
+ /* `kotlin ktor`: Ktor's primary icon and purple identity border. */
159
+ .slidev-code-wrapper:is(.code-window-icon--ktor, :has(code.code-window-icon--ktor)) {
160
+ --code-window-icon: url('../assets/code-window/ktor.svg');
161
+ --code-window-border: var(--code-window-ktor-color);
162
+ }
163
+
146
164
  .slidev-code-wrapper:is(.code-window-icon--java, :has(code.code-window-icon--java)) {
147
165
  --code-window-icon: url('../assets/code-window/java.svg');
148
166
  --code-window-border: var(--code-window-java-color);
@@ -233,6 +251,10 @@ html.dark .slidev-code-wrapper:is(.code-window-icon--amper, :has(code.code-windo
233
251
  --code-window-border: var(--code-window-amper-color);
234
252
  }
235
253
 
254
+ html.dark .slidev-code-wrapper:is(.code-window-icon--arrow, :has(code.code-window-icon--arrow)) {
255
+ --code-window-border: var(--code-window-arrow-color);
256
+ }
257
+
236
258
  html.dark .slidev-code-wrapper:is(.code-window-icon--java, :has(code.code-window-icon--java)) {
237
259
  --code-window-icon: url('../assets/code-window/java_dark.svg');
238
260
  --code-window-border: var(--code-window-java-color);