@rimelight/ui 0.0.43 → 0.0.45
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/README.md +14 -12
- package/package.json +8 -10
- package/src/components/avatar/RLAAvatar.astro +4 -12
- package/src/components/badge/RLABadge.astro +2 -1
- package/src/components/badge/badge.theme.ts +0 -4
- package/src/components/banner/RLABanner.astro +1 -1
- package/src/components/banner/banner.theme.ts +1 -1
- package/src/components/breadcrumb/RLABreadcrumb.astro +2 -2
- package/src/components/button/RLAButton.astro +4 -1
- package/src/components/button/RLSButton.tsx +1 -1
- package/src/components/button/button.theme.ts +1 -5
- package/src/components/callout/RLACallout.astro +7 -5
- package/src/components/callout/callout.theme.ts +1 -5
- package/src/components/card/card.theme.ts +3 -3
- package/src/components/carousel/RLACarousel.astro +2 -2
- package/src/components/carousel/carousel.theme.ts +2 -2
- package/src/components/chart/RLAChart.astro +1 -1
- package/src/components/checkbox/RLACheckbox.astro +2 -1
- package/src/components/checkbox/checkbox.theme.ts +0 -4
- package/src/components/chip/RLAChip.astro +2 -1
- package/src/components/chip/chip.theme.ts +0 -4
- package/src/components/collapsible/RLACollapsible.astro +1 -1
- package/src/components/color-area/RLAColorArea.astro +1 -0
- package/src/components/color-area/color-area.theme.ts +1 -5
- package/src/components/color-field/RLAColorField.astro +1 -0
- package/src/components/color-field/color-field.theme.ts +1 -5
- package/src/components/color-slider/RLAColorSlider.astro +1 -0
- package/src/components/color-slider/color-slider.theme.ts +1 -5
- package/src/components/dashboard-group/RLADashboardGroup.astro +5 -7
- package/src/components/dashboard-group/dashboard-group.theme.ts +1 -1
- package/src/components/dashboard-group/dashboard-group.ts +1 -1
- package/src/components/dashboard-navbar/RLADashboardNavbar.astro +4 -4
- package/src/components/dashboard-navbar/dashboard-navbar.theme.ts +3 -3
- package/src/components/dashboard-navbar/dashboard-navbar.ts +1 -1
- package/src/components/dashboard-panel/RLADashboardPanel.astro +9 -8
- package/src/components/dashboard-panel/dashboard-panel.theme.ts +1 -1
- package/src/components/dashboard-sidebar/RLADashboardSidebar.astro +52 -20
- package/src/components/dashboard-sidebar/dashboard-sidebar.theme.ts +6 -5
- package/src/components/dashboard-sidebar-collapse/RLADashboardSidebarCollapse.astro +1 -0
- package/src/components/drawer/RLADrawer.astro +1 -1
- package/src/components/dropdown-menu/dropdown-menu.theme.ts +2 -2
- package/src/components/footer/RLAFooter.astro +2 -0
- package/src/components/footer/footer.theme.ts +0 -8
- package/src/components/gamepad/RLAGamepad.astro +1 -1
- package/src/components/head/UIHead.astro +1 -2
- package/src/components/header/header.theme.ts +1 -1
- package/src/components/icon/RLAIcon.astro +2 -5
- package/src/components/icon/RLSIcon.tsx +2 -2
- package/src/components/icon/RLVIcon.vue +18 -6
- package/src/components/icon/icon.theme.ts +1 -1
- package/src/components/image/image.theme.ts +1 -1
- package/src/components/input/RLAInput.astro +2 -1
- package/src/components/input/input.theme.ts +0 -4
- package/src/components/input-menu/RLAInputMenu.astro +2 -2
- package/src/components/input-menu/input-menu.theme.ts +1 -1
- package/src/components/input-rating/input-rating.theme.ts +2 -2
- package/src/components/kbd/RLAKbd.astro +2 -1
- package/src/components/kbd/kbd.theme.ts +0 -4
- package/src/components/keyboard/RLAKeyboard.astro +1 -1
- package/src/components/link/RLALink.astro +1 -0
- package/src/components/link/link.theme.ts +0 -4
- package/src/components/link-group/RLALinkGroup.astro +1 -1
- package/src/components/link-group/link-group.theme.ts +1 -10
- package/src/components/locale-selector/RLALocaleSelector.astro +4 -36
- package/src/components/locale-selector/locale-selector.theme.ts +3 -11
- package/src/components/logo/RLALogo.astro +1 -2
- package/src/components/modal/RLAModal.astro +8 -5
- package/src/components/modal/RLSModal.tsx +17 -12
- package/src/components/modal/modal.theme.ts +5 -4
- package/src/components/navigation-menu/RLANavigationMenu.astro +17 -21
- package/src/components/navigation-menu/navigation-menu.theme.ts +3 -7
- package/src/components/pagination/RLAPagination.astro +2 -2
- package/src/components/pagination/pagination.theme.ts +1 -1
- package/src/components/popover/RLAPopover.astro +39 -0
- package/src/components/progress/RLAProgress.astro +2 -0
- package/src/components/progress/progress.theme.ts +0 -4
- package/src/components/scroll-area/scroll-area.theme.ts +1 -1
- package/src/components/scroll-to-top/RLAScrollToTop.astro +6 -5
- package/src/components/scroll-to-top/RLVScrollToTop.vue +7 -7
- package/src/components/scroll-to-top/scroll-to-top.theme.ts +3 -7
- package/src/components/search/RLASearch.astro +3 -3
- package/src/components/select/RLASelect.astro +96 -528
- package/src/components/select/RLSSelect.tsx +68 -14
- package/src/components/select/RLVSelect.vue +57 -0
- package/src/components/select/select.theme.ts +11 -96
- package/src/components/shortcuts/RLAShortcuts.astro +9 -9
- package/src/components/sidebar/RLASidebar.astro +3 -3
- package/src/components/slideover/RLASlideover.astro +1 -1
- package/src/components/slider/RLASlider.astro +2 -1
- package/src/components/slider/slider.theme.ts +1 -5
- package/src/components/spinner/RLASpinner.astro +2 -1
- package/src/components/spinner/spinner.theme.ts +1 -5
- package/src/components/splitter/splitter.theme.ts +1 -1
- package/src/components/stepper/RLAStepper.astro +8 -8
- package/src/components/stepper/stepper.theme.ts +6 -7
- package/src/components/steps/RLASteps.astro +3 -3
- package/src/components/switch/RLASwitch.astro +2 -1
- package/src/components/switch/switch.theme.ts +0 -4
- package/src/components/table/table.theme.ts +1 -1
- package/src/components/table-of-contents/RLATableOfContents.astro +5 -5
- package/src/components/theme-selector/RLAThemeSelector.astro +16 -14
- package/src/components/theme-selector/theme-selector.theme.ts +2 -2
- package/src/components/toast/RLAToast.astro +6 -6
- package/src/components/toast/store.ts +1 -1
- package/src/components/tooltip/tooltip.theme.ts +1 -1
- package/src/icons.raw.ts +67 -0
- package/src/icons.ts +31 -64
- package/src/index.ts +19 -18
- package/src/preset.ts +110 -108
- package/src/resolver.ts +127 -15
- package/src/shortcuts.ts +103 -84
- package/src/stores.ts +22 -0
- package/src/types.ts +27 -9
- package/src/virtual.d.ts +4 -0
- package/src/components/editor/PageEditor.vue +0 -459
- package/src/components/editor/PageMention.vue +0 -87
- package/src/components/editor/PagePropertiesEditor.vue +0 -358
- package/src/components/editor/PagePropertiesRenderer.vue +0 -285
- package/src/components/editor/PageRenderer.vue +0 -155
- package/src/components/editor/PageSurround.vue +0 -130
- package/src/components/editor/PageVersionSelector.vue +0 -371
- package/src/components/editor/blocks/AddBlockModal.vue +0 -196
- package/src/components/editor/blocks/Block.vue +0 -142
- package/src/components/editor/blocks/BlockEditRenderer.vue +0 -26
- package/src/components/editor/blocks/BlockEditor.vue +0 -141
- package/src/components/editor/blocks/BlockViewRenderer.vue +0 -71
- package/src/components/editor/blocks/TextRenderer.vue +0 -31
- package/src/components/editor/blocks/editor/CalloutBlockEditor.vue +0 -53
- package/src/components/editor/blocks/editor/ImageBlockEditor.vue +0 -55
- package/src/components/editor/blocks/editor/ParagraphBlockEditor.vue +0 -31
- package/src/components/editor/blocks/editor/SectionBlockEditor.vue +0 -65
- package/src/components/editor/blocks/nodes/LinkNode.vue +0 -28
- package/src/components/editor/blocks/nodes/TextNode.vue +0 -22
- package/src/components/editor/blocks/renderer/CalloutBlockRenderer.vue +0 -65
- package/src/components/editor/blocks/renderer/ImageBlockRenderer.vue +0 -20
- package/src/components/editor/blocks/renderer/ParagraphBlockRenderer.vue +0 -21
- package/src/components/editor/blocks/renderer/SectionBlockRenderer.vue +0 -55
- package/src/components/editor/composables/injectionKeys.ts +0 -3
- package/src/components/editor/composables/useBlockEditor.ts +0 -261
- package/src/components/editor/composables/usePageEditor.ts +0 -97
- package/src/components/editor/modals/CreatePageModal.vue +0 -160
- package/src/components/editor/modals/DeletePageModal.vue +0 -116
- package/src/components/editor/modals/PageTreeModal.vue +0 -275
- package/src/components/editor/types/blocks.ts +0 -100
- package/src/components/editor/types/pages.ts +0 -89
- package/src/components/editor/types/schemas.ts +0 -36
- package/src/components/editor/utils/blocks.ts +0 -42
- package/src/components/editor/utils/editorHelpers.ts +0 -24
- package/src/components/editor/utils/page.ts +0 -219
- package/src/components/editor/utils/richTextHelpers.ts +0 -35
- package/src/components/editor/views/PageEditView.vue +0 -195
- package/src/components/editor/views/PageLiveView.vue +0 -90
- package/src/components/editor/views/PageReviewView.vue +0 -308
- package/src/components/icon/resolver.ts +0 -23
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import type { ImageBlockProps } from "../../types/blocks"
|
|
4
|
-
import RLVInput from "../../../input/RLVInput.vue"
|
|
5
|
-
|
|
6
|
-
const props = defineProps<{ props: ImageBlockProps }>()
|
|
7
|
-
const emit = defineEmits<{ "update:props": [value: ImageBlockProps] }>()
|
|
8
|
-
|
|
9
|
-
const src = computed({
|
|
10
|
-
get: () => props.props.src || "",
|
|
11
|
-
set: (val: string) => emit("update:props", { ...props.props, src: val })
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const alt = computed({
|
|
15
|
-
get: () => props.props.alt || "",
|
|
16
|
-
set: (val: string) => emit("update:props", { ...props.props, alt: val })
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
const caption = computed({
|
|
20
|
-
get: () => props.props.caption || "",
|
|
21
|
-
set: (val: string) => emit("update:props", { ...props.props, caption: val })
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
defineOptions({ name: "ImageBlockEditor" })
|
|
25
|
-
</script>
|
|
26
|
-
|
|
27
|
-
<template>
|
|
28
|
-
<div
|
|
29
|
-
class="w-full flex flex-col gap-3 p-4 border border-default rounded-xl bg-white dark:bg-neutral-900"
|
|
30
|
-
>
|
|
31
|
-
<div class="flex flex-col gap-1">
|
|
32
|
-
<label class="text-xs font-bold text-dimmed uppercase">Image URL</label>
|
|
33
|
-
<RLVInput v-model="src" placeholder="https://..." class="w-full" />
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
37
|
-
<div class="flex flex-col gap-1">
|
|
38
|
-
<label class="text-xs font-bold text-dimmed uppercase">Alt Text</label>
|
|
39
|
-
<RLVInput v-model="alt" placeholder="Alt description" class="w-full" />
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div class="flex flex-col gap-1">
|
|
43
|
-
<label class="text-xs font-bold text-dimmed uppercase">Caption</label>
|
|
44
|
-
<RLVInput v-model="caption" placeholder="Image caption" class="w-full" />
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
|
|
48
|
-
<div
|
|
49
|
-
v-if="src"
|
|
50
|
-
class="mt-2 flex justify-center bg-neutral-100 dark:bg-neutral-800 p-2 rounded-lg"
|
|
51
|
-
>
|
|
52
|
-
<img :src="src" :alt="alt" class="max-h-48 object-cover rounded border border-default" />
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</template>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import type { ParagraphBlockProps } from "../../types/blocks"
|
|
4
|
-
import { richTextToHtml, parseHtmlToRichText } from "../../utils/richTextHelpers"
|
|
5
|
-
|
|
6
|
-
const props = defineProps<{ props: ParagraphBlockProps }>()
|
|
7
|
-
const emit = defineEmits<{ "update:props": [value: ParagraphBlockProps] }>()
|
|
8
|
-
|
|
9
|
-
const textValue = computed({
|
|
10
|
-
get: () => richTextToHtml(props.props?.text || []),
|
|
11
|
-
set: (val: string) => {
|
|
12
|
-
emit("update:props", {
|
|
13
|
-
...props.props,
|
|
14
|
-
text: parseHtmlToRichText(val)
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
defineOptions({ name: "ParagraphBlockEditor" })
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<template>
|
|
23
|
-
<div class="w-full">
|
|
24
|
-
<textarea
|
|
25
|
-
v-model="textValue"
|
|
26
|
-
placeholder="Type paragraph text here..."
|
|
27
|
-
rows="3"
|
|
28
|
-
class="w-full p-3 bg-white dark:bg-neutral-900 border border-default rounded-lg text-sm text-neutral-900 dark:text-neutral-100 focus:outline-none focus:ring-2 focus:ring-primary resize-y"
|
|
29
|
-
/>
|
|
30
|
-
</div>
|
|
31
|
-
</template>
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import type { SectionBlockProps } from "../../types/blocks"
|
|
4
|
-
import RLVInput from "../../../input/RLVInput.vue"
|
|
5
|
-
import RLVButton from "../../../button/RLVButton.vue"
|
|
6
|
-
import { useI18n } from "../../utils/editorHelpers"
|
|
7
|
-
|
|
8
|
-
import BlockEditRenderer from "../BlockEditRenderer.vue"
|
|
9
|
-
|
|
10
|
-
const props = defineProps<{ props: SectionBlockProps; containerId?: string | null }>()
|
|
11
|
-
const emit = defineEmits<{ "update:props": [value: SectionBlockProps] }>()
|
|
12
|
-
|
|
13
|
-
const { t } = useI18n()
|
|
14
|
-
|
|
15
|
-
const title = computed({
|
|
16
|
-
get: () => props.props.title || "",
|
|
17
|
-
set: (val: string) => emit("update:props", { ...props.props, title: val })
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const description = computed({
|
|
21
|
-
get: () => props.props.description || "",
|
|
22
|
-
set: (val: string) => emit("update:props", { ...props.props, description: val })
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
const level = computed({
|
|
26
|
-
get: () => props.props.level || 2,
|
|
27
|
-
set: (val: number) => emit("update:props", { ...props.props, level: val as any })
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const children = computed({
|
|
31
|
-
get: () => props.props.children || [],
|
|
32
|
-
set: (val: any[]) => emit("update:props", { ...props.props, children: val })
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
defineOptions({ name: "SectionBlockEditor" })
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<template>
|
|
39
|
-
<div
|
|
40
|
-
class="w-full flex flex-col gap-4 border border-default rounded-xl p-4 bg-neutral-50/50 dark:bg-neutral-900/30"
|
|
41
|
-
>
|
|
42
|
-
<div class="flex items-center gap-3">
|
|
43
|
-
<select
|
|
44
|
-
v-model.number="level"
|
|
45
|
-
class="bg-white dark:bg-neutral-800 border border-default rounded-lg px-2 py-1 text-xs font-bold focus:outline-none"
|
|
46
|
-
>
|
|
47
|
-
<option :value="1">H1</option>
|
|
48
|
-
<option :value="2">H2</option>
|
|
49
|
-
<option :value="3">H3</option>
|
|
50
|
-
<option :value="4">H4</option>
|
|
51
|
-
</select>
|
|
52
|
-
<RLVInput v-model="title" placeholder="Section Title" class="flex-1 font-bold text-lg" />
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<RLVInput
|
|
56
|
-
v-model="description"
|
|
57
|
-
placeholder="Section description (optional)..."
|
|
58
|
-
class="text-sm text-dimmed"
|
|
59
|
-
/>
|
|
60
|
-
|
|
61
|
-
<div class="pl-4 border-l-2 border-primary-500/30 flex flex-col gap-4 mt-2">
|
|
62
|
-
<BlockEditRenderer v-model:blocks="children" :container-id="containerId" />
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</template>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import { useI18n } from "../../utils/editorHelpers"
|
|
4
|
-
import { getLocalizedContent } from "../../utils/page"
|
|
5
|
-
|
|
6
|
-
const props = defineProps<{ node: any }>()
|
|
7
|
-
const { locale } = useI18n()
|
|
8
|
-
|
|
9
|
-
const href = computed(() => props.node?.props?.href || props.node?.href || props.node?.to || "#")
|
|
10
|
-
const target = computed(() => props.node?.props?.target || props.node?.target || "_self")
|
|
11
|
-
const contentText = computed(() => {
|
|
12
|
-
const n = props.node
|
|
13
|
-
const val = n?.props?.content ?? n?.content ?? n?.label ?? href.value
|
|
14
|
-
return getLocalizedContent(val, locale.value)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
defineOptions({ name: "LinkNode" })
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<template>
|
|
21
|
-
<a
|
|
22
|
-
:href="href"
|
|
23
|
-
:target="target"
|
|
24
|
-
class="text-primary underline hover:text-primary-600 transition-colors"
|
|
25
|
-
>
|
|
26
|
-
{{ contentText }}
|
|
27
|
-
</a>
|
|
28
|
-
</template>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import { useI18n } from "../../utils/editorHelpers"
|
|
4
|
-
import { getLocalizedContent } from "../../utils/page"
|
|
5
|
-
|
|
6
|
-
const props = defineProps<{ node: any }>()
|
|
7
|
-
const { locale } = useI18n()
|
|
8
|
-
|
|
9
|
-
const textContent = computed(() => {
|
|
10
|
-
const n = props.node
|
|
11
|
-
if (!n) return ""
|
|
12
|
-
if (typeof n === "string") return n
|
|
13
|
-
const val = n.props?.content ?? n.content ?? n.text ?? n.value
|
|
14
|
-
return getLocalizedContent(val, locale.value)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
defineOptions({ name: "TextNode" })
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<template>
|
|
21
|
-
<span>{{ textContent }}</span>
|
|
22
|
-
</template>
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import BlockViewRenderer from "../BlockViewRenderer.vue"
|
|
4
|
-
|
|
5
|
-
const props = defineProps<{ props: any }>()
|
|
6
|
-
|
|
7
|
-
const calloutProps = computed(() => props.props || {})
|
|
8
|
-
const calloutChildren = computed(() => {
|
|
9
|
-
const p = props.props
|
|
10
|
-
if (!p) return []
|
|
11
|
-
return p.children || p.blocks || p.slots?.default || []
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const variantClasses = computed(() => {
|
|
15
|
-
switch (calloutProps.value.variant) {
|
|
16
|
-
case "success":
|
|
17
|
-
return "bg-green-500/10 border-green-500/30 text-green-700 dark:text-green-300"
|
|
18
|
-
case "warning":
|
|
19
|
-
return "bg-amber-500/10 border-amber-500/30 text-amber-700 dark:text-amber-300"
|
|
20
|
-
case "error":
|
|
21
|
-
return "bg-red-500/10 border-red-500/30 text-red-700 dark:text-red-300"
|
|
22
|
-
case "commentary":
|
|
23
|
-
return "bg-purple-500/10 border-purple-500/30 text-purple-700 dark:text-purple-300"
|
|
24
|
-
case "ideation":
|
|
25
|
-
return "bg-indigo-500/10 border-indigo-500/30 text-indigo-700 dark:text-indigo-300"
|
|
26
|
-
case "source":
|
|
27
|
-
return "bg-neutral-500/10 border-neutral-500/30 text-neutral-700 dark:text-neutral-300"
|
|
28
|
-
default:
|
|
29
|
-
return "bg-blue-500/10 border-blue-500/30 text-blue-700 dark:text-blue-300"
|
|
30
|
-
}
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
const iconName = computed(() => {
|
|
34
|
-
switch (calloutProps.value.variant) {
|
|
35
|
-
case "success":
|
|
36
|
-
return "i-lucide-check-circle"
|
|
37
|
-
case "warning":
|
|
38
|
-
return "i-lucide-alert-triangle"
|
|
39
|
-
case "error":
|
|
40
|
-
return "i-lucide-alert-circle"
|
|
41
|
-
case "commentary":
|
|
42
|
-
return "i-lucide-message-square"
|
|
43
|
-
case "ideation":
|
|
44
|
-
return "i-lucide-lightbulb"
|
|
45
|
-
case "source":
|
|
46
|
-
return "i-lucide-file-code"
|
|
47
|
-
default:
|
|
48
|
-
return "i-lucide-info"
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
defineOptions({ name: "CalloutBlockRenderer" })
|
|
53
|
-
</script>
|
|
54
|
-
|
|
55
|
-
<template>
|
|
56
|
-
<div class="p-4 rounded-xl border flex gap-3 my-4 backdrop-blur-sm" :class="variantClasses">
|
|
57
|
-
<span :class="[iconName, 'size-5 shrink-0 mt-0.5']" />
|
|
58
|
-
<div class="flex-1 min-w-0">
|
|
59
|
-
<BlockViewRenderer
|
|
60
|
-
v-if="calloutChildren && calloutChildren.length"
|
|
61
|
-
:blocks="calloutChildren"
|
|
62
|
-
/>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</template>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import type { ImageBlockProps } from "../../types/blocks"
|
|
3
|
-
|
|
4
|
-
defineProps<{ props: ImageBlockProps }>()
|
|
5
|
-
defineOptions({ name: "ImageBlockRenderer" })
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<figure class="my-6 flex flex-col items-center">
|
|
10
|
-
<img
|
|
11
|
-
v-if="props.src"
|
|
12
|
-
:src="props.src"
|
|
13
|
-
:alt="props.alt || ''"
|
|
14
|
-
class="rounded-xl border border-default shadow-md max-w-full h-auto object-cover max-h-[500px]"
|
|
15
|
-
/>
|
|
16
|
-
<figcaption v-if="props.caption" class="text-xs text-dimmed mt-2 text-center italic">
|
|
17
|
-
{{ props.caption }}
|
|
18
|
-
</figcaption>
|
|
19
|
-
</figure>
|
|
20
|
-
</template>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import TextRenderer from "../TextRenderer.vue"
|
|
4
|
-
|
|
5
|
-
const props = defineProps<{ props: any }>()
|
|
6
|
-
const textContent = computed(() => {
|
|
7
|
-
const p = props.props
|
|
8
|
-
if (!p) return ""
|
|
9
|
-
return p.text ?? p.content ?? p.value ?? ""
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
defineOptions({ name: "ParagraphBlockRenderer" })
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<template>
|
|
16
|
-
<p
|
|
17
|
-
class="text-base text-neutral-800 dark:text-neutral-200 leading-relaxed my-2 whitespace-pre-wrap"
|
|
18
|
-
>
|
|
19
|
-
<TextRenderer :content="textContent" />
|
|
20
|
-
</p>
|
|
21
|
-
</template>
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue"
|
|
3
|
-
import { useI18n } from "../../utils/editorHelpers"
|
|
4
|
-
import { getLocalizedContent } from "../../utils/page"
|
|
5
|
-
|
|
6
|
-
import BlockViewRenderer from "../BlockViewRenderer.vue"
|
|
7
|
-
|
|
8
|
-
const props = defineProps<{ props: any }>()
|
|
9
|
-
const { locale } = useI18n()
|
|
10
|
-
|
|
11
|
-
const headingTag = computed(() => `h${props.props?.level || 2}`)
|
|
12
|
-
const headingClasses = computed(() => {
|
|
13
|
-
switch (Number(props.props?.level || 2)) {
|
|
14
|
-
case 1:
|
|
15
|
-
return "text-3xl font-extrabold tracking-tight mt-8 mb-4 border-b pb-2 text-neutral-900 dark:text-white"
|
|
16
|
-
case 2:
|
|
17
|
-
return "text-2xl font-bold tracking-tight mt-6 mb-3 text-neutral-900 dark:text-white"
|
|
18
|
-
case 3:
|
|
19
|
-
return "text-xl font-semibold mt-4 mb-2 text-neutral-900 dark:text-white"
|
|
20
|
-
default:
|
|
21
|
-
return "text-lg font-medium mt-3 mb-2 text-neutral-900 dark:text-white"
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
const titleText = computed(() => getLocalizedContent(props.props?.title, locale.value))
|
|
26
|
-
const descriptionText = computed(() => getLocalizedContent(props.props?.description, locale.value))
|
|
27
|
-
const sectionChildren = computed(() => {
|
|
28
|
-
const p = props.props
|
|
29
|
-
if (!p) return []
|
|
30
|
-
return p.children || p.blocks || p.slots?.default || []
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
defineOptions({ name: "SectionBlockRenderer" })
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
<template>
|
|
37
|
-
<div class="my-4">
|
|
38
|
-
<component
|
|
39
|
-
:is="headingTag"
|
|
40
|
-
v-if="titleText"
|
|
41
|
-
:class="headingClasses"
|
|
42
|
-
:id="typeof titleText === 'string' ? titleText.toLowerCase().replace(/\s+/g, '-') : undefined"
|
|
43
|
-
>
|
|
44
|
-
{{ titleText }}
|
|
45
|
-
</component>
|
|
46
|
-
|
|
47
|
-
<p v-if="descriptionText" class="text-sm text-dimmed mb-4 italic">
|
|
48
|
-
{{ descriptionText }}
|
|
49
|
-
</p>
|
|
50
|
-
|
|
51
|
-
<div v-if="sectionChildren && sectionChildren.length" class="flex flex-col gap-2">
|
|
52
|
-
<BlockViewRenderer :blocks="sectionChildren" />
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</template>
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { type Ref, computed, ref, shallowRef } from "vue"
|
|
2
|
-
import type { Block } from "../types/pages"
|
|
3
|
-
|
|
4
|
-
function findBlockLocation(
|
|
5
|
-
blocks: Block[],
|
|
6
|
-
id: string
|
|
7
|
-
): { parentArray: Block[]; index: number } | null {
|
|
8
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
9
|
-
const block = blocks[i]
|
|
10
|
-
if (!block) continue
|
|
11
|
-
if (block.id === id) {
|
|
12
|
-
return { parentArray: blocks, index: i }
|
|
13
|
-
}
|
|
14
|
-
if ("children" in block.props && Array.isArray(block.props.children)) {
|
|
15
|
-
const result = findBlockLocation(block.props.children, id)
|
|
16
|
-
if (result) return result
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function regenerateIds(block: Block): void {
|
|
23
|
-
block.id =
|
|
24
|
-
typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
|
|
25
|
-
? crypto.randomUUID()
|
|
26
|
-
: Math.random().toString(36).substring(2)
|
|
27
|
-
|
|
28
|
-
if ("children" in block.props && Array.isArray(block.props.children)) {
|
|
29
|
-
block.props.children.forEach((child: Block) => regenerateIds(child))
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function createDefaultBlock(type: Block["type"]): Block {
|
|
34
|
-
const id =
|
|
35
|
-
typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
|
|
36
|
-
? crypto.randomUUID()
|
|
37
|
-
: Math.random().toString(36).substring(2)
|
|
38
|
-
switch (type) {
|
|
39
|
-
case "SectionBlock":
|
|
40
|
-
return {
|
|
41
|
-
id,
|
|
42
|
-
type: "SectionBlock",
|
|
43
|
-
props: {
|
|
44
|
-
level: 2,
|
|
45
|
-
title: "New Section",
|
|
46
|
-
children: []
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
case "ParagraphBlock":
|
|
50
|
-
return {
|
|
51
|
-
id,
|
|
52
|
-
type: "ParagraphBlock",
|
|
53
|
-
props: {
|
|
54
|
-
text: []
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
case "CalloutBlock":
|
|
58
|
-
return {
|
|
59
|
-
id,
|
|
60
|
-
type: "CalloutBlock",
|
|
61
|
-
props: {
|
|
62
|
-
variant: "info",
|
|
63
|
-
children: []
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
case "ImageBlock":
|
|
67
|
-
return {
|
|
68
|
-
id,
|
|
69
|
-
type: "ImageBlock",
|
|
70
|
-
props: {
|
|
71
|
-
src: "https://placehold.co/600x400",
|
|
72
|
-
alt: "Placeholder Image"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
default:
|
|
76
|
-
return {
|
|
77
|
-
id,
|
|
78
|
-
type: "ParagraphBlock",
|
|
79
|
-
props: { text: [] }
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function useBlockEditor(
|
|
85
|
-
initialBlocks: Ref<Block[]>,
|
|
86
|
-
{ maxHistorySize = 100, onMutation }: { maxHistorySize?: number; onMutation?: () => void } = {}
|
|
87
|
-
) {
|
|
88
|
-
const history = shallowRef<Block[][]>([])
|
|
89
|
-
const future = shallowRef<Block[][]>([])
|
|
90
|
-
const committedBlocks = ref<Block[]>(JSON.parse(JSON.stringify(initialBlocks.value)))
|
|
91
|
-
|
|
92
|
-
const canUndo = computed(() => history.value.length > 0)
|
|
93
|
-
const canRedo = computed(() => future.value.length > 0)
|
|
94
|
-
|
|
95
|
-
const captureSnapshot = () => {
|
|
96
|
-
const snapshot: Block[] = JSON.parse(JSON.stringify(initialBlocks.value))
|
|
97
|
-
future.value = []
|
|
98
|
-
const newHistory = [...history.value, snapshot]
|
|
99
|
-
if (newHistory.length > maxHistorySize) {
|
|
100
|
-
newHistory.shift()
|
|
101
|
-
}
|
|
102
|
-
history.value = newHistory
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const executeMutation = (mutationFn: () => void) => {
|
|
106
|
-
if (onMutation) {
|
|
107
|
-
onMutation()
|
|
108
|
-
} else {
|
|
109
|
-
captureSnapshot()
|
|
110
|
-
}
|
|
111
|
-
mutationFn()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const undo = () => {
|
|
115
|
-
if (history.value.length === 0) return
|
|
116
|
-
const currentState: Block[] = JSON.parse(JSON.stringify(initialBlocks.value))
|
|
117
|
-
future.value = [currentState, ...future.value]
|
|
118
|
-
const previousState = history.value[history.value.length - 1]
|
|
119
|
-
if (previousState) {
|
|
120
|
-
initialBlocks.value.splice(0, initialBlocks.value.length, ...previousState)
|
|
121
|
-
const newHistory = [...history.value]
|
|
122
|
-
newHistory.pop()
|
|
123
|
-
history.value = newHistory
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const redo = () => {
|
|
128
|
-
if (future.value.length === 0) return
|
|
129
|
-
const currentState: Block[] = JSON.parse(JSON.stringify(initialBlocks.value))
|
|
130
|
-
let newHistory = [...history.value, currentState]
|
|
131
|
-
if (newHistory.length > maxHistorySize) {
|
|
132
|
-
newHistory.shift()
|
|
133
|
-
}
|
|
134
|
-
history.value = newHistory
|
|
135
|
-
const nextState = future.value[0]
|
|
136
|
-
if (nextState) {
|
|
137
|
-
initialBlocks.value.splice(0, initialBlocks.value.length, ...nextState)
|
|
138
|
-
const newFuture = [...future.value]
|
|
139
|
-
newFuture.shift()
|
|
140
|
-
future.value = newFuture
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const updateBlockProps = (id: string, newProps: Record<string, any>) => {
|
|
145
|
-
executeMutation(() => {
|
|
146
|
-
const loc = findBlockLocation(initialBlocks.value, id)
|
|
147
|
-
if (!loc) return
|
|
148
|
-
const oldBlock = loc.parentArray[loc.index]
|
|
149
|
-
if (!oldBlock) return
|
|
150
|
-
Object.assign(oldBlock.props, newProps)
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const removeBlock = (id: string) => {
|
|
155
|
-
executeMutation(() => {
|
|
156
|
-
const loc = findBlockLocation(initialBlocks.value, id)
|
|
157
|
-
if (!loc) return
|
|
158
|
-
loc.parentArray.splice(loc.index, 1)
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const moveBlock = (id: string, direction: -1 | 1) => {
|
|
163
|
-
executeMutation(() => {
|
|
164
|
-
const loc = findBlockLocation(initialBlocks.value, id)
|
|
165
|
-
if (!loc) return
|
|
166
|
-
const { parentArray, index } = loc
|
|
167
|
-
const newIndex = index + direction
|
|
168
|
-
if (newIndex >= 0 && newIndex < parentArray.length) {
|
|
169
|
-
const movedBlock = parentArray.splice(index, 1)[0]
|
|
170
|
-
if (movedBlock) {
|
|
171
|
-
parentArray.splice(newIndex, 0, movedBlock)
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const duplicateBlock = (id: string) => {
|
|
178
|
-
executeMutation(() => {
|
|
179
|
-
const loc = findBlockLocation(initialBlocks.value, id)
|
|
180
|
-
if (!loc) return
|
|
181
|
-
const original = loc.parentArray[loc.index]
|
|
182
|
-
const clone: Block = JSON.parse(JSON.stringify(original))
|
|
183
|
-
regenerateIds(clone)
|
|
184
|
-
loc.parentArray.splice(loc.index + 1, 0, clone)
|
|
185
|
-
})
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const insertBlock = (
|
|
189
|
-
newBlockType: Block["type"],
|
|
190
|
-
targetId: string | null = null,
|
|
191
|
-
position: "before" | "after" = "after"
|
|
192
|
-
) => {
|
|
193
|
-
executeMutation(() => {
|
|
194
|
-
const newBlock = createDefaultBlock(newBlockType)
|
|
195
|
-
if (!targetId) {
|
|
196
|
-
initialBlocks.value.push(newBlock)
|
|
197
|
-
return
|
|
198
|
-
}
|
|
199
|
-
const loc = findBlockLocation(initialBlocks.value, targetId)
|
|
200
|
-
if (!loc) return
|
|
201
|
-
const { parentArray, index } = loc
|
|
202
|
-
const insertIndex = position === "after" ? index + 1 : index
|
|
203
|
-
parentArray.splice(insertIndex, 0, newBlock)
|
|
204
|
-
})
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const commitChanges = (): Block[] => {
|
|
208
|
-
const committedSnapshot: Block[] = JSON.parse(JSON.stringify(initialBlocks.value))
|
|
209
|
-
committedBlocks.value = committedSnapshot
|
|
210
|
-
return committedSnapshot
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const relocateBlock = (
|
|
214
|
-
blockId: string,
|
|
215
|
-
targetContainerId: string | null,
|
|
216
|
-
targetIndex: number
|
|
217
|
-
) => {
|
|
218
|
-
executeMutation(() => {
|
|
219
|
-
const sourceLoc = findBlockLocation(initialBlocks.value, blockId)
|
|
220
|
-
if (!sourceLoc) return
|
|
221
|
-
const block = sourceLoc.parentArray[sourceLoc.index]
|
|
222
|
-
if (!block) return
|
|
223
|
-
sourceLoc.parentArray.splice(sourceLoc.index, 1)
|
|
224
|
-
|
|
225
|
-
let targetArray: Block[]
|
|
226
|
-
if (targetContainerId === null) {
|
|
227
|
-
targetArray = initialBlocks.value
|
|
228
|
-
} else {
|
|
229
|
-
const targetLoc = findBlockLocation(initialBlocks.value, targetContainerId)
|
|
230
|
-
if (!targetLoc) {
|
|
231
|
-
sourceLoc.parentArray.splice(sourceLoc.index, 0, block)
|
|
232
|
-
return
|
|
233
|
-
}
|
|
234
|
-
const targetBlock = targetLoc.parentArray[targetLoc.index]
|
|
235
|
-
if (!targetBlock || !("children" in targetBlock.props)) {
|
|
236
|
-
sourceLoc.parentArray.splice(sourceLoc.index, 0, block)
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
targetArray = targetBlock.props.children
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const safeIndex = Math.max(0, Math.min(targetIndex, targetArray.length))
|
|
243
|
-
targetArray.splice(safeIndex, 0, block)
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
updateBlockProps,
|
|
249
|
-
removeBlock,
|
|
250
|
-
moveBlock,
|
|
251
|
-
duplicateBlock,
|
|
252
|
-
insertBlock,
|
|
253
|
-
relocateBlock,
|
|
254
|
-
undo,
|
|
255
|
-
redo,
|
|
256
|
-
canUndo,
|
|
257
|
-
canRedo,
|
|
258
|
-
committedBlocks,
|
|
259
|
-
commitChanges
|
|
260
|
-
}
|
|
261
|
-
}
|