@tnotesjs/ui 0.3.3 → 0.4.1

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.
@@ -1,6 +1,15 @@
1
1
  export interface MindmapFenceOptions {
2
2
  title?: string
3
3
  initialExpandLevel?: number
4
+ /** Pane height in px (`h=480` in the fence info). */
5
+ height?: number
6
+ }
7
+
8
+ export const MINDMAP_MIN_HEIGHT = 200
9
+ export const MINDMAP_MAX_HEIGHT = 1600
10
+
11
+ export function clampMindmapHeight(value: number): number {
12
+ return Math.round(Math.min(MINDMAP_MAX_HEIGHT, Math.max(MINDMAP_MIN_HEIGHT, value)))
4
13
  }
5
14
 
6
15
  function cleanHeadingText(value: string): string {
@@ -10,7 +19,7 @@ function cleanHeadingText(value: string): string {
10
19
  .trim()
11
20
  }
12
21
 
13
- /** Parse the canonical `mindmap [title] 2` fence metadata. */
22
+ /** Parse the canonical `mindmap [title] 2 h=480` fence metadata. */
14
23
  export function parseMindmapFence(openLine: string): MindmapFenceOptions | null {
15
24
  const fenceBody = openLine.trim().replace(/^`+\s*/, '')
16
25
  const nameMatch = fenceBody.match(/^mindmap(?=\s|\[|$)/)
@@ -25,9 +34,15 @@ export function parseMindmapFence(openLine: string): MindmapFenceOptions | null
25
34
  `${rest.slice(0, titleMatch.index)} ${rest.slice((titleMatch.index ?? 0) + titleMatch[0].length)}`.trim()
26
35
  }
27
36
 
28
- if (rest && !/^\d+$/.test(rest)) return null
29
- if (rest) {
30
- options.initialExpandLevel = Math.max(1, Number(rest))
37
+ for (const token of rest.split(/\s+/).filter(Boolean)) {
38
+ const height = token.match(/^h=(\d+)$/)
39
+ if (height) {
40
+ options.height = clampMindmapHeight(Number(height[1]))
41
+ } else if (/^\d+$/.test(token) && options.initialExpandLevel === undefined) {
42
+ options.initialExpandLevel = Math.max(1, Number(token))
43
+ } else {
44
+ return null
45
+ }
31
46
  }
32
47
  return options
33
48
  }
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <div v-if="show" class="rightClickMenu" :style="{ left: x + 'px', top: y + 'px' }">
2
+ <div
3
+ v-if="show"
4
+ class="rightClickMenu"
5
+ :style="{ left: x + 'px', top: y + 'px' }"
6
+ @mousedown.stop
7
+ >
3
8
  <div v-if="showPin" class="menuItem" @click="handlePin">📌 Pin</div>
4
9
  <div class="menuItem" @click="(e) => handlePronounce(e, 'en-GB')">📢 Pronounce(英)</div>
5
10
  <div class="menuItem" @click="(e) => handlePronounce(e, 'en-US')">📢 Pronounce(美)</div>
@@ -61,12 +66,12 @@ const handleReset = () => {
61
66
  .rightClickMenu {
62
67
  position: fixed;
63
68
  z-index: 99999;
64
- background: #2c2c2c;
65
- border: 1px solid #444;
66
- border-radius: 6px;
67
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
69
+ background: var(--tn-c-bg-elv, var(--tn-c-bg));
70
+ border: 1px solid var(--tn-c-divider);
71
+ border-radius: 8px;
72
+ box-shadow: var(--tn-shadow-2);
68
73
  font-size: 13px;
69
- color: #eee;
74
+ color: var(--tn-c-text);
70
75
  cursor: pointer;
71
76
  user-select: none;
72
77
  }
@@ -75,7 +80,7 @@ const handleReset = () => {
75
80
  padding: 8px 16px;
76
81
 
77
82
  &:hover {
78
- background-color: #444;
83
+ background: var(--tn-c-hover);
79
84
  }
80
85
  }
81
86
  </style>
@@ -48,6 +48,7 @@ const sortedWords = computed(() => {
48
48
  if (!props.needSort) return unique
49
49
  return unique.sort((a, b) => a.toLowerCase().charCodeAt(0) - b.toLowerCase().charCodeAt(0))
50
50
  })
51
+ const islandWords = computed(() => encodeURIComponent(JSON.stringify(sortedWords.value)))
51
52
  const checkedStates = ref({})
52
53
 
53
54
  const updateCheckedState = (word, isChecked) => {
@@ -84,6 +85,7 @@ const cardX = ref(0)
84
85
  const cardY = ref(0)
85
86
  const cardContent = ref('')
86
87
  const wordCache = ref({})
88
+ const wordMarkdown = ref({})
87
89
 
88
90
  // 加载失败的词汇(也就是词库中不存在的词汇)
89
91
  const failedWords = ref({})
@@ -112,6 +114,66 @@ let currentWordForContextMenu = null
112
114
  // 防抖计时器
113
115
  let hoverTimer = null
114
116
 
117
+ function wordSlug(word) {
118
+ return encodeURIComponent(word.toLowerCase().replaceAll(/\s/g, '_'))
119
+ }
120
+
121
+ function wordGithubUrl(word) {
122
+ return `${props.wordsBaseUrl}${wordSlug(word)}.md`
123
+ }
124
+
125
+ async function ensureWord(word) {
126
+ if (wordCache.value[word]) return
127
+ const url = `${props.wordsRawBaseUrl}${wordSlug(word)}.md`
128
+ try {
129
+ const res = await fetch(url)
130
+ if (res.ok) {
131
+ const text = await res.text()
132
+ wordMarkdown.value[word] = text
133
+ wordCache.value[word] = marked.parse(text)
134
+ } else {
135
+ wordCache.value[word] = `<em>无法加载单词内容</em>`
136
+ failedWords.value[word] = true
137
+ }
138
+ } catch (err) {
139
+ console.error(err)
140
+ wordCache.value[word] = `<em>加载失败</em>`
141
+ failedWords.value[word] = true
142
+ }
143
+ }
144
+
145
+ const copiedCardId = ref(null)
146
+ let copiedTimer = null
147
+
148
+ async function copyCardMarkdown(card, event) {
149
+ event.stopPropagation()
150
+ const markdown = wordMarkdown.value[card.word]
151
+ if (!markdown) return
152
+ try {
153
+ await navigator.clipboard.writeText(markdown)
154
+ } catch {
155
+ const field = document.createElement('textarea')
156
+ field.value = markdown
157
+ field.setAttribute('readonly', '')
158
+ field.style.position = 'fixed'
159
+ field.style.left = '-9999px'
160
+ document.body.append(field)
161
+ field.select()
162
+ document.execCommand('copy')
163
+ field.remove()
164
+ }
165
+ copiedCardId.value = card.id
166
+ clearTimeout(copiedTimer)
167
+ copiedTimer = setTimeout(() => {
168
+ copiedCardId.value = null
169
+ }, 1500)
170
+ }
171
+
172
+ function openCardOnGithub(card, event) {
173
+ event.stopPropagation()
174
+ window.open(wordGithubUrl(card.word), '_blank', 'noopener')
175
+ }
176
+
115
177
  /**
116
178
  * 显示单词卡片
117
179
  */
@@ -128,29 +190,8 @@ const showWordCard = async (e, word) => {
128
190
  cardY.value = clientY + 10
129
191
  showCard.value = true
130
192
 
131
- if (wordCache.value[word]) {
132
- cardContent.value = wordCache.value[word]
133
- resolve()
134
- return
135
- }
136
-
137
- const url = `${props.wordsRawBaseUrl}${encodeURIComponent(
138
- word.toLowerCase().replaceAll(/\s/g, '_')
139
- )}.md`
140
- try {
141
- const res = await fetch(url)
142
- if (res.ok) {
143
- let text = await res.text()
144
- text = marked.parse(text)
145
- wordCache.value[word] = text
146
- cardContent.value = text
147
- } else {
148
- cardContent.value = `<em>无法加载单词内容</em>`
149
- }
150
- } catch (err) {
151
- console.error(err)
152
- cardContent.value = `<em>加载失败</em>`
153
- }
193
+ await ensureWord(word)
194
+ cardContent.value = wordCache.value[word] || `<em>加载失败</em>`
154
195
  resolve()
155
196
  }, 300)
156
197
  })
@@ -208,28 +249,8 @@ const preloadWords = async () => {
208
249
  for (let i = 0; i < wordsToPreload.length; i++) {
209
250
  const word = wordsToPreload[i]
210
251
 
211
- // 如果已经缓存过,跳过
212
252
  if (wordCache.value[word]) continue
213
-
214
- const url = `${props.wordsRawBaseUrl}${encodeURIComponent(
215
- word.toLowerCase().replaceAll(/\s/g, '_')
216
- )}.md`
217
- try {
218
- const res = await fetch(url)
219
- if (res.ok) {
220
- let text = await res.text()
221
- text = marked.parse(text)
222
- wordCache.value[word] = text
223
- console.log(`✅ 预加载完成: ${word}`)
224
- } else {
225
- wordCache.value[word] = `<em>无法加载单词内容</em>`
226
- failedWords.value[word] = true
227
- }
228
- } catch (err) {
229
- console.error(`❌ 加载失败: ${word}`, err)
230
- wordCache.value[word] = `<em>加载失败</em>`
231
- failedWords.value[word] = true
232
- }
253
+ await ensureWord(word)
233
254
 
234
255
  // 可选:加个延迟避免并发请求过多
235
256
  await new Promise((resolve) => setTimeout(resolve, 200))
@@ -446,6 +467,7 @@ onMounted(() => {
446
467
  */
447
468
  onUnmounted(() => {
448
469
  clearTimeout(hoverTimer)
470
+ clearTimeout(copiedTimer)
449
471
  if (typeof document !== 'undefined') {
450
472
  document.removeEventListener('mousemove', onDragging)
451
473
  document.removeEventListener('mouseup', stopDrag)
@@ -455,7 +477,12 @@ onUnmounted(() => {
455
477
  </script>
456
478
 
457
479
  <template>
458
- <div class="tn-word-list">
480
+ <div
481
+ class="tn-word-list"
482
+ data-tn-island="word-list"
483
+ :data-words="islandWords"
484
+ :data-need-sort="needSort ? 'true' : 'false'"
485
+ >
459
486
  <ol>
460
487
  <li
461
488
  v-for="(word, index) in sortedWords"
@@ -515,10 +542,60 @@ onUnmounted(() => {
515
542
  @mousedown="(e) => startDrag(card, e)"
516
543
  @click="bringToFront(card)"
517
544
  >
545
+ <div class="wordCardTools">
546
+ <button
547
+ type="button"
548
+ class="cardTool"
549
+ aria-label="在 GitHub 打开"
550
+ title="在 GitHub 打开"
551
+ @mousedown.stop
552
+ @click.stop="openCardOnGithub(card, $event)"
553
+ >
554
+ <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
555
+ <path
556
+ fill="currentColor"
557
+ d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8"
558
+ />
559
+ </svg>
560
+ </button>
561
+ <button
562
+ type="button"
563
+ class="cardTool"
564
+ :aria-label="copiedCardId === card.id ? '已复制' : '复制 Markdown'"
565
+ :title="copiedCardId === card.id ? '已复制' : '复制 Markdown'"
566
+ @mousedown.stop
567
+ @click.stop="copyCardMarkdown(card, $event)"
568
+ >
569
+ <svg
570
+ v-if="copiedCardId !== card.id"
571
+ viewBox="0 0 24 24"
572
+ width="16"
573
+ height="16"
574
+ aria-hidden="true"
575
+ >
576
+ <path
577
+ fill="none"
578
+ stroke="currentColor"
579
+ stroke-width="1.8"
580
+ d="M9 9h10v10H9zM5 15V5h10"
581
+ />
582
+ </svg>
583
+ <svg v-else viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
584
+ <path
585
+ fill="none"
586
+ stroke="currentColor"
587
+ stroke-width="1.8"
588
+ stroke-linecap="round"
589
+ stroke-linejoin="round"
590
+ d="m5 12 5 5L20 7"
591
+ />
592
+ </svg>
593
+ </button>
594
+ </div>
518
595
  <div class="wordCardContentWrapper">
519
596
  <div class="wordCardContent" v-html="card.content"></div>
520
597
  </div>
521
- <button class="closeBtn" @click.stop="removeCard(card.id)">✖</button>
598
+ <button class="closeBtn" @mousedown.stop @click.stop="removeCard(card.id)">✖</button>
522
599
  <div class="resizeHandle" @mousedown.stop="startResize(card, $event)"></div>
523
600
  </div>
524
601
  </template>
@@ -549,11 +626,41 @@ onUnmounted(() => {
549
626
 
550
627
  <style scoped lang="scss">
551
628
  .tn-word-list {
629
+ padding: 12px 16px;
630
+ border: 1px solid var(--tn-c-divider);
631
+ border-radius: 8px;
632
+
552
633
  // Checkbox 样式
553
634
  input[type='checkbox'] {
554
- margin: 8px;
555
- transform: scale(1.3);
635
+ appearance: none;
636
+ -webkit-appearance: none;
637
+ position: relative;
638
+ box-sizing: border-box;
639
+ flex: none;
640
+ width: 16px;
641
+ height: 16px;
642
+ margin: 0 8px;
643
+ border: 1px solid var(--tn-c-task-check-border);
644
+ border-radius: 4px;
645
+ background: var(--tn-c-task-check-bg);
556
646
  cursor: pointer;
647
+
648
+ &:checked {
649
+ border-color: var(--tn-c-task-check);
650
+ background: var(--tn-c-task-check);
651
+ }
652
+
653
+ &:checked::after {
654
+ content: '';
655
+ position: absolute;
656
+ left: 4.5px;
657
+ top: 1px;
658
+ width: 4px;
659
+ height: 9px;
660
+ border: solid #fff;
661
+ border-width: 0 2px 2px 0;
662
+ transform: rotate(45deg);
663
+ }
557
664
  }
558
665
 
559
666
  // 链接样式
@@ -577,8 +684,9 @@ onUnmounted(() => {
577
684
 
578
685
  // 单词列表样式
579
686
  ol {
580
- list-style-type: decimal;
581
- padding-left: 20px;
687
+ list-style: none;
688
+ margin: 0;
689
+ padding-left: 0;
582
690
 
583
691
  li {
584
692
  display: flex;
@@ -599,13 +707,12 @@ onUnmounted(() => {
599
707
  }
600
708
  }
601
709
 
602
- // 单词卡片样式(🌑 暗色悬浮卡片)
603
710
  .wordCard {
604
711
  position: fixed;
605
712
  z-index: 9999;
606
- background: #1e1e1e;
607
- border: 1px solid #333;
608
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
713
+ background: var(--tn-c-bg-elv, var(--tn-c-bg));
714
+ border: 1px solid var(--tn-c-divider);
715
+ box-shadow: var(--tn-shadow-2);
609
716
  padding: 12px 16px;
610
717
  max-width: 600px;
611
718
  min-width: 200px;
@@ -613,12 +720,11 @@ onUnmounted(() => {
613
720
  font-size: 14px;
614
721
  line-height: 1.4;
615
722
  border-radius: 8px;
616
- color: #eee;
723
+ color: var(--tn-c-text);
617
724
  pointer-events: auto;
618
- font-family: sans-serif;
725
+ font-family: var(--tn-font-sans, sans-serif);
619
726
  cursor: move;
620
727
 
621
- // 关闭按钮
622
728
  .closeBtn {
623
729
  position: absolute;
624
730
  right: 5px;
@@ -627,19 +733,49 @@ onUnmounted(() => {
627
733
  border: none;
628
734
  font-size: 16px;
629
735
  cursor: pointer;
630
- color: #ccc;
736
+ color: var(--tn-c-text-2);
631
737
 
632
738
  &:hover {
633
- color: white;
739
+ color: var(--tn-c-text);
634
740
  }
635
741
  }
636
742
  }
637
743
 
638
744
  // 卡片内容包裹器
745
+ .wordCardTools {
746
+ position: absolute;
747
+ top: 6px;
748
+ left: 8px;
749
+ z-index: 2;
750
+ display: flex;
751
+ gap: 2px;
752
+ }
753
+
754
+ .cardTool {
755
+ display: inline-flex;
756
+ align-items: center;
757
+ justify-content: center;
758
+ width: 24px;
759
+ height: 24px;
760
+ padding: 0;
761
+ border: 0;
762
+ border-radius: 4px;
763
+ background: transparent;
764
+ color: var(--tn-c-text-2);
765
+ cursor: pointer;
766
+
767
+ &:hover {
768
+ background: var(--tn-c-hover);
769
+ color: var(--tn-c-text);
770
+ }
771
+ }
772
+
639
773
  .wordCardContentWrapper {
640
774
  width: 100%;
641
775
  height: 100%;
642
776
  overflow: auto;
777
+ box-sizing: border-box;
778
+ padding-top: 22px;
643
779
  }
644
780
 
645
781
  // 卡片内容样式
@@ -657,13 +793,13 @@ onUnmounted(() => {
657
793
  bottom: 0;
658
794
  width: 12px;
659
795
  height: 12px;
660
- background-color: #666;
796
+ background-color: var(--tn-c-text-2);
661
797
  cursor: nwse-resize;
662
798
  z-index: 2;
663
799
  border-radius: 50%;
664
800
 
665
801
  &:hover {
666
- background-color: #aaa;
802
+ background-color: var(--tn-c-text);
667
803
  }
668
804
  }
669
805
  </style>
@@ -105,12 +105,13 @@ defineExpose({ state, errorReason })
105
105
  align-items: center;
106
106
  justify-content: center;
107
107
  overflow: hidden;
108
- border-radius: 8px;
108
+ border-radius: 4px;
109
109
  background: var(--tn-excalidraw-bg, transparent);
110
110
  }
111
111
  .tn-excalidraw-view__image {
112
112
  max-width: 100%;
113
113
  max-height: 100%;
114
+ border-radius: 4px;
114
115
  object-fit: contain;
115
116
  }
116
117
  .tn-excalidraw-view__placeholder {
package/src/index.ts CHANGED
@@ -11,7 +11,13 @@ export {
11
11
  resolveWordListFeatures
12
12
  } from './components/WordList/wordListFeatures'
13
13
  export type { WordListFeatures } from './components/WordList/wordListFeatures'
14
- export { normalizeMindmapMarkdown, parseMindmapFence } from './components/Mindmap/markdown'
14
+ export {
15
+ clampMindmapHeight,
16
+ MINDMAP_MAX_HEIGHT,
17
+ MINDMAP_MIN_HEIGHT,
18
+ normalizeMindmapMarkdown,
19
+ parseMindmapFence
20
+ } from './components/Mindmap/markdown'
15
21
  export type { MindmapFenceOptions, NormalizeMindmapOptions } from './components/Mindmap/markdown'
16
22
  export type { NotesTableRow } from './components/NotesTable/types'
17
23
  export {
@@ -159,7 +159,7 @@ html[data-theme='dark'] .tn-code-highlight span:not(.line) {
159
159
  }
160
160
  .tn-code-group {
161
161
  position: relative;
162
- margin: 1rem 0;
162
+ margin: 0;
163
163
  }
164
164
  .tn-code-group__tabs {
165
165
  position: absolute;
@@ -47,15 +47,15 @@
47
47
  line-height: var(--tn-heading-6-line);
48
48
  }
49
49
  :is(.tn-prose, .vp-doc) :where(a) {
50
- color: var(--tn-c-brand);
50
+ color: var(--tn-c-link);
51
51
  text-decoration: none;
52
- font-weight: 500;
52
+ font-weight: 400;
53
53
  overflow-wrap: anywhere;
54
54
  word-break: break-word;
55
55
  }
56
56
  :is(.tn-prose, .vp-doc) :where(a:hover) {
57
- color: var(--tn-c-brand-hover);
58
- text-decoration: underline;
57
+ color: var(--tn-c-link);
58
+ text-decoration: none;
59
59
  }
60
60
  :is(.tn-prose, .vp-doc) :where(ul, ol) {
61
61
  padding-left: 1.5rem;
@@ -106,11 +106,21 @@
106
106
  background-size: 12px 12px;
107
107
  }
108
108
  :is(.tn-prose, .vp-doc) :where(:not(pre) > code) {
109
- color: var(--tn-c-brand);
110
- background: var(--tn-c-default-soft);
109
+ color: inherit;
110
+ background: var(--tn-c-inline-code-bg);
111
+ border: 1px solid var(--tn-c-inline-code-border);
111
112
  border-radius: 4px;
112
- font: 0.875em var(--tn-font-mono);
113
- padding: 3px 6px;
113
+ margin: 1px 3px;
114
+ padding: 0 4px;
115
+ font-family: var(--tn-font-mono);
116
+ font-size: 1em;
117
+ font-weight: 400;
118
+ }
119
+ :is(.tn-prose, .vp-doc) :where(mark) {
120
+ color: inherit;
121
+ background: var(--tn-c-mark-bg);
122
+ border-radius: 2px;
123
+ padding: 0 2px;
114
124
  }
115
125
  :is(.tn-prose, .vp-doc) :where(blockquote) {
116
126
  margin: 16px 0;
@@ -155,6 +165,13 @@
155
165
  max-width: 100%;
156
166
  height: auto;
157
167
  }
168
+ /* 笔记里的图片默认 4px 圆角。Desk 和静态站共用;按钮里的图标保持直角。 */
169
+ :is(.tn-prose, .vp-doc, .live-editor) :where(img) {
170
+ border-radius: 4px;
171
+ }
172
+ :is(.tn-prose, .vp-doc, .live-editor) button img {
173
+ border-radius: 0;
174
+ }
158
175
  :is(.tn-prose, .vp-doc) :where(figure.tn-image) {
159
176
  display: block;
160
177
  width: fit-content;
@@ -174,6 +191,14 @@
174
191
  width: 100%;
175
192
  height: auto;
176
193
  }
194
+
195
+ /* 正文图片边界。Desk 可视化图和静态站图共用;Swiper 的边画在 .tn-swiper 上。 */
196
+ :is(.tn-prose, .vp-doc) :where(figure.tn-image > img),
197
+ .cm-lp-image-frame > img,
198
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block img) {
199
+ border: 1px solid var(--tn-c-media-edge);
200
+ border-radius: 4px;
201
+ }
177
202
  :is(.tn-prose, .vp-doc) :where(figure.tn-image > figcaption),
178
203
  :is(.tn-prose, .vp-doc) :where(figcaption) {
179
204
  display: block;
@@ -185,7 +210,7 @@
185
210
  }
186
211
 
187
212
  /* Callouts — same soft-tint cards as Desk visual (no left accent bar). */
188
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block) {
213
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block) {
189
214
  box-sizing: border-box;
190
215
  margin: 16px 0;
191
216
  padding: 12px 16px;
@@ -195,37 +220,37 @@
195
220
  font-size: inherit;
196
221
  line-height: 1.5;
197
222
  }
198
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block.tip) {
223
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block.tip) {
199
224
  background-color: var(--tn-c-highlight);
200
225
  }
201
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block.info),
202
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block.note),
203
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block.details) {
226
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block.info),
227
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block.note),
228
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block.details) {
204
229
  background-color: var(--tn-c-hover);
205
230
  }
206
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block.warning) {
231
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block.warning) {
207
232
  background-color: var(--tn-c-warning-soft);
208
233
  }
209
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block.danger) {
234
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block.danger) {
210
235
  background-color: var(--tn-c-danger-soft);
211
236
  }
212
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block-title) {
237
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block-title) {
213
238
  margin: 0 0 2px;
214
239
  font-size: inherit;
215
240
  font-weight: 600;
216
241
  line-height: 1.5;
217
242
  color: var(--tn-c-text);
218
243
  }
219
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block > p:not(.tn-custom-block-title)) {
244
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block > p:not(.tn-custom-block-title)) {
220
245
  margin: 0;
221
246
  padding: 4px 0;
222
247
  font-size: 1em;
223
248
  line-height: 1.5;
224
249
  }
225
- :is(.tn-prose, .vp-doc) :where(.tn-custom-block > :last-child) {
250
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(.tn-custom-block > :last-child) {
226
251
  margin-bottom: 0;
227
252
  }
228
- :is(.tn-prose, .vp-doc) :where(details.tn-custom-block > summary) {
253
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(details.tn-custom-block > summary) {
229
254
  display: flex;
230
255
  align-items: center;
231
256
  gap: 8px;
@@ -236,13 +261,14 @@
236
261
  font-weight: 600;
237
262
  line-height: 1.5;
238
263
  }
239
- :is(.tn-prose, .vp-doc) :where(details.tn-custom-block:not([open]) > summary) {
264
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(details.tn-custom-block:not([open]) > summary) {
240
265
  margin-bottom: 0;
241
266
  }
242
- :is(.tn-prose, .vp-doc) :where(details.tn-custom-block > summary::-webkit-details-marker) {
267
+ :is(.tn-prose, .vp-doc, .cm-lp-card)
268
+ :where(details.tn-custom-block > summary::-webkit-details-marker) {
243
269
  display: none;
244
270
  }
245
- :is(.tn-prose, .vp-doc) :where(details.tn-custom-block > summary::before) {
271
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(details.tn-custom-block > summary::before) {
246
272
  content: '';
247
273
  flex: none;
248
274
  box-sizing: border-box;
@@ -256,7 +282,7 @@
256
282
  transform-origin: 50% 50%;
257
283
  transition: transform 120ms ease;
258
284
  }
259
- :is(.tn-prose, .vp-doc) :where(details.tn-custom-block[open] > summary::before) {
285
+ :is(.tn-prose, .vp-doc, .cm-lp-card) :where(details.tn-custom-block[open] > summary::before) {
260
286
  margin-top: -0.05em;
261
287
  transform: rotate(45deg);
262
288
  }