@hanology/cham-browser 0.4.31 → 0.4.33

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanology/cham-browser",
3
- "version": "0.4.31",
3
+ "version": "0.4.33",
4
4
  "description": "CHAM — browser-compatible parser, serializer, and site generator for Classical Han Annotated Markdown",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
2
+ import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
3
3
  import { annotationToPronSegment } from '../utils/annotationParser'
4
4
  import { toChineseNumber } from '../utils/chineseNumber'
5
5
  import PronunciationGroup from './PronunciationGroup.vue'
@@ -21,6 +21,10 @@ const emit = defineEmits<{
21
21
 
22
22
  const bodyRef = ref<HTMLElement | null>(null)
23
23
 
24
+ const ww = ref(typeof window !== 'undefined' ? window.innerWidth : 1024)
25
+ const isMobile = computed(() => ww.value < 768)
26
+ function onResize() { ww.value = window.innerWidth }
27
+
24
28
  // ─── Resize ───
25
29
  const paneWidth = ref(320)
26
30
  const MIN_W = 180
@@ -36,7 +40,7 @@ function initWidth() {
36
40
  return
37
41
  }
38
42
  } catch {}
39
- paneWidth.value = props.vertical ? 240 : 320
43
+ paneWidth.value = props.vertical ? (ww.value < 768 ? Math.round(ww.value * 0.65) : 240) : 320
40
44
  }
41
45
 
42
46
  let resizing = false
@@ -137,10 +141,12 @@ watch(() => props.activeId, async (id) => {
137
141
  onMounted(() => {
138
142
  initWidth()
139
143
  document.addEventListener('keydown', onKeydown)
144
+ window.addEventListener('resize', onResize, { passive: true })
140
145
  })
141
146
 
142
147
  onBeforeUnmount(() => {
143
148
  document.removeEventListener('keydown', onKeydown)
149
+ window.removeEventListener('resize', onResize)
144
150
  if (moveFn) {
145
151
  document.removeEventListener('mousemove', moveFn)
146
152
  document.removeEventListener('touchmove', moveFn)
@@ -154,6 +160,13 @@ onBeforeUnmount(() => {
154
160
 
155
161
  <template>
156
162
  <Teleport to="body">
163
+ <Transition name="ann-dim">
164
+ <div
165
+ v-if="visible && annotations.length && vertical && isMobile"
166
+ class="ann-pane-dim"
167
+ @click="emit('close')"
168
+ />
169
+ </Transition>
157
170
  <Transition name="ann-pane">
158
171
  <div
159
172
  v-if="visible && annotations.length"
@@ -165,7 +178,7 @@ onBeforeUnmount(() => {
165
178
  <span class="ann-pane-title">注釋</span>
166
179
  <span class="ann-pane-count">{{ annotations.length }}</span>
167
180
  <button class="ann-pane-close" @click="emit('close')" aria-label="關閉">
168
- <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M18 6L6 18M6 6l12 12"/></svg>
181
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M18 6L6 18M6 6l12 12"/></svg>
169
182
  </button>
170
183
  </div>
171
184
  <div ref="bodyRef" class="ann-pane-body">
@@ -404,6 +417,21 @@ onBeforeUnmount(() => {
404
417
  height: 48px;
405
418
  }
406
419
 
420
+ /* ─── Backdrop dim (mobile vertical) ─── */
421
+ .ann-pane-dim {
422
+ position: fixed;
423
+ inset: 0;
424
+ background: rgba(var(--shadow-rgb), 0.24);
425
+ backdrop-filter: blur(4px);
426
+ -webkit-backdrop-filter: blur(4px);
427
+ z-index: 299;
428
+ }
429
+
430
+ .ann-dim-enter-active { transition: opacity 0.3s ease; }
431
+ .ann-dim-leave-active { transition: opacity 0.15s ease; }
432
+ .ann-dim-enter-from,
433
+ .ann-dim-leave-to { opacity: 0; }
434
+
407
435
  /* ─── Transition ─── */
408
436
  .ann-pane-enter-active {
409
437
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
@@ -461,10 +489,12 @@ onBeforeUnmount(() => {
461
489
  overflow-y: hidden;
462
490
  overflow-x: auto;
463
491
  overscroll-behavior: contain;
492
+ touch-action: pan-x;
493
+ -webkit-overflow-scrolling: touch;
464
494
  }
465
495
 
466
496
  .ann-pane.vertical .ann-pane-entry {
467
- padding: 12px 0;
497
+ padding: 24px 12px;
468
498
  border-bottom: none;
469
499
  border-right: 1px solid var(--border-light);
470
500
  border-left: none;
@@ -521,7 +551,14 @@ onBeforeUnmount(() => {
521
551
 
522
552
  .ann-pane.vertical .ann-pane-close {
523
553
  margin-left: 0;
524
- margin-top: auto;
554
+ margin-top: 0;
555
+ margin-bottom: 12px;
556
+ order: -1;
557
+ width: 32px;
558
+ height: 32px;
559
+ border: 1px solid var(--border);
560
+ border-radius: 6px;
561
+ background: var(--surface);
525
562
  }
526
563
 
527
564
  .ann-pane.vertical .ann-pane-count,
@@ -536,7 +573,9 @@ onBeforeUnmount(() => {
536
573
 
537
574
  @media (max-width: 768px) {
538
575
  .ann-pane.vertical {
539
- width: 80vw !important;
576
+ width: auto !important;
577
+ max-width: 65vw !important;
578
+ min-width: 180px;
540
579
  height: 100vh !important;
541
580
  max-height: none !important;
542
581
  top: 0 !important;
@@ -546,10 +585,15 @@ onBeforeUnmount(() => {
546
585
  border-top: none !important;
547
586
  border-radius: 0 !important;
548
587
  box-shadow: -4px 0 24px rgba(var(--shadow-rgb), 0.06) !important;
588
+ z-index: 300;
549
589
  }
550
590
  .ann-pane.vertical .ann-pane-handle {
551
591
  display: flex !important;
552
592
  }
593
+ .ann-pane.vertical .ann-pane-close {
594
+ width: 36px;
595
+ height: 36px;
596
+ }
553
597
  .ann-pane.vertical.ann-pane-enter-from,
554
598
  .ann-pane.vertical.ann-pane-leave-to {
555
599
  transform: translateX(-100%) !important;