@shwfed/nuxt 0.1.18 → 0.1.20

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.
Files changed (34) hide show
  1. package/dist/module.json +2 -2
  2. package/dist/module.mjs +6 -0
  3. package/dist/runtime/components/app.d.vue.ts +2 -2
  4. package/dist/runtime/components/app.vue +4 -0
  5. package/dist/runtime/components/app.vue.d.ts +2 -2
  6. package/dist/runtime/components/dialog.d.vue.ts +22 -0
  7. package/dist/runtime/components/dialog.vue +64 -0
  8. package/dist/runtime/components/dialog.vue.d.ts +22 -0
  9. package/dist/runtime/components/markdown.d.vue.ts +19 -0
  10. package/dist/runtime/components/markdown.vue +52 -0
  11. package/dist/runtime/components/markdown.vue.d.ts +19 -0
  12. package/dist/runtime/components/table.d.vue.ts +1 -1
  13. package/dist/runtime/components/table.vue +103 -22
  14. package/dist/runtime/components/table.vue.d.ts +1 -1
  15. package/dist/runtime/components/tooltip.vue +1 -1
  16. package/dist/runtime/components/ui/button/Button.d.vue.ts +27 -0
  17. package/dist/runtime/components/ui/button/Button.vue +24 -0
  18. package/dist/runtime/components/ui/button/Button.vue.d.ts +27 -0
  19. package/dist/runtime/components/ui/button/index.d.ts +7 -0
  20. package/dist/runtime/components/ui/button/index.js +24 -0
  21. package/dist/runtime/components/ui/separator/Separator.d.vue.ts +11 -0
  22. package/dist/runtime/components/ui/separator/Separator.vue +26 -0
  23. package/dist/runtime/components/ui/separator/Separator.vue.d.ts +11 -0
  24. package/dist/runtime/components/ui/separator/index.d.ts +1 -0
  25. package/dist/runtime/components/ui/separator/index.js +1 -0
  26. package/dist/runtime/plugins/markdown/index.d.ts +5 -4
  27. package/dist/runtime/plugins/markdown/index.js +7 -4
  28. package/dist/runtime/plugins/markdown/md.js +2 -1
  29. package/dist/runtime/plugins/toast/index.d.ts +108 -0
  30. package/dist/runtime/plugins/toast/index.js +12 -0
  31. package/dist/runtime/table-renderers/builtins.js +28 -21
  32. package/dist/runtime/utils/cn.d.ts +2 -0
  33. package/dist/runtime/utils/cn.js +3 -0
  34. package/package.json +5 -5
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@shwfed/nuxt",
3
3
  "configKey": "shwfed",
4
- "version": "0.1.18",
4
+ "version": "0.1.20",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
- "unbuild": "unknown"
7
+ "unbuild": "3.6.1"
8
8
  }
9
9
  }
