j
CI / Verify (push) Successful in 1m30s
CI / Build immutable images and deploy (push) Successful in 2m5s

This commit is contained in:
2026-09-26 01:54:50 +07:00 Unverified
parent 079468f259
commit db9b5ecdc8
6 changed files with 184 additions and 77 deletions
+44 -21
View File
@@ -95,6 +95,8 @@ import {
addExtraSheetRow,
clearExtraSheetCellFormatting,
DEFAULT_EXTRA_SHEET_COLUMN_WIDTH,
MAX_EXTRA_SHEET_COLUMN_WIDTH,
MIN_EXTRA_SHEET_COLUMN_WIDTH,
deleteExtraSheetColumn,
deleteExtraSheetRow,
extraSheetRangeToTsv,
@@ -408,6 +410,7 @@ export function ExtraSheetEditor({
coordinateGetter: sortableKeyboardCoordinates,
}),
);
const sheetRootRef = useRef<HTMLDivElement>(null);
const spreadsheetRef = useRef<SpreadsheetRef>(null);
const initialEditTextRef = useRef<string | null>(null);
const [active, setActive] = useState<Point>({ row: 0, column: 0 });
@@ -417,7 +420,6 @@ export function ExtraSheetEditor({
const [removeOpen, setRemoveOpen] = useState(false);
const [selectedCount, setSelectedCount] = useState(1);
const [selectionKind, setSelectionKind] = useState<"cells" | "rows" | "columns">("cells");
const [draftWidths, setDraftWidths] = useState<Record<number, number>>({});
const [history, setHistory] = useState<SheetHistory>({
items: [value],
index: 0,
@@ -548,17 +550,34 @@ export function ExtraSheetEditor({
const target = event.target as HTMLElement;
if (target.closest("input, textarea, [contenteditable='true']")) return;
const key = event.key.toLowerCase();
const commandKey = event.metaKey || event.ctrlKey;
const undo =
(event.metaKey || event.ctrlKey) && !event.shiftKey && key === "z";
commandKey && !event.shiftKey && key === "z";
const redo =
((event.metaKey || event.ctrlKey) && event.shiftKey && key === "z") ||
(commandKey && event.shiftKey && key === "z") ||
(event.ctrlKey && !event.shiftKey && key === "y");
const format = commandKey && !event.altKey && !event.shiftKey
? ({ b: "bold", i: "italic", u: "underline" } as const)[key as "b" | "i" | "u"]
: event.altKey && event.shiftKey && key === "5"
? "strike"
: undefined;
if (undo && canUndo) {
event.preventDefault();
travel(-1);
} else if (redo && canRedo) {
event.preventDefault();
travel(1);
} else if (format) {
event.preventDefault();
const activePattern = {
bold: /<strong\b/i,
italic: /<em\b/i,
underline: /<u\b/i,
strike: /<s\b/i,
}[format];
commitSheet(styleExtraSheetCells(value, selectedPointsRef.current, {
[format]: !activePattern.test(activeValue),
}));
} else if (event.key === "Delete" || event.key === "Backspace") {
event.preventDefault();
commitSheet(updateExtraSheetCells(value, selectedPointsRef.current, { value: "" }));
@@ -689,14 +708,18 @@ export function ExtraSheetEditor({
};
const resizeColumn = useCallback(
(column: number, width: number, commit: boolean) => {
setDraftWidths((current) => ({ ...current, [column]: width }));
if (!commit) return;
setDraftWidths((current) => {
const next = { ...current };
delete next[column];
return next;
});
commitSheet(resizeExtraSheetColumn(value, column, width));
const boundedWidth = Math.round(Math.max(
MIN_EXTRA_SHEET_COLUMN_WIDTH,
Math.min(MAX_EXTRA_SHEET_COLUMN_WIDTH, width),
));
if (!commit) {
const columnElement = sheetRootRef.current?.querySelector<HTMLTableColElement>(
`col[data-sheet-column-index="${column}"]`,
);
if (columnElement) columnElement.style.width = `${boundedWidth}px`;
return;
}
commitSheet(resizeExtraSheetColumn(value, column, boundedWidth));
},
[commitSheet, value],
);
@@ -707,12 +730,11 @@ export function ExtraSheetEditor({
id={columnDragId(value.columns[props.column].id)}
onRename={openRenameColumn}
onResize={resizeColumn}
width={draftWidths[props.column]
?? value.columns[props.column].width
width={value.columns[props.column].width
?? DEFAULT_EXTRA_SHEET_COLUMN_WIDTH}
/>
),
[draftWidths, openRenameColumn, resizeColumn, value.columns],
[openRenameColumn, resizeColumn, value.columns],
);
const rowIndicator = useCallback(
(props: RowIndicatorProps) => (
@@ -744,9 +766,9 @@ export function ExtraSheetEditor({
{Array.from({ length: columns }, (_, index) => (
<col
key={value.columns[index]?.id ?? index}
data-sheet-column-index={index}
style={{
width: draftWidths[index]
?? value.columns[index]?.width
width: value.columns[index]?.width
?? DEFAULT_EXTRA_SHEET_COLUMN_WIDTH,
}}
/>
@@ -755,7 +777,7 @@ export function ExtraSheetEditor({
<tbody>{children}</tbody>
</table>
),
[draftWidths, value.columns],
[value.columns],
);
const activeFormats = [
/<strong\b/i.test(activeValue) ? "bold" : null,
@@ -768,6 +790,7 @@ export function ExtraSheetEditor({
return (
<div
ref={sheetRootRef}
className="flex min-w-0 flex-col gap-3"
aria-label="ตารางข้อมูลเสริม"
onKeyDown={handleSheetKeyDown}
@@ -811,16 +834,16 @@ export function ExtraSheetEditor({
if (Object.keys(patch).length) applyStyle(patch);
}}
>
<ToggleGroupItem value="bold" aria-label="ตัวหนา">
<ToggleGroupItem value="bold" aria-label="ตัวหนา" title="ตัวหนา (Ctrl/⌘ B)">
<BoldIcon />
</ToggleGroupItem>
<ToggleGroupItem value="italic" aria-label="ตัวเอียง">
<ToggleGroupItem value="italic" aria-label="ตัวเอียง" title="ตัวเอียง (Ctrl/⌘ I)">
<ItalicIcon />
</ToggleGroupItem>
<ToggleGroupItem value="underline" aria-label="ขีดเส้นใต้">
<ToggleGroupItem value="underline" aria-label="ขีดเส้นใต้" title="ขีดเส้นใต้ (Ctrl/⌘ U)">
<UnderlineIcon />
</ToggleGroupItem>
<ToggleGroupItem value="strike" aria-label="ขีดฆ่า">
<ToggleGroupItem value="strike" aria-label="ขีดฆ่า" title="ขีดฆ่า (Alt/⌥ Shift 5)">
<StrikethroughIcon />
</ToggleGroupItem>
</ToggleGroup>
+1 -1
View File
@@ -4829,7 +4829,7 @@ function ExtraEditor({ guide, extraSectionId, initial, characters, weapons, arti
}
>
<PlusIcon data-icon="inline-start" />
เพิ่มตาราง 2 × 2
เพิ่มตาราง 4 × 6
</Button>
)}
</Field>