Copy readonly features from canvas editor to canvas reader.

This commit is contained in:
2025-02-01 13:45:16 +01:00
parent af317cb0e3
commit 154584e175
7 changed files with 244 additions and 160 deletions

View File

@@ -1,13 +1,19 @@
<script setup lang="ts">
import type { Direction, Path } from "~/shared/canvas.util";
import type { CanvasColor } from "~/types/canvas";
const props = defineProps<{
path: Path;
color?: CanvasColor;
label?: string;
}>();
<template>
<div class="absolute overflow-visible">
<div v-if="edge.label" :style="{ transform: `${labelPos} translate(-50%, -50%)` }" class="relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20">{{ edge.label }}</div>
<svg class="absolute top-0 overflow-visible h-px w-px">
<g :style="{'--canvas-color': edge.color?.hex}" class="z-0">
<g :style="`transform: translate(${path!.to.x}px, ${path!.to.y}px) scale(var(--zoom-multiplier)) rotate(${rotation[path!.side]}deg);`">
<polygon :class="style.fill" points="0,0 6.5,10.4 -6.5,10.4"></polygon>
</g>
<path :style="`stroke-width: calc(3px * var(--zoom-multiplier));`" style="stroke-linecap: butt;" :class="style.stroke" class="fill-none stroke-[4px]" :d="path!.path"></path>
</g>
</svg>
</div>
</template>
<script lang="ts">
import type { Direction } from '#shared/canvas.util';
const rotation: Record<Direction, string> = {
top: "180",
bottom: "0",
@@ -15,12 +21,24 @@ const rotation: Record<Direction, string> = {
right: "270"
};
</script>
<script setup lang="ts">
import { getPath, labelCenter } from '#shared/canvas.util';
import type { CanvasEdge, CanvasNode } from '~/types/canvas';
<template>
<g :style="{'--canvas-color': color?.hex}" class="z-0">
<path :style="`stroke-linecap: butt; stroke-width: calc(3px * var(--zoom-multiplier));`" :class="color?.class ? `stroke-light-${color.class} dark:stroke-dark-${color.class}` : ((color && color?.hex !== undefined) ? 'stroke-[color:var(--canvas-color)]' : 'stroke-light-40 dark:stroke-dark-40')" class="fill-none stroke-[4px]" :d="path.path"></path>
<g :style="`transform: translate(${path.to.x}px, ${path.to.y}px) scale(var(--zoom-multiplier)) rotate(${rotation[path.side]}deg);`">
<polygon :class="color?.class ? `fill-light-${color.class} dark:fill-dark-${color.class}` : ((color && color?.hex !== undefined) ? 'fill-[color:var(--canvas-color)]' : 'fill-light-40 dark:fill-dark-40')" points="0,0 6.5,10.4 -6.5,10.4"></polygon>
</g>
</g>
</template>
const { edge, nodes } = defineProps<{
edge: CanvasEdge
nodes: CanvasNode[]
}>();
const from = computed(() => nodes!.find(f => f.id === edge.fromNode));
const to = computed(() => nodes!.find(f => f.id === edge.toNode));
const path = computed(() => getPath(from.value!, edge.fromSide, to.value!, edge.toSide));
const labelPos = computed(() => labelCenter(from.value!, edge.fromSide, to.value!, edge.toSide));
const style = computed(() => {
return edge.color ? edge.color?.class ?
{ fill: `fill-light-${edge.color?.class} dark:fill-dark-${edge.color?.class}`, stroke: `stroke-light-${edge.color?.class} dark:stroke-dark-${edge.color?.class}` } :
{ fill: `fill-colored`, stroke: `stroke-[color:var(--canvas-color)]` } :
{ stroke: `stroke-light-40 dark:stroke-dark-40`, fill: `fill-light-40 dark:fill-dark-40` }
});
</script>

View File

@@ -1,44 +1,28 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue/dist/iconify.js';
import type { CanvasNode } from '~/types/canvas';
interface Props {
node: CanvasNode;
}
const props = defineProps<Props>();
const size = Math.max(props.node.width, props.node.height);
const colors = computed(() => {
if(props.node.color)
{
const color = props.node.color;
return color?.class ? { bg: `bg-light-${color?.class} dark:bg-dark-${color?.class}`, border: `border-light-${color?.class} dark:border-dark-${color?.class}`} : { bg: `bg-colored`, border: `border-[color:var(--canvas-color)]` };
}
else
{
return { border: `border-light-40 dark:border-dark-40`, bg: `bg-light-40 dark:bg-dark-40` };
}
})
</script>
<style>
.bg-colored
{
--tw-bg-opacity: 1;
background-color: rgba(from var(--canvas-color) r g b / var(--tw-bg-opacity));
}
</style>
<template>
<div class="absolute" :style="{transform: `translate(${node.x}px, ${node.y}px)`, width: `${node.width}px`, height: `${node.height}px`, '--canvas-color': node.color?.hex}" :class="{'-z-10': node.type === 'group', 'z-10': node.type !== 'group'}">
<div :class="[colors.border]" class="border-2 bg-light-20 dark:bg-dark-20 overflow-hidden contain-strict w-full h-full flex">
<div class="w-full h-full py-2 px-4 flex !bg-opacity-[0.07]" :class="colors.bg">
<div :class="[style.border]" class="outline-0 transition-[outline-width] border-2 bg-light-20 dark:bg-dark-20 w-full h-full hover:outline-4">
<div class="w-full h-full py-2 px-4 flex !bg-opacity-[0.07] overflow-auto" :class="style.bg">
<div v-if="node.text?.length > 0" class="flex items-center">
<MarkdownRenderer :content="node.text" />
</div>
</div>
</div>
<div v-if="node.type === 'group' && node.label !== undefined" :class="[colors.border]" style="max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))" class="origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] mb-2 px-2 py-1 font-thin">{{ node.label }}</div>
<div v-if="node.type === 'group' && node.label !== undefined" :class="style.border" style="max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))" class="origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] mb-2 px-2 py-1 font-thin">{{ node.label }}</div>
</div>
</template>
</template>
<script setup lang="ts">
import type { CanvasNode } from '~/types/canvas';
const { node } = defineProps<{
node: CanvasNode
zoom: number
}>();
const style = computed(() => {
return node.color ? node.color?.class ?
{ bg: `bg-light-${node.color?.class} dark:bg-dark-${node.color?.class}`, border: `border-light-${node.color?.class} dark:border-dark-${node.color?.class}` } :
{ bg: `bg-colored`, border: `border-[color:var(--canvas-color)]` } :
{ border: `border-light-40 dark:border-dark-40`, bg: `bg-light-40 dark:bg-dark-40` }
});
</script>

View File

@@ -1,41 +0,0 @@
<template>
<div class="absolute top-0 left-0 w-full h-full origin-center pointer-events-none *:pointer-events-auto *:select-none" v-if="canvas">
<div>
<CanvasNode v-for="node of canvas.nodes" :key="node.id" :node="node" />
</div>
<template v-for="edge of canvas.edges">
<div :key="edge.id" v-if="edge.label" class="absolute z-10"
:style="{ transform: labelCenter(getNode(canvas.nodes, edge.fromNode)!, edge.fromSide, getNode(canvas.nodes, edge.toNode)!, edge.toSide) }">
<div class="relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 -translate-x-[50%] -translate-y-[50%]">{{ edge.label }}</div>
</div>
</template>
<svg class="absolute top-0 left-0 overflow-visible w-full h-full origin-top pointer-events-none">
<CanvasEdge v-for="edge of canvas.edges" :key="edge.id"
:path="getPath(getNode(canvas.nodes, edge.fromNode)!, edge.fromSide, getNode(canvas.nodes, edge.toNode)!, edge.toSide)!"
:color="edge.color" :label="edge.label" />
</svg>
</div>
</template>
<script setup lang="ts">
import { labelCenter, getNode, getPath } from '#shared/canvas.util';
import type { CanvasContent } from '~/types/content';
import type { CanvasContent as Canvas } from '~/types/canvas';
const { path } = defineProps<{
path: string
}>();
const { content, get } = useContent();
const overview = computed(() => content.value.find(e => e.path === path) as CanvasContent | undefined);
const loading = ref(false);
if(overview.value && !overview.value.content)
{
loading.value = true;
await get(path);
loading.value = false;
}
const canvas = computed(() => overview.value && overview.value.content ? overview.value.content : undefined);
</script>