Merge remote-tracking branch 'origin/dev' into sub_laptop_2
This commit is contained in:
@@ -94,7 +94,7 @@ export function resolveBoxBorders(
|
||||
/** 빈 글 = 인라인 테두리를 안 그림(css `aislo-grid--gridlines` 눈금선이 비쳐 보임). `scale` = 확대 · 축소 배율(선 굵기도 같이). */
|
||||
function borderCss(side: BorderSide | undefined, scale: number): string {
|
||||
if (!side) return "";
|
||||
const color = side.색 ?? "#000000";
|
||||
const color = side.색 ?? "currentColor";
|
||||
const w = (px: number): number => Math.max(1, Math.round(px * scale));
|
||||
switch (side.선) {
|
||||
case "hair":
|
||||
|
||||
@@ -252,29 +252,39 @@ function unescapeMsoNumFmt(v: string): string {
|
||||
return v.replace(/^"|"$/g, "").replace(/\\(.)/g, "$1");
|
||||
}
|
||||
|
||||
const BORDER_STYLE_MAP: Record<string, BorderLine> = {
|
||||
solid: "thin",
|
||||
dashed: "dashed",
|
||||
dotted: "dotted",
|
||||
double: "double",
|
||||
};
|
||||
/** pt 굵기 → 우리 선 종류(엑셀 내보내기 흔한 값 기준 — hairline ≈ .5pt 이하 · thin ≈ 1pt · medium ≈
|
||||
* 1.5~2pt · thick ≈ 2pt 넘음). `solid` 아닌 것은 굵기와 상관없이 그 모양. */
|
||||
function ptToBorderLine(pt: number, cssStyle: string): BorderLine {
|
||||
if (cssStyle === "dashed") return "dashed";
|
||||
if (cssStyle === "dotted") return "dotted";
|
||||
if (cssStyle === "double") return "double";
|
||||
if (pt <= 0.5) return "hair";
|
||||
if (pt <= 1.25) return "thin";
|
||||
if (pt <= 2) return "medium";
|
||||
return "thick";
|
||||
}
|
||||
|
||||
function parseBorderShorthand(v: string): BorderSide | undefined {
|
||||
const m = /([\d.]+)\s*(?:pt|px)\s+(solid|dashed|dotted|double)\s*([^;]*)/i.exec(v);
|
||||
if (!m) return undefined;
|
||||
const 선 = BORDER_STYLE_MAP[m[2].toLowerCase()] ?? "thin";
|
||||
const 선 = ptToBorderLine(Number(m[1]), m[2].toLowerCase());
|
||||
const 색 = cssColorToHex(m[3]);
|
||||
return 색 ? { 선, 색 } : { 선 };
|
||||
}
|
||||
|
||||
/** `<style>...</style>` 안 `.xl65 {...}` 짜임(엑셀이 인라인 대신 클래스로 서식을 실을 때) → 클래스별 선언. */
|
||||
/** `<style>...</style>` 안 `.xl65 {...}` · `.xl65, .xl70 {...}`(묶음 선택자) 짜임(엑셀이 인라인 대신
|
||||
* 클래스로 서식을 실을 때) → 클래스별 선언(같은 클래스가 여러 규칙에 나오면 뒤엣것이 이김). */
|
||||
function parseClassRules(doc: Document): Record<string, Record<string, string>> {
|
||||
const css = Array.from(doc.querySelectorAll("style"))
|
||||
.map((s) => s.textContent ?? "")
|
||||
.join("\n");
|
||||
const rules: Record<string, Record<string, string>> = {};
|
||||
for (const m of css.matchAll(/\.([a-zA-Z0-9_-]+)\s*\{([^}]*)\}/g)) {
|
||||
rules[m[1]] = parseStyleAttr(m[2]);
|
||||
for (const m of css.matchAll(/([^{}]+)\{([^}]*)\}/g)) {
|
||||
const decls = parseStyleAttr(m[2]);
|
||||
for (const selectorPart of m[1].split(",")) {
|
||||
const cls = /\.([a-zA-Z0-9_-]+)\s*$/.exec(selectorPart.trim());
|
||||
if (cls) Object.assign((rules[cls[1]] ??= {}), decls);
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
@@ -4,12 +4,16 @@
|
||||
* ========================================================================== */
|
||||
|
||||
.aislo-grid {
|
||||
--aislo-grid-line: #d9d9d9;
|
||||
--aislo-grid-head-bg: #f3f3f3;
|
||||
--aislo-grid-head-fg: #444;
|
||||
--aislo-grid-head-border: #cfcfcf;
|
||||
/* 앱 전역 테마 토큰(ui_template_theme.css · :root[data-theme])을 그대로 물려받음 —
|
||||
* 여기서 값을 다시 안 적음(다크 전환 시 앱 토큰이 바뀌면 같이 바뀜). */
|
||||
--aislo-grid-bg: var(--color-surface-raised);
|
||||
--aislo-grid-fg: var(--color-text-body);
|
||||
--aislo-grid-line: var(--color-border);
|
||||
--aislo-grid-head-bg: var(--color-surface);
|
||||
--aislo-grid-head-fg: var(--color-text-secondary);
|
||||
--aislo-grid-head-border: var(--color-border);
|
||||
--aislo-grid-freeze-shadow: rgba(0, 0, 0, 0.12);
|
||||
--aislo-grid-selected: #1a73e8;
|
||||
--aislo-grid-selected: var(--color-accent);
|
||||
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -18,7 +22,8 @@
|
||||
font:
|
||||
10pt "굴림",
|
||||
sans-serif;
|
||||
background: #fff;
|
||||
background: var(--aislo-grid-bg);
|
||||
color: var(--aislo-grid-fg);
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
@@ -94,7 +99,7 @@
|
||||
|
||||
.aislo-grid__colhead--hidden-before,
|
||||
.aislo-grid__rowhead--hidden-before {
|
||||
border-left: 3px double #888;
|
||||
border-left: 3px double var(--aislo-grid-head-fg);
|
||||
}
|
||||
|
||||
.aislo-grid__head-label {
|
||||
@@ -122,7 +127,7 @@
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
border: 1px solid var(--aislo-grid-head-border);
|
||||
background: #fff;
|
||||
background: var(--aislo-grid-head-bg);
|
||||
color: var(--aislo-grid-head-fg);
|
||||
font-size: 0.7em;
|
||||
line-height: 1;
|
||||
@@ -160,7 +165,7 @@
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 0 2px;
|
||||
background: #fff;
|
||||
background: var(--aislo-grid-bg);
|
||||
cursor: cell;
|
||||
}
|
||||
|
||||
@@ -228,7 +233,7 @@
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: var(--aislo-grid-selected);
|
||||
border: 1px solid #fff;
|
||||
border: 1px solid var(--aislo-grid-bg);
|
||||
cursor: crosshair;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
@@ -815,7 +815,7 @@ export function createGrid(ctx: SpreadsheetContext): GridHandle {
|
||||
node.style.top = `${screen.y}px`;
|
||||
node.style.width = `${screen.w}px`;
|
||||
node.style.height = `${screen.h}px`;
|
||||
node.style.borderColor = "#1a73e8";
|
||||
node.style.borderColor = "var(--aislo-grid-selected)";
|
||||
node.style.borderWidth = i === 0 ? "2px" : "1px";
|
||||
selLayer!.append(node);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<!-- fixture_excel_style_paste.html — 엑셀이 표 서식(머리 채움 · 가는 선 · 합계 줄 위 굵은 선 · 숫자
|
||||
쉼표)을 실제로 어떻게 싣는지 재현(브레인 9-28 사용자 지시 근거 = PLAN.md 12장). 서식 대부분이
|
||||
인라인 style 이 아니라 <style> 안 클래스(.xl65 같은 이름 · 묶음 선택자 포함)에 있고 칸에는
|
||||
class 만 두는 실제 엑셀 내보내기 짜임을 그대로 씀 — `parseHtmlTable`/`styleFromTd` 가 클래스
|
||||
규칙을 인라인과 합쳐 읽는지 이 견본으로 시험. -->
|
||||
<html
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
||||
xmlns="http://www.w3.org/TR/REC-html40"
|
||||
>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
<!--table
|
||||
{mso-displayed-decimal-separator:"\.";
|
||||
mso-displayed-thousand-separator:"\,";}
|
||||
.xl_head, .xl_head2
|
||||
{background:#D9D9D9;
|
||||
font-weight:700;
|
||||
text-align:center;
|
||||
border:.5pt solid windowtext;}
|
||||
.xl_num
|
||||
{mso-number-format:"\#\,\#\#0";
|
||||
text-align:right;
|
||||
border:.5pt solid windowtext;}
|
||||
.xl_label
|
||||
{border:.5pt solid windowtext;}
|
||||
.xl_total_label
|
||||
{font-weight:700;
|
||||
border-left:.5pt solid windowtext;
|
||||
border-right:.5pt solid windowtext;
|
||||
border-bottom:.5pt solid windowtext;
|
||||
border-top:1.5pt solid windowtext;}
|
||||
.xl_total_num
|
||||
{mso-number-format:"\#\,\#\#0";
|
||||
font-weight:700;
|
||||
text-align:right;
|
||||
border-left:.5pt solid windowtext;
|
||||
border-right:.5pt solid windowtext;
|
||||
border-bottom:.5pt solid windowtext;
|
||||
border-top:1.5pt solid windowtext;}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body link="#0563C1" vlink="#954F72">
|
||||
<!--StartFragment-->
|
||||
<table
|
||||
border="0"
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
width="288"
|
||||
style="border-collapse: collapse; width: 216pt"
|
||||
>
|
||||
<tr height="20" style="height: 15pt">
|
||||
<td class="xl_head" width="96" style="width: 72pt" x:str>품목</td>
|
||||
<td class="xl_head2" width="96" style="width: 72pt" x:str>수량</td>
|
||||
<td class="xl_head2" width="96" style="width: 72pt" x:str>금액</td>
|
||||
</tr>
|
||||
<tr height="20" style="height: 15pt">
|
||||
<td class="xl_label" x:str>터파기</td>
|
||||
<td class="xl_num" x:num>120</td>
|
||||
<td class="xl_num" x:num>1200000</td>
|
||||
</tr>
|
||||
<tr height="20" style="height: 15pt">
|
||||
<td class="xl_label" x:str>메우기</td>
|
||||
<td class="xl_num" x:num>80</td>
|
||||
<td class="xl_num" x:num>800000</td>
|
||||
</tr>
|
||||
<tr height="20" style="height: 15pt">
|
||||
<td class="xl_total_label" x:str>합계</td>
|
||||
<td class="xl_total_num" x:num>200</td>
|
||||
<td class="xl_total_num" x:num>2000000</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--EndFragment-->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<html lang="ko" data-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>C 격자 시험 틀</title>
|
||||
<link rel="stylesheet" href="../../../ui_template/ui_template_theme.css" />
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
|
||||
Reference in New Issue
Block a user