style(frontend): 삼성향 라이트 팔레트(samsung) 추가하고 기본으로
삼성닷컴(sec) 공개 웹 실측값 — 검정 주색/CTA, 흰 canvas, #f7f7f7 surface, #707070 muted, #dddddd border, 링크 #007aff, 그림자 없음, 버튼·카드 radius 20px(알약). One UI 파랑은 폰 앱용이라 안 씀. 폰트는 재배포 근거 없어 안 넣음. 다크 모드는 기존 그대로. 기존 사용자 저장값 clean-blue 는 한 번만 samsung 으로 교체(index.html 부트스트랩). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
e351560377
commit
efb9fb46de
@@ -10,14 +10,14 @@
|
||||
// 팔레트는 localStorage 'theme' 키, 다크모드는 'theme-store' (zustand persist).
|
||||
;(function () {
|
||||
try {
|
||||
var pal = localStorage.getItem("theme") || "clean-blue"
|
||||
// 이전 기본 베이지는 한 번만 교체. 이후 직접 고른 팔레트는 유지.
|
||||
if (!localStorage.getItem("clean-blue-default-v1")) {
|
||||
if (pal === "warm-tan") {
|
||||
pal = "clean-blue"
|
||||
var pal = localStorage.getItem("theme") || "samsung"
|
||||
// 기본 팔레트 교체는 한 번만(삼성향, 2026-09). 이후 직접 고른 팔레트는 유지.
|
||||
if (!localStorage.getItem("samsung-default-v1")) {
|
||||
if (pal === "warm-tan" || pal === "clean-blue") {
|
||||
pal = "samsung"
|
||||
localStorage.setItem("theme", pal)
|
||||
}
|
||||
localStorage.setItem("clean-blue-default-v1", "1")
|
||||
localStorage.setItem("samsung-default-v1", "1")
|
||||
}
|
||||
document.documentElement.setAttribute("data-theme", pal)
|
||||
var raw = localStorage.getItem("theme-store")
|
||||
|
||||
@@ -83,6 +83,37 @@ export type DerivedTokens = {
|
||||
// 의미색 — 모든 테마 공통
|
||||
const DESTRUCTIVE = "oklch(0.577 0.245 27.325)"
|
||||
|
||||
// 삼성향 — 삼성닷컴(sec) 공개 웹 2026-07 실측값. 검정 주색·흰 바탕·회색 면, 그림자 없음, 알약 버튼(20px).
|
||||
// One UI 파랑(#0381fe)은 폰 앱용이라 안 씀. 링크만 #007aff. 폰트는 재배포 근거 없어 안 넣음.
|
||||
const SAMSUNG_TOKENS: DerivedTokens = {
|
||||
background: "#FFFFFF", // canvas
|
||||
foreground: "#000000",
|
||||
card: "#FFFFFF",
|
||||
cardForeground: "#000000",
|
||||
popover: "#FFFFFF",
|
||||
popoverForeground: "#000000",
|
||||
primary: "#000000", // contained CTA
|
||||
primaryForeground: "#FFFFFF",
|
||||
secondary: "#F7F7F7", // surface
|
||||
secondaryForeground: "#000000",
|
||||
muted: "#F7F7F7",
|
||||
mutedForeground: "#707070",
|
||||
accent: "#EDEDED", // hover — surface 보다 한 단계
|
||||
accentForeground: "#000000",
|
||||
destructive: DESTRUCTIVE,
|
||||
border: "#DDDDDD",
|
||||
input: "#DDDDDD",
|
||||
ring: "#000000",
|
||||
sidebar: "#F7F7F7",
|
||||
sidebarForeground: "#000000",
|
||||
sidebarPrimary: "#000000",
|
||||
sidebarPrimaryForeground: "#FFFFFF",
|
||||
sidebarAccent: "#EDEDED",
|
||||
sidebarAccentForeground: "#000000",
|
||||
sidebarBorder: "#DDDDDD",
|
||||
sidebarRing: "#000000",
|
||||
}
|
||||
|
||||
// 기본 팔레트(id 는 하위호환으로 clean-blue 유지) — ABAP_OPENCODE DESIGN_SYSTEM.md §7 라이트 값.
|
||||
// globals.css :root 와 같은 값. 명도 정렬(derive)을 안 타서 블루가 차콜로 안 바뀜.
|
||||
const CLEAN_BLUE_TOKENS: DerivedTokens = {
|
||||
@@ -114,6 +145,16 @@ const CLEAN_BLUE_TOKENS: DerivedTokens = {
|
||||
sidebarRing: "#3563E9",
|
||||
}
|
||||
|
||||
// 고정 토큰 팔레트(명도 정렬 안 탐). 나머지는 swatch 에서 derive.
|
||||
const FIXED_TOKENS: Record<string, DerivedTokens> = {
|
||||
"clean-blue": CLEAN_BLUE_TOKENS,
|
||||
samsung: SAMSUNG_TOKENS,
|
||||
}
|
||||
// 팔레트별 추가 CSS — samsung 은 알약 radius(실측 20px) + 링크색
|
||||
const EXTRA_CSS: Record<string, string> = {
|
||||
samsung: `[data-theme="samsung"]:not(.dark){--radius:20px;--link:#007aff}`,
|
||||
}
|
||||
|
||||
export function derivePaletteTokens(
|
||||
swatch: readonly [string, string, string, string]
|
||||
): DerivedTokens {
|
||||
@@ -181,13 +222,15 @@ function paletteToCss(id: string, t: DerivedTokens): string {
|
||||
}
|
||||
|
||||
// 전체 테마 CSS를 한 번에 생성. 모듈 로드 시 1회 실행.
|
||||
export const ALL_THEMES_CSS: string = PALETTES.map((p) =>
|
||||
paletteToCss(p.id, p.id === "clean-blue" ? CLEAN_BLUE_TOKENS : derivePaletteTokens(p.swatch))
|
||||
export const ALL_THEMES_CSS: string = PALETTES.map(
|
||||
(p) =>
|
||||
paletteToCss(p.id, FIXED_TOKENS[p.id] ?? derivePaletteTokens(p.swatch)) +
|
||||
(EXTRA_CSS[p.id] ?? "")
|
||||
).join("")
|
||||
|
||||
// 미리보기 카드용 — id로 derived tokens 조회
|
||||
export function getDerivedTokens(id: string): DerivedTokens | null {
|
||||
if (id === "clean-blue") return { ...CLEAN_BLUE_TOKENS }
|
||||
if (FIXED_TOKENS[id]) return { ...FIXED_TOKENS[id] }
|
||||
const p = PALETTES.find((x) => x.id === id)
|
||||
return p ? derivePaletteTokens(p.swatch) : null
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ export type RawPalette = {
|
||||
}
|
||||
|
||||
export const PALETTES: RawPalette[] = [
|
||||
{
|
||||
id: "samsung", // 고정 토큰(derive.ts SAMSUNG_TOKENS) — 삼성닷컴 공개 웹 실측값. 라이트 전용, 다크는 공통
|
||||
name: "Samsung",
|
||||
swatch: ["#FFFFFF", "#F7F7F7", "#000000", "#707070"],
|
||||
},
|
||||
{
|
||||
id: "clean-blue", // id 는 저장된 값 호환 위해 유지 — 실제 토큰은 derive.ts 워크스페이스(ABAP_OPENCODE) 값
|
||||
name: "워크스페이스",
|
||||
@@ -80,7 +85,7 @@ export const PALETTES: RawPalette[] = [
|
||||
},
|
||||
]
|
||||
|
||||
export const DEFAULT_THEME = "clean-blue"
|
||||
export const DEFAULT_THEME = "samsung"
|
||||
|
||||
export const PALETTE_BY_ID: Record<string, RawPalette> = Object.fromEntries(
|
||||
PALETTES.map((p) => [p.id, p])
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/routes.tsx","./src/vite-env.d.ts","./src/config/env.ts","./src/config/routes.ts","./src/features/auth/index.ts","./src/features/auth/api/auth.api.ts","./src/features/auth/components/entraloginbutton.tsx","./src/features/auth/components/entraloginsection.tsx","./src/features/auth/components/loginform.tsx","./src/features/auth/components/sessionexpirydialog.tsx","./src/features/auth/hooks/useentraenabled.ts","./src/features/auth/hooks/useentralogin.ts","./src/features/auth/hooks/uselogin.ts","./src/features/auth/hooks/uselogout.ts","./src/features/auth/hooks/useme.ts","./src/features/auth/hooks/useslidingrefresh.ts","./src/features/auth/pages/loginpage.tsx","./src/features/auth/schemas/index.ts","./src/features/auth/store/authstore.ts","./src/features/auth/store/sessionexpirystore.ts","./src/features/auth/utils/saferedirectpath.ts","./src/features/snap/api/snap.api.ts","./src/features/snap/api/snap.stream.ts","./src/features/snap/components/chatheader.tsx","./src/features/snap/components/clipboardhistory.tsx","./src/features/snap/components/codeblock.tsx","./src/features/snap/components/composer.tsx","./src/features/snap/components/hero.tsx","./src/features/snap/components/message.tsx","./src/features/snap/components/navrail.tsx","./src/features/snap/components/searchhitcard.tsx","./src/features/snap/components/sessioncard.tsx","./src/features/snap/components/sessionsearch.tsx","./src/features/snap/components/snaplayout.tsx","./src/features/snap/components/snapusercontrols.tsx","./src/features/snap/components/abaphljs.ts","./src/features/snap/contract/types.ts","./src/features/snap/hooks/useescapekey.ts","./src/features/snap/hooks/usesnapchat.ts","./src/features/snap/lib/format.ts","./src/features/snap/pages/newchatpage.tsx","./src/features/snap/pages/sessionchatpage.tsx","./src/features/snap/pages/sessionlistpage.tsx","./src/features/snap/store/snapchatstore.ts","./src/features/snippets/types.ts","./src/features/snippets/api/snippets.api.ts","./src/features/snippets/components/categorychips.tsx","./src/features/snippets/components/editdialog.tsx","./src/features/snippets/components/previewpane.tsx","./src/features/snippets/components/snippetrow.tsx","./src/features/snippets/core/ranking.ts","./src/features/snippets/core/search.ts","./src/features/snippets/hooks/usesnippets.ts","./src/features/snippets/pages/snippetpalettepage.tsx","./src/lib/api/client.ts","./src/lib/api/errors.ts","./src/lib/auth/msal.ts","./src/lib/auth/tokenprovider.ts","./src/lib/bridge/bridgenavigate.ts","./src/lib/bridge/snippetbridge.ts","./src/lib/bridge/transport.ts","./src/lib/bridge/webviewbridge.ts","./src/lib/hooks/usedebounce.ts","./src/lib/query/queryclient.ts","./src/lib/streaming/stoppednotice.tsx","./src/lib/streaming/streamingtext.tsx","./src/lib/streaming/abort.ts","./src/lib/streaming/index.ts","./src/lib/streaming/sse.ts","./src/lib/streaming/streamllm.ts","./src/lib/streaming/usesmoothedtext.ts","./src/lib/streaming/usestreamsession.ts","./src/lib/utils/cn.ts","./src/lib/utils/randomid.ts","./src/lib/utils/relativetime.ts","./src/lib/utils/sleep.ts","./src/shared/components/desktopwindowframe.tsx","./src/shared/components/errorboundary.tsx","./src/shared/components/kbd.tsx","./src/shared/components/layout.tsx","./src/shared/components/paletteshell.tsx","./src/shared/components/pastetargetbadge.tsx","./src/shared/components/protectedroute.tsx","./src/shared/components/themetoggle.tsx","./src/shared/hooks/usepastetarget.ts","./src/shared/store/themestore.ts","./src/shared/theme/derive.ts","./src/shared/theme/palettes.ts","./src/shared/theme/usetheme.ts","./src/shared/ui/alert-dialog.tsx","./src/shared/ui/alert.tsx","./src/shared/ui/button.tsx","./src/shared/ui/dialog.tsx","./src/shared/ui/dropdown-menu.tsx","./src/shared/ui/input.tsx","./src/shared/ui/label.tsx","./src/shared/ui/separator.tsx","./src/shared/ui/skeleton.tsx","./src/shared/ui/textarea.tsx","./src/shared/ui/tooltip.tsx","./src/types/api.ts"],"version":"5.9.3"}
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/routes.tsx","./src/vite-env.d.ts","./src/config/env.ts","./src/config/routes.ts","./src/features/auth/index.ts","./src/features/auth/api/auth.api.ts","./src/features/auth/components/entraloginbutton.tsx","./src/features/auth/components/entraloginsection.tsx","./src/features/auth/components/loginform.tsx","./src/features/auth/components/sessionexpirydialog.tsx","./src/features/auth/hooks/useentraenabled.ts","./src/features/auth/hooks/useentralogin.ts","./src/features/auth/hooks/uselogin.ts","./src/features/auth/hooks/uselogout.ts","./src/features/auth/hooks/useme.ts","./src/features/auth/hooks/useslidingrefresh.ts","./src/features/auth/pages/loginpage.tsx","./src/features/auth/schemas/index.ts","./src/features/auth/store/authstore.ts","./src/features/auth/store/sessionexpirystore.ts","./src/features/auth/utils/saferedirectpath.ts","./src/features/snap/api/snap.api.ts","./src/features/snap/api/snap.stream.ts","./src/features/snap/components/chatheader.tsx","./src/features/snap/components/clipboardhistory.tsx","./src/features/snap/components/codeblock.tsx","./src/features/snap/components/composer.tsx","./src/features/snap/components/hero.tsx","./src/features/snap/components/message.tsx","./src/features/snap/components/navrail.tsx","./src/features/snap/components/searchhitcard.tsx","./src/features/snap/components/sessioncard.tsx","./src/features/snap/components/sessionsearch.tsx","./src/features/snap/components/snaplayout.tsx","./src/features/snap/components/snapusercontrols.tsx","./src/features/snap/components/abaphljs.ts","./src/features/snap/contract/types.ts","./src/features/snap/hooks/useescapekey.ts","./src/features/snap/hooks/usesnapchat.ts","./src/features/snap/lib/format.ts","./src/features/snap/pages/newchatpage.tsx","./src/features/snap/pages/sessionchatpage.tsx","./src/features/snap/pages/sessionlistpage.tsx","./src/features/snap/store/snapchatstore.ts","./src/features/snippets/types.ts","./src/features/snippets/api/snippets.api.ts","./src/features/snippets/components/categorychips.tsx","./src/features/snippets/components/editdialog.tsx","./src/features/snippets/components/previewpane.tsx","./src/features/snippets/components/snippetrow.tsx","./src/features/snippets/core/ranking.ts","./src/features/snippets/core/search.ts","./src/features/snippets/hooks/usesnippets.ts","./src/features/snippets/pages/snippetpalettepage.tsx","./src/lib/api/client.ts","./src/lib/api/errors.ts","./src/lib/auth/msal.ts","./src/lib/auth/tokenprovider.ts","./src/lib/bridge/bridgenavigate.ts","./src/lib/bridge/snippetbridge.ts","./src/lib/bridge/transport.ts","./src/lib/bridge/webviewbridge.ts","./src/lib/hooks/usedebounce.ts","./src/lib/query/queryclient.ts","./src/lib/streaming/stoppednotice.tsx","./src/lib/streaming/streamingtext.tsx","./src/lib/streaming/abort.ts","./src/lib/streaming/index.ts","./src/lib/streaming/sse.ts","./src/lib/streaming/streamllm.ts","./src/lib/streaming/usesmoothedtext.ts","./src/lib/streaming/usestreamsession.ts","./src/lib/utils/cn.ts","./src/lib/utils/randomid.ts","./src/lib/utils/relativetime.ts","./src/lib/utils/sleep.ts","./src/shared/components/centerspinner.tsx","./src/shared/components/desktopwindowframe.tsx","./src/shared/components/errorboundary.tsx","./src/shared/components/kbd.tsx","./src/shared/components/layout.tsx","./src/shared/components/logomark.tsx","./src/shared/components/paletteshell.tsx","./src/shared/components/pastetargetbadge.tsx","./src/shared/components/protectedroute.tsx","./src/shared/components/themetoggle.tsx","./src/shared/hooks/usepastetarget.ts","./src/shared/store/themestore.ts","./src/shared/theme/derive.ts","./src/shared/theme/palettes.ts","./src/shared/theme/usetheme.ts","./src/shared/ui/alert-dialog.tsx","./src/shared/ui/alert.tsx","./src/shared/ui/button.tsx","./src/shared/ui/dialog.tsx","./src/shared/ui/dropdown-menu.tsx","./src/shared/ui/input.tsx","./src/shared/ui/label.tsx","./src/shared/ui/separator.tsx","./src/shared/ui/skeleton.tsx","./src/shared/ui/textarea.tsx","./src/shared/ui/tooltip.tsx","./src/types/api.ts"],"version":"5.9.3"}
|
||||
Reference in New Issue
Block a user