From 04c01fc47f7f49d6cc09073de061e3067b6a213c Mon Sep 17 00:00:00 2001 From: LeeJhin Date: Wed, 10 Jun 2026 11:09:08 +0900 Subject: [PATCH 1/2] Tighten new-problem funnel width and densify grade and topic steps - Remove the .app-canvas 1280->1600 container override so /app/* obeys the 1280 productivity width (DESIGN.md spec); steps now align to the same left edge as the nav. - Grade: lay the options as a compact 4-up row that fills the aligned container (was an 820 centered column indented ~190px from the nav, which looked skewed). - Topic: replace the 1-column unit list + permanent half-empty example panel with a dense 3-up unit grid that fits one viewport; the example preview now mounts on-demand below the grid after a unit is selected. - Drop the unused .container-step and .topic-grid-1col helpers and the empty-state example panel rules. --- packages/web/app/app/new/topic/picker.tsx | 116 +++++------ packages/web/app/globals.css | 237 ++++++++++++++-------- 2 files changed, 210 insertions(+), 143 deletions(-) diff --git a/packages/web/app/app/new/topic/picker.tsx b/packages/web/app/app/new/topic/picker.tsx index 4985a1e..970d022 100644 --- a/packages/web/app/app/new/topic/picker.tsx +++ b/packages/web/app/app/new/topic/picker.tsx @@ -161,7 +161,7 @@ export function TopicPicker({ schoolLevel, grade }: Props) {

) : (
@@ -194,73 +194,61 @@ export function TopicPicker({ schoolLevel, grade }: Props) { )} - +
+ 예시는 corpus 의 기존 문제이며, 실제 출제 시 LLM 이 동형 + 문제를 새로 생성하고 SymPy 가 검증합니다. +
+ + )}
diff --git a/packages/web/app/globals.css b/packages/web/app/globals.css index 0392476..11c874a 100644 --- a/packages/web/app/globals.css +++ b/packages/web/app/globals.css @@ -779,9 +779,9 @@ background: var(--color-canvas-pure); min-height: 100vh; } - .app-canvas .container-app { - max-width: 1600px; - } + /* container-app — productivity 표준 1280px (DESIGN.md §"Grid & Container"). + * 워크스페이스 랜딩, S2~S6 (topic / intent / verify / result / export) 가 사용. + */ .container-app { max-width: 1280px; margin: 0 auto; @@ -813,7 +813,11 @@ border-bottom: 1px solid var(--color-hairline-soft); } - /* hero-tile-productivity — DESIGN.md {component.hero-tile-productivity} */ + /* hero-tile-productivity — DESIGN.md {component.hero-tile-productivity}. + * 발표/소개 페이지의 흑색 hero 전용 (예: 미래 v2 marketing-in-app). + * S0 워크스페이스 랜딩(/app)에는 사용 안 함 — 출제 도구는 brochure 가 + * 아니라 tool 로 읽혀야 하므로 .workspace-header 로 대체됨. + */ .hero-tile-productivity { background: var(--color-ink); color: var(--color-on-ink); @@ -883,17 +887,71 @@ } } + /* workspace-header — /app 워크스페이스 랜딩의 compact tool-like 헤더. + * 흑색 96px 풀-블리드 hero 대신 productivity canvas-pure 위에 작은 + * sans 헤딩 + meta 만 둔다. DESIGN.md "display-section 은 hero-tile 한 자리" + * 정책을 지키기 위해 Inter heading-lg (24px) 사용. + */ + .workspace-header { + padding-top: 40px; + padding-bottom: 24px; + display: flex; + flex-direction: column; + gap: 10px; + } + .workspace-header .eyebrow-mono { + font-family: var(--font-mono); + font-size: 11.5px; + font-weight: 400; + letter-spacing: 0.04em; + color: var(--color-ink-3); + margin: 0; + display: inline-flex; + align-items: center; + gap: 10px; + } + .workspace-header h1 { + font-family: var(--font-sans); + font-size: 28px; + font-weight: 500; + line-height: 1.25; + letter-spacing: -0.01em; + color: var(--color-ink); + margin: 0; + word-break: keep-all; + } + .workspace-header .lede { + font-family: var(--font-sans); + font-size: 14px; + font-weight: 400; + line-height: 1.55; + color: var(--color-ink-3); + margin: 0; + max-width: 64ch; + word-break: keep-all; + } + @media (max-width: 768px) { + .workspace-header { + padding-top: 28px; + padding-bottom: 20px; + } + .workspace-header h1 { + font-size: 24px; + } + } + /* job-entry-card — DESIGN.md {component.job-entry-card} */ .entry-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; - padding: var(--spacing-section) 0; + padding-top: 0; + padding-bottom: var(--spacing-section); } @media (max-width: 768px) { .entry-grid { grid-template-columns: 1fr; - padding: 32px 0; + padding-bottom: 32px; } } .job-entry-card { @@ -1147,25 +1205,42 @@ line-height: 1.5; } - /* grade-grid (S1 3-up) */ + /* grade-grid (S1) — 1280px container-app 안의 4-up 단일 행 그리드. + * 4 개 학년 옵션(중1·중2·중3·고등 공통수학)이 한 줄에 정렬되어 nav 의 + * 좌측 edge 와 동일한 좌측 edge 에서 시작한다. 각 카드 ~290px. + * ≤900px → 2-up, ≤560px → 1-up 으로 collapse. + */ .grade-grid { display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 16px; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 12px; } - @media (max-width: 600px) { + @media (max-width: 900px) { + .grade-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + @media (max-width: 560px) { .grade-grid { grid-template-columns: 1fr; } } - /* topic-grid (S2 2-up) */ + /* topic-grid (S2) — 1280px container-app 안의 3-up dense 단원 그리드. + * 한 학년 10~13 단원이 3~5 행으로 떨어져 1 viewport 안에 스캔 가능. + * ≤1100px → 2-up, ≤620px → 1-up. + */ .topic-grid { display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 16px; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; } - @media (max-width: 768px) { + @media (max-width: 1100px) { + .topic-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + @media (max-width: 620px) { .topic-grid { grid-template-columns: 1fr; } @@ -2531,75 +2606,71 @@ } } - /* topic-picker (S2) — 2-column: 좌 단원 카드 / 우 예시 패널. 좁은 폭에서도 2-col 유지하여 옆에 같이 보이도록. min-width:0 으로 컬럼 자유 축소. */ + /* topic-picker (S2) — 단일 컬럼 vertical stack: 위 단원 그리드 / 아래 (선택 시) + * 예시 패널. 이전의 50/50 2-column 은 우측이 항상 비어 있어 공간 낭비 + + * 좌측 단원 리스트가 1-col 으로 좁아져 스크롤 양 1.31 화면이었음. + * Now: 단원 그리드가 1280 폭 전부를 사용해 3-up 으로 스캔되고, 예시는 + * 선택 후 같은 폭에서 아래에 펼쳐진다. + */ .topic-picker .topic-layout { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); - gap: clamp(16px, 2vw, 32px); - align-items: start; - } - .topic-picker .topic-grid-1col { - grid-template-columns: 1fr; + display: flex; + flex-direction: column; + gap: 24px; } - @media (max-width: 768px) { - .topic-picker .topic-layout { - grid-template-columns: 1fr; - gap: 20px; - } + + /* topic-cards — 단원 그리드 wrapper. min-width:0 으로 grid item 자유 축소. */ + .topic-picker .topic-cards { + min-width: 0; } - /* example-panel — sticky 우측 패널. max-height = 페이지헤더(breadcrumb+title+subtitle+filter ≈ 300px) + action-bar(80px) 차감하여 짧은 뷰포트(vh~650)에서도 잘리지 않음. 내부 .example-list 만 스크롤. min-height 는 빈 상태(empty)에만 적용. */ - .example-panel { - position: sticky; - top: 24px; - max-height: calc(100dvh - 400px); - background: var(--color-canvas-pure); - border: 1px solid var(--color-rule); - border-radius: 12px; - padding: 16px 18px; - display: flex; - flex-direction: column; + /* topic-picker scope 의 intent-radio-card — 단원 카드는 baseline 보다 compact + * 하게. label-desc 는 2-line clamp + 시각적 secondary. + */ + .topic-picker .intent-radio-card { + padding: 12px 14px; + align-items: flex-start; gap: 10px; - overflow: hidden; } - @media (max-width: 768px) { - .example-panel { - position: static; - max-height: none; - overflow: visible; - } + .topic-picker .intent-radio-card:has(input:checked) { + padding: 11px 13px; } - .example-panel:has(.example-panel-empty) { - min-height: 240px; + .topic-picker .intent-radio-card .label { + gap: 4px; } - - .example-panel-empty { - display: flex; - flex-direction: column; + .topic-picker .intent-radio-card .label-main { + font-size: 15px; gap: 8px; - padding: 32px 16px; - text-align: center; - color: var(--color-ink-3); } - .example-panel-empty-title { - font-family: var(--font-serif); - font-size: 18px; - font-weight: 500; - color: var(--color-ink-2); - margin: 0; + .topic-picker .intent-radio-card .label-desc { + font-size: 12.5px; + line-height: 1.45; + color: var(--color-ink-3); + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + line-clamp: 2; + overflow: hidden; } - .example-panel-empty-desc { - font-family: var(--font-sans); - font-size: 13px; - line-height: 1.55; - margin: 0; + + /* example-panel — 단원 선택 후 그리드 아래에 펼쳐지는 on-demand 미리보기. + * 이전의 sticky 우측 50% 패널 + 빈 placeholder 를 폐기. 선택 전에는 panel + * 자체가 mount 되지 않아 0px 공간 점유. + */ + .example-panel { + background: var(--color-canvas-pure); + border: 1px solid var(--color-rule); + border-radius: 12px; + padding: 20px 22px; + display: flex; + flex-direction: column; + gap: 14px; } .example-panel-header { display: flex; flex-direction: column; gap: 8px; - padding-bottom: 16px; + padding-bottom: 14px; border-bottom: 1px solid var(--color-rule-soft); } .example-panel-title-row { @@ -2631,16 +2702,24 @@ margin: 0; } + /* example-list — 예시 3 문항을 가로 3-up 그리드로. 좁아지면 2-up → 1-up. */ .example-list { list-style: none; - padding: 0 4px 0 0; + padding: 0; margin: 0; - display: flex; - flex-direction: column; - gap: 10px; - overflow-y: auto; - flex: 1 1 auto; - min-height: 0; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + } + @media (max-width: 1024px) { + .example-list { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + @media (max-width: 620px) { + .example-list { + grid-template-columns: 1fr; + } } .example-card { background: var(--color-canvas); @@ -2722,11 +2801,10 @@ .topic-picker .filter-row { margin-bottom: 16px; } .topic-picker .filter-chip { height: 30px; padding: 6px 14px; font-size: 12px; } .topic-picker .topic-layout { gap: 20px; } - .topic-picker .intent-radio-card { padding: 12px 14px; font-size: 14.5px; } - .topic-picker .intent-radio-card .label-main { font-size: 14.5px; } - .topic-picker .intent-radio-card .label-desc { font-size: 12.5px; margin-top: 2px; } + .topic-picker .intent-radio-card { padding: 10px 12px; } + .topic-picker .intent-radio-card:has(input:checked) { padding: 9px 11px; } - .example-panel { max-height: calc(100dvh - 300px); padding: 14px 16px; gap: 8px; } + .example-panel { padding: 16px 18px; gap: 10px; } .example-panel-header { padding-bottom: 10px; gap: 6px; } .example-panel-title { font-size: 18px; } .example-panel-desc { font-size: 12px; } @@ -2746,9 +2824,10 @@ .topic-picker .filter-row { margin-bottom: 12px; } .topic-picker .filter-chip { height: 28px; padding: 5px 12px; } .topic-picker .topic-layout { gap: 16px; } - .topic-picker .intent-radio-card { padding: 10px 12px; } + .topic-picker .intent-radio-card { padding: 9px 11px; } + .topic-picker .intent-radio-card:has(input:checked) { padding: 8px 10px; } - .example-panel { max-height: calc(100dvh - 220px); padding: 12px 14px; gap: 6px; } + .example-panel { padding: 14px 16px; gap: 8px; } .example-panel-title { font-size: 16px; } .example-card { padding: 8px 10px; gap: 5px; } .example-question { font-size: 12px; line-height: 1.5; } From 444d6f9062f576cdd0885c1bf3bbc4e69210219a Mon Sep 17 00:00:00 2001 From: LeeJhin Date: Wed, 10 Jun 2026 11:09:10 +0900 Subject: [PATCH 2/2] Replace workspace hero with a compact tool header Drop the full-bleed black editorial hero on /app and lead with a compact Inter header so the 'new problem' entry cards sit above the fold and the workspace reads as a tool rather than a landing page. --- packages/web/app/app/page.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/web/app/app/page.tsx b/packages/web/app/app/page.tsx index d598cb4..8e555d2 100644 --- a/packages/web/app/app/page.tsx +++ b/packages/web/app/app/page.tsx @@ -3,17 +3,15 @@ import Link from "next/link"; export default function WorkspacePage() { return ( <> -
-
- - - 워크스페이스 - -

검증된 문제 한 세트.

-

- 학년 → 단원 → 의도 → 검증 → PDF · 5 ~ 30 초 동형 출제. -

-
+
+ + + 워크스페이스 + +

새 작업 시작

+

+ 학년 → 단원 → 의도 → 검증 → PDF. 한 번에 3 ~ 10 문항, 5 ~ 30 초 출제. +