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 +17 -0
- package/README.md +7 -1
- package/assets/code-window/arrow.svg +6 -0
- package/assets/code-window/ktor.svg +11 -0
- package/components/DrawnAnnotation.vue +23 -6
- package/components/README.md +31 -0
- package/components/TypeHint.vue +5 -6
- package/package.json +1 -1
- package/setup/code-window-icon.ts +4 -0
- package/styles/layout.css +22 -0
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
|
-
|
|
1545
|
-
|
|
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
|
package/components/README.md
CHANGED
|
@@ -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
|
package/components/TypeHint.vue
CHANGED
|
@@ -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
|
-
//
|
|
32
|
-
//
|
|
33
|
-
// its
|
|
34
|
-
//
|
|
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: (
|
|
43
|
+
inlay: () => props.type ? `: ${props.type}` : highlightProps.message,
|
|
45
44
|
})
|
|
46
45
|
</script>
|
|
47
46
|
|
package/package.json
CHANGED
|
@@ -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);
|