feat(md-deck): add vertical alignment options to layers

Expand align from l/c/r to a 3x3 grid with vertical prefixes:
tl/tc/tr/bl/bc/br. Vertical position renders via flex
justify-content; compact layers strings and YAML both parse the
new values, and the layer editor dropdown gains corner/edge
options.
This commit is contained in:
2026-09-03 10:17:44 +08:00
parent d75df5280f
commit 5fc2bc5262
7 changed files with 102 additions and 35 deletions
@@ -1,7 +1,7 @@
import { For, createSignal, onCleanup, onMount } from "solid-js";
import { createSortable, useDragDropContext } from "@thisbeyond/solid-dnd";
import type { DeckStore } from "../hooks/deckStore";
import type { LayerConfig } from "../types";
import type { Align, LayerConfig } from "../types";
import alignLeftIcon from "./icons/align-left.png";
import alignCenterIcon from "./icons/align-center.png";
import alignRightIcon from "./icons/align-right.png";
@@ -17,7 +17,7 @@ export interface LayerRowProps {
setOpenDropdown: (val: string | null) => void;
onUpdateOrientation: (o: "n" | "s" | "e" | "w") => void;
onUpdateFontSize: (fs?: number) => void;
onUpdateAlign: (a?: "l" | "c" | "r") => void;
onUpdateAlign: (a?: Align) => void;
onSelect: () => void;
onRemove: () => void;
}
@@ -29,11 +29,17 @@ const ORIENTATIONS = [
{ value: "w" as const, label: "← 西" },
];
const ALIGNS = [
{ value: "" as const, icon: alignCenterIcon },
{ value: "l" as const, icon: alignLeftIcon },
{ value: "c" as const, icon: alignCenterIcon },
{ value: "r" as const, icon: alignRightIcon },
const ALIGNS: { value: Align | ""; icon: string }[] = [
{ value: "", icon: alignCenterIcon },
{ value: "l", icon: alignLeftIcon },
{ value: "c", icon: alignCenterIcon },
{ value: "r", icon: alignRightIcon },
{ value: "tl", icon: "↖" },
{ value: "tc", icon: "↑" },
{ value: "tr", icon: "↗" },
{ value: "bl", icon: "↙" },
{ value: "bc", icon: "↓" },
{ value: "br", icon: "↘" },
];
const FONT_PRESETS = [3, 5, 8, 12] as const;
@@ -53,14 +59,28 @@ function orientChar(v: string) {
}
}
function alignSrc(v: string) {
function alignIcon(v: string): import("solid-js").JSX.Element {
switch (v) {
case "tl":
return "↖";
case "tc":
return "↑";
case "tr":
return "↗";
case "bl":
return "↙";
case "bc":
return "↓";
case "br":
return "↘";
case "l":
return alignLeftIcon;
return <img src={alignLeftIcon} alt="align" class="w-5 h-5 not-prose" />;
case "r":
return alignRightIcon;
return <img src={alignRightIcon} alt="align" class="w-5 h-5 not-prose" />;
default:
return alignCenterIcon;
return (
<img src={alignCenterIcon} alt="align" class="w-5 h-5 not-prose" />
);
}
}
@@ -149,13 +169,7 @@ export function LayerRow(props: LayerRowProps) {
</DropdownButton>
<DropdownButton
icon={
<img
src={alignSrc(props.layer.align || "")}
alt="align"
class="w-5 h-5 not-prose"
/>
}
icon={alignIcon(props.layer.align || "")}
visible={props.layer.visible}
open={props.openDropdown === `align-${props.index}`}
onToggle={() =>
@@ -173,7 +187,13 @@ export function LayerRow(props: LayerRowProps) {
onClick={() => props.onUpdateAlign(o.value || undefined)}
class="flex items-center gap-2 w-full px-3 py-1.5 text-sm hover:bg-gray-100 cursor-pointer whitespace-nowrap"
>
<img src={o.icon} alt="" class="w-4 h-4 not-prose max-w-none" />
{o.icon.endsWith(".png") ? (
<img src={o.icon} alt="" class="w-4 h-4 not-prose max-w-none" />
) : (
<span class="w-4 h-4 flex items-center justify-center not-prose">
{o.icon}
</span>
)}
</button>
)}
</For>