Reviewed-on: #1 Co-authored-by: Matthew L McPeak <m.mcpeak98@icloud.com> Co-committed-by: Matthew L McPeak <m.mcpeak98@icloud.com>
152 lines
4.4 KiB
Vue
152 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import { computed, onMounted, onBeforeUnmount, ref } from 'vue'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
vertical?: boolean
|
|
label?: string
|
|
height?: number
|
|
size?: number
|
|
}>(),
|
|
{
|
|
vertical: false,
|
|
height: 14,
|
|
size: 18,
|
|
},
|
|
)
|
|
|
|
// 16-leaf radial wreath, used as the vertical divider's center ornament
|
|
const radialLeaves = Array.from({ length: 16 }, (_, i) => {
|
|
const angle = i * 22.5
|
|
const isB = i % 2 === 1
|
|
return isB
|
|
? {
|
|
path: 'M340,72 C350,80 352,97 343,113 C339,108 332,94 335,77 Z',
|
|
line: { x1: 340, y1: 75, x2: 343, y2: 111 },
|
|
transform: `rotate(${angle},340,180)`,
|
|
}
|
|
: {
|
|
path: 'M340,70 C350,78 352,96 343,112 C339,107 332,93 335,76 Z',
|
|
line: { x1: 340, y1: 73, x2: 343, y2: 110 },
|
|
transform: `rotate(${angle},340,180)`,
|
|
}
|
|
})
|
|
|
|
// Running laurel: the loader's Type-A leaf rotated 90° CW and tiled, fitting
|
|
// only whole leaves across the container width (no clipped edge leaves).
|
|
const wrapRef = ref<HTMLElement | null>(null)
|
|
const uid = `ld${Math.random().toString(36).slice(2, 8)}`
|
|
const svgW = ref(800)
|
|
let ro: ResizeObserver | null = null
|
|
|
|
onMounted(() => {
|
|
if (!wrapRef.value) return
|
|
svgW.value = Math.floor(wrapRef.value.getBoundingClientRect().width)
|
|
if (typeof ResizeObserver === 'undefined') return
|
|
ro = new ResizeObserver(([entry]) => {
|
|
if (entry) svgW.value = Math.floor(entry.contentRect.width)
|
|
})
|
|
ro.observe(wrapRef.value)
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
ro?.disconnect()
|
|
})
|
|
|
|
const h = computed(() => props.height)
|
|
const k = computed(() => (h.value * 0.7) / 20)
|
|
const tileW = computed(() => Math.round(42 * k.value))
|
|
const cx = computed(() => tileW.value / 2)
|
|
const cy = computed(() => h.value * 0.55)
|
|
|
|
const tf = (x: number, y: number): [number, number] => [
|
|
cx.value + (y - 91) * k.value,
|
|
cy.value - (x - 340) * k.value,
|
|
]
|
|
|
|
const rawPts: Array<[number, number]> = [
|
|
[340, 70],
|
|
[350, 78],
|
|
[352, 96],
|
|
[343, 112],
|
|
[339, 107],
|
|
[332, 93],
|
|
[335, 76],
|
|
]
|
|
const f = (n: number) => n.toFixed(1)
|
|
|
|
const pts = computed(() => rawPts.map(([x, y]) => tf(x, y)))
|
|
|
|
const leafPath = computed(() => {
|
|
const p = pts.value
|
|
return [
|
|
`M${f(p[0]![0])} ${f(p[0]![1])}`,
|
|
`C${f(p[1]![0])} ${f(p[1]![1])} ${f(p[2]![0])} ${f(p[2]![1])} ${f(p[3]![0])} ${f(p[3]![1])}`,
|
|
`C${f(p[4]![0])} ${f(p[4]![1])} ${f(p[5]![0])} ${f(p[5]![1])} ${f(p[6]![0])} ${f(p[6]![1])}`,
|
|
'Z',
|
|
].join(' ')
|
|
})
|
|
|
|
const numTiles = computed(() => Math.max(1, Math.floor(svgW.value / tileW.value)))
|
|
const usedW = computed(() => numTiles.value * tileW.value)
|
|
const offsetX = computed(() => (svgW.value - usedW.value) / 2)
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="vertical" class="nych-divider--vertical" role="separator">
|
|
<svg
|
|
viewBox="226 66 228 228"
|
|
:width="size"
|
|
:height="size"
|
|
fill="currentColor"
|
|
stroke="currentColor"
|
|
aria-hidden="true"
|
|
style="flex-shrink: 0"
|
|
>
|
|
<g v-for="(leaf, i) in radialLeaves" :key="i" :transform="leaf.transform">
|
|
<path :d="leaf.path" />
|
|
<line
|
|
:x1="leaf.line.x1"
|
|
:y1="leaf.line.y1"
|
|
:x2="leaf.line.x2"
|
|
:y2="leaf.line.y2"
|
|
stroke-width="0.8"
|
|
stroke-linecap="round"
|
|
/>
|
|
</g>
|
|
</svg>
|
|
</div>
|
|
<div v-else class="nych-divider" role="separator" :data-p="label ? 'label' : undefined">
|
|
<span v-if="label" class="nych-divider-label">{{ label }}</span>
|
|
<div v-else ref="wrapRef" style="width: 100%; height: 100%">
|
|
<svg :width="svgW" :height="h" aria-hidden="true">
|
|
<defs>
|
|
<pattern
|
|
:id="uid"
|
|
:x="offsetX"
|
|
y="0"
|
|
:width="tileW"
|
|
:height="h"
|
|
patternUnits="userSpaceOnUse"
|
|
>
|
|
<path :d="leafPath" fill="currentColor" opacity="0.85" />
|
|
<line
|
|
:x1="f(pts[0]![0])"
|
|
:y1="f(pts[0]![1])"
|
|
:x2="f(pts[3]![0])"
|
|
:y2="f(pts[3]![1])"
|
|
stroke="currentColor"
|
|
stroke-width="0.5"
|
|
stroke-linecap="round"
|
|
opacity="0.4"
|
|
/>
|
|
</pattern>
|
|
<clipPath :id="`${uid}c`">
|
|
<rect :x="offsetX" y="0" :width="usedW" :height="h" />
|
|
</clipPath>
|
|
</defs>
|
|
<rect :width="svgW" :height="h" :fill="`url(#${uid})`" :clip-path="`url(#${uid}c)`" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</template>
|