package/dist/module.mjs CHANGED
@@ -9,8 +9,14 @@ const module$1 = defineNuxtModule({
9
9
  setup(options, nuxt) {
10
10
  const resolver = createResolver(import.meta.url);
11
11
  nuxt.options.runtimeConfig.public.shwfed = options;
12
+ nuxt.options.css ||= [];
13
+ nuxt.options.css.push("vue-sonner/style.css");
12
14
  addPlugin(resolver.resolve("runtime/plugins/cel/index"));
13
15
  addPlugin(resolver.resolve("runtime/plugins/markdown/index"));
16
+ addPlugin({
17
+ src: resolver.resolve("runtime/plugins/toast/index"),
18
+ mode: "client"
19
+ });
14
20
  addImportsDir(resolver.resolve("runtime/composables"));
15
21
  addComponentsDir({
16
22
  path: resolver.resolve("runtime/components"),
@@ -1,6 +1,6 @@
1
- declare var __VLS_8: {};
1
+ declare var __VLS_19: {};
2
2
  type __VLS_Slots = {} & {
3
- default?: (props: typeof __VLS_8) => any;
3
+ default?: (props: typeof __VLS_19) => any;
4
4
  };
5
5
  declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
6
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { useHead } from "#app";
3
3
  import { Tooltip } from "reka-ui/namespaced";
4
+ import { Toaster } from "vue-sonner";
4
5
  useHead({
5
6
  bodyAttrs: {
6
7
  style: {
@@ -12,6 +13,9 @@ useHead({
12
13
 
13
14
  <template>
14
15
  <Tooltip.Provider>
16
+ <ClientOnly>
17
+ <Toaster />
18
+ </ClientOnly>
15
19
  <slot />
16
20
  </Tooltip.Provider>
17
21
  </template>
@@ -1,6 +1,6 @@
1
- declare var __VLS_8: {};
1
+ declare var __VLS_19: {};
2
2
  type __VLS_Slots = {} & {
3
- default?: (props: typeof __VLS_8) => any;
3
+ default?: (props: typeof __VLS_19) => any;
4
4
  };
5
5
  declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
6
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -0,0 +1,22 @@
1
+ type __VLS_Props = {
2
+ /**
3
+ * MD
4
+ */
5
+ title?: string;
6
+ width?: string;
7
+ description?: string;
8
+ disabled?: boolean;
9
+ };
10
+ type __VLS_Slots = {
11
+ trigger: () => void;
12
+ default: () => void;
13
+ };
14
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
18
+ type __VLS_WithSlots<T, S> = T & {
19
+ new (): {
20
+ $slots: S;
21
+ };
22
+ };
@@ -0,0 +1,64 @@
1
+ <script setup>
2
+ import { Icon } from "@iconify/vue";
3
+ import { Dialog } from "reka-ui/namespaced";
4
+ defineProps({
5
+ title: { type: String, required: false },
6
+ width: { type: String, required: false },
7
+ description: { type: String, required: false },
8
+ disabled: { type: Boolean, required: false }
9
+ });
10
+ defineSlots();
11
+ </script>
12
+
13
+ <template>
14
+ <template v-if="disabled">
15
+ <slot name="trigger" />
16
+ </template>
17
+ <Dialog.Root v-else>
18
+ <Dialog.Trigger as-child>
19
+ <slot name="trigger" />
20
+ </Dialog.Trigger>
21
+ <Dialog.Portal>
22
+ <Dialog.Overlay
23
+ class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-zinc-900/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
24
+ >
25
+ <Dialog.Content
26
+ class="absolute z-50 grid my-8 gap-4 border border-slate-200 bg-white p-4 shadow-lg duration-200 rounded-sm outline-none -translate-y-32 translate-3d"
27
+ :style="{
28
+ minWidth: width
29
+ }"
30
+ @pointer-down-outside="(event) => {
31
+ const originalEvent = event.detail.originalEvent;
32
+ const target = originalEvent.target;
33
+ if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
34
+ event.preventDefault();
35
+ }
36
+ }"
37
+ >
38
+ <Dialog.Title
39
+ class="flex items-center justify-between"
40
+ >
41
+ <span
42
+ class="prose prose-zinc prose-base"
43
+ v-html="$md.inline`${title}`({})"
44
+ />
45
+
46
+ <Dialog.Close
47
+ class="outline-none rounded-md p-1 text-zinc-500 hover:text-zinc-800 transition-colors duration-150 bg-transparent"
48
+ >
49
+ <Icon
50
+ icon="fluent:dismiss-20-regular"
51
+ />
52
+ <span class="sr-only">Close</span>
53
+ </Dialog.Close>
54
+ </Dialog.Title>
55
+ <Dialog.Description class="sr-only">
56
+ {{ description }}
57
+ </Dialog.Description>
58
+
59
+ <slot name="default" />
60
+ </Dialog.Content>
61
+ </Dialog.Overlay>
62
+ </Dialog.Portal>
63
+ </Dialog.Root>
64
+ </template>
@@ -0,0 +1,22 @@
1
+ type __VLS_Props = {
2
+ /**
3
+ * MD
4
+ */
5
+ title?: string;
6
+ width?: string;
7
+ description?: string;
8
+ disabled?: boolean;
9
+ };
10
+ type __VLS_Slots = {
11
+ trigger: () => void;
12
+ default: () => void;
13
+ };
14
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
18
+ type __VLS_WithSlots<T, S> = T & {
19
+ new (): {
20
+ $slots: S;
21
+ };
22
+ };
@@ -0,0 +1,19 @@
1
+ type MarkdownEditorVariable = Readonly<{
2
+ identity: string;
3
+ type: string;
4
+ description: string;
5
+ }>;
6
+ type __VLS_Props = {
7
+ variables?: ReadonlyArray<MarkdownEditorVariable>;
8
+ };
9
+ type __VLS_ModelProps = {
10
+ 'modelValue': string;
11
+ };
12
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ "update:modelValue": (value: string) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
16
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -0,0 +1,52 @@
1
+ <script setup>
2
+ import { computed, useAttrs } from "vue";
3
+ const model = defineModel("modelValue", { type: String, ...{ required: true } });
4
+ defineOptions({
5
+ inheritAttrs: false
6
+ });
7
+ const props = defineProps({
8
+ variables: { type: Array, required: false }
9
+ });
10
+ const attrs = useAttrs();
11
+ const textareaAttrs = computed(() => {
12
+ const { class: _class, ...rest } = attrs;
13
+ return rest;
14
+ });
15
+ </script>
16
+
17
+ <template>
18
+ <div class="space-y-2">
19
+ <textarea
20
+ v-bind="textareaAttrs"
21
+ v-model="model"
22
+ :class="[
23
+ 'w-full border text-sync-200 hover:text-sync-300 transition-colors duration-150 rounded-sm outline-none',
24
+ 'text-zinc-700 text-xs font-mono placeholder:text-zinc-400 hover:border-zinc-300 focus:border-zinc-300',
25
+ 'p-2 resize-none',
26
+ attrs.class
27
+ ]"
28
+ placeholder="输入 Markdown 使用 {{ }} 嵌入表达式"
29
+ />
30
+
31
+ <h3 class="text-sm text-zinc-700">
32
+ 可使用的变量
33
+ </h3>
34
+
35
+ <ul
36
+ v-if="props.variables?.length"
37
+ class="space-y-1"
38
+ >
39
+ <li
40
+ v-for="variable in props.variables"
41
+ :key="variable.identity"
42
+ class="text-xs text-zinc-700 space-x-2 list-circle list-inside"
43
+ >
44
+ <span class="font-mono text-xs">{{ variable.identity }}: {{ variable.type }}</span>
45
+ <span
46
+ class="prose prose-zinc text-xs opacity-80"
47
+ v-html="$md.inline`${variable.description}`({})"
48
+ />
49
+ </li>
50
+ </ul>
51
+ </div>
52
+ </template>
@@ -0,0 +1,19 @@
1
+ type MarkdownEditorVariable = Readonly<{
2
+ identity: string;
3
+ type: string;
4
+ description: string;
5
+ }>;
6
+ type __VLS_Props = {
7
+ variables?: ReadonlyArray<MarkdownEditorVariable>;
8
+ };
9
+ type __VLS_ModelProps = {
10
+ 'modelValue': string;
11
+ };
12
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ "update:modelValue": (value: string) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
16
+ "onUpdate:modelValue"?: ((value: string) => any) | undefined;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const _default: typeof __VLS_export;
19
+ export default _default;
@@ -44,7 +44,7 @@ declare const __VLS_export: import("vue").DefineComponent<Readonly<{
44
44
  props?: Omit<TableOptions<unknown>, "columns" | "data" | "getRowId" | "getCoreRowModel">;
45
45
  paginationLeft?: Markdown;
46
46
  paginationRight?: Markdown;
47
- }>, import("@tanstack/vue-table").Table<unknown>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Readonly<{
47
+ }>, import("@tanstack/table-core").Table<unknown>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Readonly<{
48
48
  id: string;
49
49
  getRowId?: Expression;
50
50
  getSubRows?: Expression;
@@ -6,8 +6,12 @@ import { getProperty } from "dot-prop";
6
6
  import { Pagination } from "reka-ui/namespaced";
7
7
  import { computed, ref } from "vue";
8
8
  import { useNuxtApp } from "#app";
9
+ import { Button } from "./ui/button";
9
10
  import { useTableRenderers } from "../composables/useTableRenderers";
10
11
  import Tooltip from "./tooltip.vue";
12
+ import Dialog from "./dialog.vue";
13
+ import MarkdownEditor from "./markdown.vue";
14
+ import { useCheating } from "#imports";
11
15
  </script>
12
16
 
13
17
  <script setup>
@@ -25,6 +29,7 @@ const props = defineProps({
25
29
  paginationRight: { type: String, required: false }
26
30
  });
27
31
  const { $dsl } = useNuxtApp();
32
+ const isCheating = useCheating();
28
33
  const { resolveTableRenderer } = useTableRenderers();
29
34
  const containerRef = ref(null);
30
35
  function genColumnId(column) {
@@ -291,22 +296,20 @@ function getSortIcon(column) {
291
296
  <Tooltip
292
297
  v-if="!header.isPlaceholder && header.column.columnDef.meta?.tooltip"
293
298
  :delay-duration="180"
294
- :content="$md.inline`${header.column.columnDef.meta.tooltip}`"
299
+ :content="$md.inline`${header.column.columnDef.meta.tooltip}`()"
295
300
  >
296
301
  <Icon icon="fluent:info-20-regular" />
297
302
  </Tooltip>
298
303
 
299
- <button
304
+ <Button
300
305
  v-if="!header.isPlaceholder && header.column.getCanSort()"
301
- type="button"
302
- :class="[
303
- 'p-1 cursor-pointer outline-none absolute right-1 top-1/2 -translate-y-1/2 transform-3d',
304
- 'group-hover:opacity-100 opacity-60 transition-opacity duration-180 bg-transparent'
305
- ]"
306
- @click="header.column.getToggleSortingHandler()?.($event)"
306
+ variant="ghost"
307
+ size="xs"
308
+ class="absolute hover:bg-transparent right-1 top-1/2 -translate-y-1/2 transform-3d group-hover:opacity-100 opacity-60 transition-opacity duration-180"
309
+ @click="(event) => header.column.getToggleSortingHandler()?.(event)"
307
310
  >
308
311
  <Icon :icon="getSortIcon(header.column)" />
309
- </button>
312
+ </Button>
310
313
 
311
314
  <div
312
315
  v-if="!header.isPlaceholder && header.column.getCanResize() && (!header.column.getIsLastColumn('right') || !table.getIsSomeColumnsPinned('right') && !header.column.getIsLastColumn('center'))"
@@ -328,7 +331,7 @@ function getSortIcon(column) {
328
331
  ]"
329
332
  @mousedown="header.getResizeHandler()($event)"
330
333
  >
331
- <div :class="['w-2pt', 'translate-x-1pt', 'h-full', 'bg-blue-400']" />
334
+ <div :class="['w-2pt', 'h-full', 'translate-x-1pt', 'transform-3d', 'bg-[color-mix(in_srgb,var(--primary)_80%,white)]']" />
332
335
  </div>
333
336
  </th>
334
337
  </tr>
@@ -370,7 +373,7 @@ function getSortIcon(column) {
370
373
  </tr>
371
374
  </tbody>
372
375
 
373
- <tfoot class="hidden has-[[data-footer]]:grid sticky bottom-0 z-10 select-none border-t border-zinc-200">
376
+ <tfoot class="hidden has-data-footer:grid sticky bottom-0 z-10 select-none border-t border-zinc-200">
374
377
  <tr
375
378
  v-for="group in table.getFooterGroups()"
376
379
  :key="group.id"
@@ -406,10 +409,48 @@ function getSortIcon(column) {
406
409
  </div>
407
410
  </div>
408
411
 
409
- <div class="flex items-center justify-between w-full p-4 text-sm text-zinc-600">
410
- <div>
411
- <div />
412
- </div>
412
+ <div class="flex items-center justify-between w-full py-2 gap-2 text-sm text-zinc-600">
413
+ <Dialog
414
+ title="编辑分页左侧文字"
415
+ width="50%"
416
+ :disabled="!isCheating"
417
+ >
418
+ <template #trigger>
419
+ <div
420
+ :class="[
421
+ 'relative p-1 flex-1 prose prose-zinc text-xs border border-dashed',
422
+ isCheating ? 'border-(--primary)/20 rounded hover:border-(--primary)/40 transition-colors duration-150 group cursor-pointer' : 'border-transparent'
423
+ ]"
424
+ >
425
+ <span
426
+ v-html="$md.inline`${props.paginationLeft}`({
427
+ selected: table.getSelectedRowModel().rows.map((row) => row.original)
428
+ })"
429
+ />
430
+ <Icon
431
+ v-if="isCheating"
432
+ icon="fluent:edit-20-regular"
433
+ class="w-4 h-4 text-(--primary) absolute right-1 top-1/2 -translate-y-1/2 transform-3d group-hover:opacity-100 opacity-50 transition-opacity duration-150"
434
+ />
435
+ &nbsp;
436
+ </div>
437
+ </template>
438
+ <template #default>
439
+ <MarkdownEditor
440
+ :model-value="props.paginationLeft ?? ''"
441
+ class="w-full h-64"
442
+ :variables="[
443
+ {
444
+ identity: 'selected',
445
+ type: 'list<dyn>',
446
+ description: $md.raw`
447
+ 表格被选中的行:如果没有被选中的行,那么这个变量将始终为空列表。
448
+ `
449
+ }
450
+ ]"
451
+ />
452
+ </template>
453
+ </Dialog>
413
454
  <div class="flex items-center gap-4">
414
455
  <span class="text-xs">{{ `\u5171 ${props.data.length} \u6761` }}</span>
415
456
  <Pagination.Root
@@ -426,7 +467,7 @@ function getSortIcon(column) {
426
467
  <Pagination.First
427
468
  :class="[
428
469
  'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
429
- 'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed cursor-pointer'
470
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
430
471
  ]"
431
472
  >
432
473
  <Icon
@@ -437,7 +478,7 @@ function getSortIcon(column) {
437
478
  <Pagination.Prev
438
479
  :class="[
439
480
  'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
440
- 'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed cursor-pointer'
481
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
441
482
  ]"
442
483
  >
443
484
  <Icon
@@ -453,8 +494,8 @@ function getSortIcon(column) {
453
494
  <Pagination.ListItem
454
495
  v-if="page.type === 'page'"
455
496
  :class="[
456
- 'w-7 h-7 flex items-center justify-center border border-zinc-200 rounded text-xs bg-transparent',
457
- 'data-[selected]:text-[var(--primary)] data-[selected]:border-[var(--primary)] hover:bg-zinc-100 transition cursor-pointer'
497
+ 'w-7 h-7 flex items-center justify-center rounded text-xs bg-transparent',
498
+ 'data-selected:text-(--primary) data-selected:border-(--primary) hover:bg-zinc-100 transition cursor-pointer'
458
499
  ]"
459
500
  :value="page.value"
460
501
  >
@@ -471,7 +512,7 @@ function getSortIcon(column) {
471
512
  <Pagination.Next
472
513
  :class="[
473
514
  'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
474
- 'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed cursor-pointer'
515
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
475
516
  ]"
476
517
  >
477
518
  <Icon
@@ -482,7 +523,7 @@ function getSortIcon(column) {
482
523
  <Pagination.Last
483
524
  :class="[
484
525
  'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
485
- 'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed cursor-pointer'
526
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
486
527
  ]"
487
528
  >
488
529
  <Icon
@@ -494,7 +535,47 @@ function getSortIcon(column) {
494
535
  </Pagination.Root>
495
536
  <span class="text-xs">前往</span>
496
537
  </div>
497
- <div />
538
+ <Dialog
539
+ title="编辑分页右侧文字"
540
+ width="50%"
541
+ :disabled="!isCheating"
542
+ >
543
+ <template #trigger>
544
+ <div
545
+ :class="[
546
+ 'relative p-1 flex-1 prose prose-zinc text-xs border border-dashed',
547
+ isCheating ? 'border-(--primary)/20 rounded hover:border-(--primary)/40 transition-colors duration-150 group cursor-pointer' : 'border-transparent'
548
+ ]"
549
+ >
550
+ <span
551
+ v-html="$md.inline`${props.paginationRight}`({
552
+ selected: table.getSelectedRowModel().rows.map((row) => row.original)
553
+ })"
554
+ />
555
+ <Icon
556
+ v-if="isCheating"
557
+ icon="fluent:edit-20-regular"
558
+ class="w-4 h-4 text-(--primary) absolute right-1 top-1/2 -translate-y-1/2 transform-3d group-hover:opacity-100 opacity-50 transition-opacity duration-150"
559
+ />
560
+ &nbsp;
561
+ </div>
562
+ </template>
563
+ <template #default>
564
+ <MarkdownEditor
565
+ :model-value="props.paginationRight ?? ''"
566
+ class="w-full h-64"
567
+ :variables="[
568
+ {
569
+ identity: 'selected',
570
+ type: 'list<dyn>',
571
+ description: $md.raw`
572
+ 表格被选中的行:如果没有被选中的行,那么这个变量将始终为空列表。
573
+ `
574
+ }
575
+ ]"
576
+ />
577
+ </template>
578
+ </Dialog>
498
579
  </div>
499
580
  </div>
500
581
  </template>
@@ -44,7 +44,7 @@ declare const __VLS_export: import("vue").DefineComponent<Readonly<{
44
44
  props?: Omit<TableOptions<unknown>, "columns" | "data" | "getRowId" | "getCoreRowModel">;
45
45
  paginationLeft?: Markdown;
46
46
  paginationRight?: Markdown;
47
- }>, import("@tanstack/vue-table").Table<unknown>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Readonly<{
47
+ }>, import("@tanstack/table-core").Table<unknown>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Readonly<{
48
48
  id: string;
49
49
  getRowId?: Expression;
50
50
  getSubRows?: Expression;
@@ -39,7 +39,7 @@ const forwarded = useForwardPropsEmits(props, emits);
39
39
  />
40
40
  <Tooltip.Arrow
41
41
  :class="[
42
- 'bg-white fill-white size-2.5 translate-y-[calc(-50%)] rotate-45 rounded-[2px]',
42
+ 'bg-white fill-white size-2.5 translate-y-[calc(-50%)] rotate-45 rounded-xs',
43
43
  'border-b border-r border-zinc-200'
44
44
  ]"
45
45
  />
@@ -0,0 +1,27 @@
1
+ import type { PrimitiveProps } from 'reka-ui';
2
+ import type { HTMLAttributes } from 'vue';
3
+ import type { ButtonVariants } from '.';
4
+ interface Props extends PrimitiveProps {
5
+ variant?: ButtonVariants['variant'];
6
+ size?: ButtonVariants['size'];
7
+ class?: HTMLAttributes['class'];
8
+ }
9
+ declare var __VLS_8: {};
10
+ type __VLS_Slots = {} & {
11
+ default?: (props: typeof __VLS_8) => any;
12
+ };
13
+ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ click: (...args: any[]) => void;
15
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
16
+ onClick?: ((...args: any[]) => any) | undefined;
17
+ }>, {
18
+ as: import("reka-ui").AsTag | import("vue").Component;
19
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
23
+ type __VLS_WithSlots<T, S> = T & {
24
+ new (): {
25
+ $slots: S;
26
+ };
27
+ };
@@ -0,0 +1,24 @@
1
+ <script setup>
2
+ import { cn } from "../../../utils/cn";
3
+ import { Primitive, useForwardPropsEmits } from "reka-ui";
4
+ import { buttonVariants } from ".";
5
+ const props = defineProps({
6
+ variant: { type: null, required: false },
7
+ size: { type: null, required: false },
8
+ class: { type: null, required: false },
9
+ asChild: { type: Boolean, required: false },
10
+ as: { type: null, required: false, default: "button" }
11
+ });
12
+ const emits = defineEmits(["click"]);
13
+ const forwarded = useForwardPropsEmits(props, emits);
14
+ </script>
15
+
16
+ <template>
17
+ <Primitive
18
+ data-slot="button"
19
+ v-bind="forwarded"
20
+ :class="cn(buttonVariants({ variant, size }), props.class)"
21
+ >
22
+ <slot />
23
+ </Primitive>
24
+ </template>
@@ -0,0 +1,27 @@
1
+ import type { PrimitiveProps } from 'reka-ui';
2
+ import type { HTMLAttributes } from 'vue';
3
+ import type { ButtonVariants } from '.';
4
+ interface Props extends PrimitiveProps {
5
+ variant?: ButtonVariants['variant'];
6
+ size?: ButtonVariants['size'];
7
+ class?: HTMLAttributes['class'];
8
+ }
9
+ declare var __VLS_8: {};
10
+ type __VLS_Slots = {} & {
11
+ default?: (props: typeof __VLS_8) => any;
12
+ };
13
+ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ click: (...args: any[]) => void;
15
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
16
+ onClick?: ((...args: any[]) => any) | undefined;
17
+ }>, {
18
+ as: import("reka-ui").AsTag | import("vue").Component;
19
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
23
+ type __VLS_WithSlots<T, S> = T & {
24
+ new (): {
25
+ $slots: S;
26
+ };
27
+ };
@@ -0,0 +1,7 @@
1
+ import type { VariantProps } from 'class-variance-authority';
2
+ export { default as Button } from './Button.vue.js';
3
+ export declare const buttonVariants: (props?: ({
4
+ variant?: "primary" | "default" | "destructive" | "ghost" | null | undefined;
5
+ size?: "default" | "sm" | "xs" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ export type ButtonVariants = VariantProps<typeof buttonVariants>;
@@ -0,0 +1,24 @@
1
+ import { cva } from "class-variance-authority";
2
+ export { default as Button } from "./Button.vue";
3
+ export const buttonVariants = cva(
4
+ "cursor-pointer tracking-wide inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-sm text-sm font-medium transition-all duration-180 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none aria-invalid:border-red-200 select-none",
5
+ {
6
+ variants: {
7
+ variant: {
8
+ default: "border border-slate-200 bg-white text-slate-700 hover:bg-[color-mix(in_srgb,var(--primary)_20%,white)] hover:border-[color-mix(in_srgb,var(--primary)_60%,white)] hover:text-(--primary)",
9
+ destructive: "border border-red-200 text-red-600 bg-[color-mix(in_srgb,red_10%,white)] hover:bg-red-400 hover:border-red-400 hover:text-white",
10
+ primary: "bg-(--primary) text-white hover:bg-[color-mix(in_srgb,var(--primary)_70%,white)]",
11
+ ghost: "border-none bg-transparent text-slate-700 hover:bg-slate-100 hover:text-slate-900"
12
+ },
13
+ size: {
14
+ default: "h-8 px-4 py-2 has-[>svg]:px-3",
15
+ sm: "h-6 rounded gap-1.5 text-xs px-3 has-[>svg]:px-2.5",
16
+ xs: "h-4 rounded gap-1 text-xs px-2 has-[>svg]:px-1"
17
+ }
18
+ },
19
+ defaultVariants: {
20
+ variant: "default",
21
+ size: "default"
22
+ }
23
+ }
24
+ );
@@ -0,0 +1,11 @@
1
+ import type { SeparatorProps } from 'reka-ui';
2
+ import type { HTMLAttributes } from 'vue';
3
+ type __VLS_Props = SeparatorProps & {
4
+ class?: HTMLAttributes['class'];
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
7
+ orientation: "horizontal" | "vertical";
8
+ decorative: boolean;
9
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
@@ -0,0 +1,26 @@
1
+ <script setup>
2
+ import { reactiveOmit } from "@vueuse/core";
3
+ import { Separator } from "reka-ui";
4
+ import { cn } from "../../../utils/cn";
5
+ const props = defineProps({
6
+ orientation: { type: String, required: false, default: "horizontal" },
7
+ decorative: { type: Boolean, required: false, default: true },
8
+ asChild: { type: Boolean, required: false },
9
+ as: { type: null, required: false },
10
+ class: { type: null, required: false }
11
+ });
12
+ const delegatedProps = reactiveOmit(props, "class");
13
+ </script>
14
+
15
+ <template>
16
+ <Separator
17
+ data-slot="separator"
18
+ v-bind="delegatedProps"
19
+ :class="
20
+ cn(
21
+ 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
22
+ props.class
23
+ )
24
+ "
25
+ />
26
+ </template>
@@ -0,0 +1,11 @@
1
+ import type { SeparatorProps } from 'reka-ui';
2
+ import type { HTMLAttributes } from 'vue';
3
+ type __VLS_Props = SeparatorProps & {
4
+ class?: HTMLAttributes['class'];
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
7
+ orientation: "horizontal" | "vertical";
8
+ decorative: boolean;
9
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
@@ -0,0 +1 @@
1
+ export { default as Separator } from './Separator.vue.js';
@@ -0,0 +1 @@
1
+ export { default as Separator } from "./Separator.vue";
@@ -1,23 +1,24 @@
1
1
  import { md } from './md.js';
2
+ import type { Context } from '@marcbachmann/cel-js';
2
3
  declare const _default: import("#app").Plugin<{
3
4
  md: {
4
5
  raw: typeof md;
5
6
  inline: (template: {
6
7
  raw: readonly string[] | ArrayLike<string>;
7
- }, ...substitutions: any[]) => string;
8
+ }, ...substitutions: any[]) => (context?: Context) => string;
8
9
  block: (template: {
9
10
  raw: readonly string[] | ArrayLike<string>;
10
- }, ...substitutions: any[]) => string;
11
+ }, ...substitutions: any[]) => (context?: Context) => string;
11
12
  };
12
13
  }> & import("#app").ObjectPlugin<{
13
14
  md: {
14
15
  raw: typeof md;
15
16
  inline: (template: {
16
17
  raw: readonly string[] | ArrayLike<string>;
17
- }, ...substitutions: any[]) => string;
18
+ }, ...substitutions: any[]) => (context?: Context) => string;
18
19
  block: (template: {
19
20
  raw: readonly string[] | ArrayLike<string>;
20
- }, ...substitutions: any[]) => string;
21
+ }, ...substitutions: any[]) => (context?: Context) => string;
21
22
  };
22
23
  }>;
23
24
  export default _default;
@@ -9,12 +9,15 @@ export default defineNuxtPlugin({
9
9
  html: true
10
10
  });
11
11
  const { $dsl } = useNuxtApp();
12
- function evaluateBlock(source) {
12
+ function evaluateBlock(source, context) {
13
13
  return source.replace(/\{\{([\s\S]+?)\}\}/g, (_, expression) => {
14
14
  if (!expression)
15
15
  return "";
16
16
  try {
17
- return $dsl.evaluate(expression);
17
+ const result = $dsl.evaluate(expression, context);
18
+ if (result !== null)
19
+ return String(result);
20
+ return "";
18
21
  } catch (e) {
19
22
  console.error(e);
20
23
  return "";
@@ -25,8 +28,8 @@ export default defineNuxtPlugin({
25
28
  provide: {
26
29
  md: {
27
30
  raw: md,
28
- inline: (...args) => engine.renderInline(evaluateBlock(md(...args))),
29
- block: (...args) => engine.render(evaluateBlock(md(...args)))
31
+ inline: (...args) => (context) => engine.renderInline(evaluateBlock(md(...args), context)),
32
+ block: (...args) => (context) => engine.render(evaluateBlock(md(...args), context))
30
33
  }
31
34
  }
32
35
  };
@@ -1,5 +1,6 @@
1
1
  export function md(...args) {
2
- const original = String.raw(...args);
2
+ const [template, ...rest] = args;
3
+ const original = String.raw(template, ...rest.map((arg) => arg ?? ""));
3
4
  const indent = (original.startsWith("\n") ? original.slice(1) : original).split("\n", 1)[0]?.match(/^(\s*)/)?.[1]?.length ?? 0;
4
5
  return original.trim().replaceAll("\\`", "`").split("\n").map((line) => line.replace(new RegExp(`^${String.raw`\s`.repeat(indent)}`), "")).join("\n");
5
6
  }
@@ -0,0 +1,108 @@
1
+ declare const _default: import("#app").Plugin<{
2
+ toast: ((message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number) & {
3
+ success: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
4
+ info: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
5
+ warning: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
6
+ error: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
7
+ custom: (component: import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
8
+ message: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
9
+ promise: <ToastData>(promise: Promise<ToastData> | (() => Promise<ToastData>), data?: ({
10
+ id?: number | string | undefined;
11
+ class?: string | undefined;
12
+ style?: import("vue").CSSProperties | undefined;
13
+ icon?: import("vue").Component | undefined;
14
+ toasterId?: string | undefined;
15
+ component?: import("vue").Component | undefined;
16
+ componentProps?: any;
17
+ richColors?: boolean | undefined;
18
+ invert?: boolean | undefined;
19
+ closeButton?: boolean | undefined;
20
+ dismissible?: boolean | undefined;
21
+ duration?: number | undefined;
22
+ important?: boolean | undefined;
23
+ action?: (import("vue-sonner").Action | import("vue").Component) | undefined;
24
+ cancel?: (import("vue-sonner").Action | import("vue").Component) | undefined;
25
+ onDismiss?: ((toast: import("vue-sonner").ToastT) => void) | undefined;
26
+ onAutoClose?: ((toast: import("vue-sonner").ToastT) => void) | undefined;
27
+ cancelButtonStyle?: import("vue").CSSProperties | undefined;
28
+ actionButtonStyle?: import("vue").CSSProperties | undefined;
29
+ unstyled?: boolean | undefined;
30
+ classes?: import("vue-sonner").ToastClasses | undefined;
31
+ descriptionClass?: string | undefined;
32
+ position?: ("top-left" | "top-right" | "bottom-left" | "bottom-right" | "top-center" | "bottom-center") | undefined;
33
+ closeButtonPosition?: ("top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
34
+ testId?: string | undefined;
35
+ } & {
36
+ loading?: string | import("vue").Component;
37
+ success?: (string | import("vue").Component | ((data: ToastData) => import("vue").Component | string | Promise<import("vue").Component | string>)) | (import("vue-sonner").PromiseIExtendedResult | ((data: ToastData) => import("vue-sonner").PromiseIExtendedResult | Promise<import("vue-sonner").PromiseIExtendedResult>)) | undefined;
38
+ error?: (string | import("vue").Component | ((data: any) => import("vue").Component | string | Promise<import("vue").Component | string>)) | (import("vue-sonner").PromiseIExtendedResult | ((data: any) => import("vue-sonner").PromiseIExtendedResult | Promise<import("vue-sonner").PromiseIExtendedResult>));
39
+ description?: string | import("vue").Component | ((data: any) => import("vue").Component | string | Promise<import("vue").Component | string>);
40
+ finally?: () => void | Promise<void>;
41
+ }) | undefined) => (string & {
42
+ unwrap: () => Promise<ToastData>;
43
+ }) | (number & {
44
+ unwrap: () => Promise<ToastData>;
45
+ }) | {
46
+ unwrap: () => Promise<ToastData>;
47
+ } | undefined;
48
+ dismiss: (id?: number | string) => string | number | undefined;
49
+ loading: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
50
+ } & {
51
+ getHistory: () => (import("vue-sonner").ToastT<import("vue").Component> | import("vue-sonner").ToastToDismiss)[];
52
+ getToasts: () => (import("vue-sonner").ToastT<import("vue").Component> | import("vue-sonner").ToastToDismiss)[];
53
+ };
54
+ }> & import("#app").ObjectPlugin<{
55
+ toast: ((message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number) & {
56
+ success: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
57
+ info: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
58
+ warning: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
59
+ error: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
60
+ custom: (component: import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
61
+ message: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
62
+ promise: <ToastData>(promise: Promise<ToastData> | (() => Promise<ToastData>), data?: ({
63
+ id?: number | string | undefined;
64
+ class?: string | undefined;
65
+ style?: import("vue").CSSProperties | undefined;
66
+ icon?: import("vue").Component | undefined;
67
+ toasterId?: string | undefined;
68
+ component?: import("vue").Component | undefined;
69
+ componentProps?: any;
70
+ richColors?: boolean | undefined;
71
+ invert?: boolean | undefined;
72
+ closeButton?: boolean | undefined;
73
+ dismissible?: boolean | undefined;
74
+ duration?: number | undefined;
75
+ important?: boolean | undefined;
76
+ action?: (import("vue-sonner").Action | import("vue").Component) | undefined;
77
+ cancel?: (import("vue-sonner").Action | import("vue").Component) | undefined;
78
+ onDismiss?: ((toast: import("vue-sonner").ToastT) => void) | undefined;
79
+ onAutoClose?: ((toast: import("vue-sonner").ToastT) => void) | undefined;
80
+ cancelButtonStyle?: import("vue").CSSProperties | undefined;
81
+ actionButtonStyle?: import("vue").CSSProperties | undefined;
82
+ unstyled?: boolean | undefined;
83
+ classes?: import("vue-sonner").ToastClasses | undefined;
84
+ descriptionClass?: string | undefined;
85
+ position?: ("top-left" | "top-right" | "bottom-left" | "bottom-right" | "top-center" | "bottom-center") | undefined;
86
+ closeButtonPosition?: ("top-left" | "top-right" | "bottom-left" | "bottom-right") | undefined;
87
+ testId?: string | undefined;
88
+ } & {
89
+ loading?: string | import("vue").Component;
90
+ success?: (string | import("vue").Component | ((data: ToastData) => import("vue").Component | string | Promise<import("vue").Component | string>)) | (import("vue-sonner").PromiseIExtendedResult | ((data: ToastData) => import("vue-sonner").PromiseIExtendedResult | Promise<import("vue-sonner").PromiseIExtendedResult>)) | undefined;
91
+ error?: (string | import("vue").Component | ((data: any) => import("vue").Component | string | Promise<import("vue").Component | string>)) | (import("vue-sonner").PromiseIExtendedResult | ((data: any) => import("vue-sonner").PromiseIExtendedResult | Promise<import("vue-sonner").PromiseIExtendedResult>));
92
+ description?: string | import("vue").Component | ((data: any) => import("vue").Component | string | Promise<import("vue").Component | string>);
93
+ finally?: () => void | Promise<void>;
94
+ }) | undefined) => (string & {
95
+ unwrap: () => Promise<ToastData>;
96
+ }) | (number & {
97
+ unwrap: () => Promise<ToastData>;
98
+ }) | {
99
+ unwrap: () => Promise<ToastData>;
100
+ } | undefined;
101
+ dismiss: (id?: number | string) => string | number | undefined;
102
+ loading: (message: string | (() => string | import("vue").Component) | import("vue").Component, data?: import("vue-sonner").ExternalToast) => string | number;
103
+ } & {
104
+ getHistory: () => (import("vue-sonner").ToastT<import("vue").Component> | import("vue-sonner").ToastToDismiss)[];
105
+ getToasts: () => (import("vue-sonner").ToastT<import("vue").Component> | import("vue-sonner").ToastToDismiss)[];
106
+ };
107
+ }>;
108
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import { defineNuxtPlugin } from "#app";
2
+ import { toast as sonnerToast } from "vue-sonner";
3
+ export default defineNuxtPlugin({
4
+ name: "shwfed-nuxt:toast",
5
+ setup: () => {
6
+ return {
7
+ provide: {
8
+ toast: sonnerToast
9
+ }
10
+ };
11
+ }
12
+ });
@@ -5,6 +5,7 @@ import { defineComponent } from "vue";
5
5
  import { z } from "zod";
6
6
  import { defineTableRenderer } from "./registry.js";
7
7
  import { useNuxtApp } from "#app";
8
+ import { Button } from "../components/ui/button/index.js";
8
9
  const JUSTIFY_CLASS = {
9
10
  left: "justify-start",
10
11
  center: "justify-center",
@@ -218,15 +219,10 @@ defineTableRenderer(
218
219
  children: [
219
220
  isEmpty ? "-" : String(rawValue),
220
221
  options.copyable && !isEmpty ? /* @__PURE__ */ jsx(
221
- "button",
222
+ Button,
222
223
  {
223
- type: "button",
224
- class: [
225
- "cursor-pointer absolute right-1 top-1/2 -translate-y-1/2 bg-white border",
226
- "w-6 h-6 flex items-center justify-center group-hover:opacity-100 opacity-0",
227
- "transition-all duration-180 rounded border-zinc-200 text-zinc-500",
228
- "hover:border-[color-mix(in_srgb,var(--primary)_50%,white)] hover:text-[color-mix(in_srgb,var(--primary)_80%,#00000033)] hover:bg-[color-mix(in_srgb,var(--primary)_10%,white)]"
229
- ],
224
+ class: "p-1 w-6 h-6 flex items-center justify-center right-1 top-1/2 -translate-y-1/2 transform-3d group-hover:opacity-100 opacity-0 absolute transition-opacity duration-180",
225
+ size: "xs",
230
226
  onClick: onCopy,
231
227
  children: /* @__PURE__ */ jsx(Icon, { icon: "fluent:copy-20-regular" })
232
228
  }
@@ -256,13 +252,13 @@ defineTableRenderer(
256
252
  checked: ctx.row.getIsSelected(),
257
253
  class: [
258
254
  "peer h-4 w-4 disabled:opacity-50 transition-colors duration-180 appearance-none",
259
- "border border-zinc-200 not-checked-enabled-group-hover:border-zinc-300 not-checked-enabled-group-hover:bg-zinc-100 checked:border-[var(--primary)]",
255
+ "border border-zinc-200 not-checked-enabled-group-hover:border-zinc-300 not-checked-enabled-group-hover:bg-zinc-100 checked:border-(--primary)",
260
256
  isSingle ? "rounded-full" : "rounded"
261
257
  ],
262
258
  onInput: (e) => ctx.row.getToggleSelectedHandler()(e)
263
259
  }
264
260
  ),
265
- isSingle ? /* @__PURE__ */ jsx("div", { class: "absolute inset-1 bg-[var(--primary)] pointer-events-none rounded-full peer-checked:opacity-100 opacity-0 transition-opacity duration-180" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
261
+ isSingle ? /* @__PURE__ */ jsx("div", { class: "absolute inset-1 bg-(--primary) pointer-events-none rounded-full peer-checked:opacity-100 opacity-0 transition-opacity duration-180" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
266
262
  /* @__PURE__ */ jsx(
267
263
  Icon,
268
264
  {
@@ -270,7 +266,7 @@ defineTableRenderer(
270
266
  class: "peer-checked:opacity-100 opacity-0 text-white text-xs absolute z-1 -translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2"
271
267
  }
272
268
  ),
273
- /* @__PURE__ */ jsx("div", { class: "absolute inset-0 bg-[var(--primary)] rounded pointer-events-none peer-checked:opacity-100 opacity-0 transition-opacity duration-180" })
269
+ /* @__PURE__ */ jsx("div", { class: "absolute inset-0 bg-(--primary) rounded pointer-events-none peer-checked:opacity-100 opacity-0 transition-opacity duration-180" })
274
270
  ] })
275
271
  ] }) });
276
272
  },
@@ -291,7 +287,7 @@ defineTableRenderer(
291
287
  class: [
292
288
  "peer h-4 w-4 cursor-pointer transition-colors duration-180 appearance-none rounded bg-white",
293
289
  "border border-[color-mix(in_srgb,var(--primary)_10%,#00000033)] not-checked-group-hover:border-[color-mix(in_srgb,var(--primary)_20%,#00000033)]",
294
- "not-checked-group-hover:bg-[color-mix(in_srgb,var(--primary)_5%,#00000011)] checked:border-[var(--primary)] checked:bg-[var(--primary)]"
290
+ "not-checked-group-hover:bg-[color-mix(in_srgb,var(--primary)_5%,#00000011)] checked:border-(--primary) checked:bg-(--primary)"
295
291
  ],
296
292
  ref: (el) => {
297
293
  if (el instanceof HTMLInputElement)
@@ -317,21 +313,22 @@ defineTableRenderer(
317
313
  if (!ctx.row.getCanExpand())
318
314
  return null;
319
315
  return /* @__PURE__ */ jsx("div", { class: "group w-full h-full flex items-center justify-center text-zinc-700", children: /* @__PURE__ */ jsx(
320
- "button",
316
+ Button,
321
317
  {
322
- type: "button",
323
- class: "cursor-pointer bg-transparent",
324
- onClick: () => ctx.row.getToggleExpandedHandler()(),
318
+ variant: "ghost",
319
+ class: "cursor-pointer hover:bg-transparent text-lg",
320
+ onClick: ctx.row.getToggleExpandedHandler(),
325
321
  children: /* @__PURE__ */ jsx(Icon, { icon: ctx.row.getIsExpanded() ? "fluent:subtract-square-20-regular" : "fluent:add-square-20-regular" })
326
322
  }
327
323
  ) });
328
324
  },
329
325
  header: ({ ctx }) => /* @__PURE__ */ jsx("div", { class: "group w-full h-full flex items-center justify-center text-base text-zinc-700", children: /* @__PURE__ */ jsx(
330
- "button",
326
+ Button,
331
327
  {
332
- type: "button",
333
- class: "cursor-pointer bg-transparent",
334
- onClick: (e) => ctx.table.getToggleAllRowsExpandedHandler()(e),
328
+ variant: "ghost",
329
+ size: "xs",
330
+ class: "cursor-pointer hover:bg-transparent text-lg",
331
+ onClick: ctx.table.getToggleAllRowsExpandedHandler(),
335
332
  children: /* @__PURE__ */ jsx(Icon, { icon: ctx.table.getIsAllRowsExpanded() ? "fluent:subtract-square-20-regular" : "fluent:add-square-20-regular" })
336
333
  }
337
334
  ) }),
@@ -402,7 +399,17 @@ defineTableRenderer(
402
399
  cell: ({ ctx, options }) => {
403
400
  const { $md } = useNuxtApp();
404
401
  const source = options.source ?? String(ctx.cell.getValue());
405
- return /* @__PURE__ */ jsx("div", { class: "relative w-full py-2 px-1 flex items-center justify-center text-xs", children: /* @__PURE__ */ jsx("span", { class: "prose prose-zinc text-xs", innerHTML: $md.inline`${source}` }) });
402
+ return /* @__PURE__ */ jsx("div", { class: "relative w-full py-2 px-1 flex items-center justify-center text-xs", children: /* @__PURE__ */ jsx(
403
+ "span",
404
+ {
405
+ class: "prose prose-zinc text-xs",
406
+ innerHTML: $md.inline`${source}`({
407
+ row: ctx.row.original,
408
+ index: BigInt(ctx.row.index),
409
+ id: ctx.column.id
410
+ })
411
+ }
412
+ ) });
406
413
  },
407
414
  config: TableRendererMarkdownConfig
408
415
  }
@@ -0,0 +1,2 @@
1
+ import { type ClassValue } from 'clsx';
2
+ export declare const cn: (...classes: ReadonlyArray<ClassValue>) => string;
@@ -0,0 +1,3 @@
1
+ import { twMerge } from "tailwind-merge";
2
+ import { clsx } from "clsx";
3
+ export const cn = (...classes) => twMerge(clsx(...classes));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shwfed/nuxt",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,10 +24,6 @@
24
24
  "files": [
25
25
  "dist"
26
26
  ],
27
- "workspaces": [
28
- ".",
29
- "playground"
30
- ],
31
27
  "scripts": {
32
28
  "prepack": "nuxt-module-build build",
33
29
  "dev": "npm run dev:prepare && nuxt dev playground",
@@ -48,12 +44,16 @@
48
44
  "@tanstack/vue-table": "^8.21.3",
49
45
  "@tanstack/vue-virtual": "^3.13.18",
50
46
  "@vueuse/core": "^14.1.0",
47
+ "class-variance-authority": "^0.7.1",
48
+ "clsx": "^2.1.1",
51
49
  "date-fns": "^4.1.0",
52
50
  "defu": "^6.1.4",
53
51
  "dot-prop": "^10.1.0",
54
52
  "markdown-it": "^14.1.0",
55
53
  "reka-ui": "^2.7.0",
54
+ "tailwind-merge": "^3.4.0",
56
55
  "vue": "^3.5.27",
56
+ "vue-sonner": "^2.0.9",
57
57
  "zod": "^4.3.6"
58
58
  },
59
59
  "devDependencies": {