diff --git a/app/api/og/route.tsx b/app/api/og/route.tsx index 95efc5c2..b6f63950 100644 --- a/app/api/og/route.tsx +++ b/app/api/og/route.tsx @@ -40,7 +40,7 @@ export async function GET(req: NextRequest) { flexDirection: 'column', alignItems: 'flex-start', justifyContent: 'center', - backgroundImage: 'linear-gradient(to bottom right, #EAEBEA, #E0E1E3)', + backgroundImage: 'linear-gradient(to bottom right, #ECEEEF, #E1E4E7)', padding: '80px', }} > @@ -86,8 +86,8 @@ export async function GET(req: NextRequest) { key={tag} style={{ display: 'flex', - backgroundColor: '#E0E1E3', - color: '#3F3F46', + backgroundColor: '#E1E4E7', + color: '#A6294D', padding: '8px 24px', borderRadius: '50px', fontSize: '24px', @@ -114,7 +114,7 @@ export async function GET(req: NextRequest) { style={{ fontSize: '32px', fontWeight: 700, - color: '#3F3F46', + color: '#A6294D', fontFamily: 'Pretendard', }} > diff --git a/app/icon.png b/app/icon.png deleted file mode 100644 index 0d48fbca..00000000 Binary files a/app/icon.png and /dev/null differ diff --git a/app/icon.svg b/app/icon.svg new file mode 100644 index 00000000..a78cbb89 --- /dev/null +++ b/app/icon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/layout.tsx b/app/layout.tsx index 7cecc553..44d4d429 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -56,7 +56,7 @@ export const metadata: Metadata = { }; export const viewport: Viewport = { - themeColor: '#EAEBEA', + themeColor: '#ECEEEF', width: 'device-width', initialScale: 1, }; diff --git a/app/not-found.tsx b/app/not-found.tsx index 6d7012d4..022e77bf 100644 --- a/app/not-found.tsx +++ b/app/not-found.tsx @@ -17,7 +17,7 @@ export default function NotFound() {

홈으로 돌아가기 diff --git a/blog/ui/components/ReadingProgress/ReadingProgress.test.tsx b/blog/ui/components/ReadingProgress/ReadingProgress.test.tsx index bb755773..076e9a00 100644 --- a/blog/ui/components/ReadingProgress/ReadingProgress.test.tsx +++ b/blog/ui/components/ReadingProgress/ReadingProgress.test.tsx @@ -26,7 +26,7 @@ vi.mock('framer-motion', () => ({ }) => { const className = props.className as string; const testId = - className.includes('bg-[var(--color-accent)]') && + className.includes('bg-[var(--color-accent-fill)]') && className.includes('h-full') ? 'reading-progress-bar' : 'reading-progress-root'; diff --git a/blog/ui/components/ReadingProgress/ReadingProgress.tsx b/blog/ui/components/ReadingProgress/ReadingProgress.tsx index 632b485d..9ac8373b 100644 --- a/blog/ui/components/ReadingProgress/ReadingProgress.tsx +++ b/blog/ui/components/ReadingProgress/ReadingProgress.tsx @@ -39,7 +39,7 @@ export default function ReadingProgress() { > diff --git a/blog/ui/pages/EngineeringPageClient.tsx b/blog/ui/pages/EngineeringPageClient.tsx index f11684f9..cbb4c2fa 100644 --- a/blog/ui/pages/EngineeringPageClient.tsx +++ b/blog/ui/pages/EngineeringPageClient.tsx @@ -114,7 +114,7 @@ export default function EngineeringPageClient({ className={clsx( 'rounded border px-3 py-1.5 transition-colors', page === currentPage - ? 'border-[var(--color-accent)] bg-[var(--color-accent)] text-[var(--color-accent-foreground)]' + ? 'border-[var(--color-accent-fill)] bg-[var(--color-accent-fill)] text-[var(--color-accent-foreground)]' : 'border-[var(--color-grey-200)] bg-[var(--color-bg-primary)] text-[var(--color-grey-700)] hover:bg-[var(--color-grey-50)]' )} > diff --git a/docs/README.md b/docs/README.md index 5c283d91..dbb7ec2b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # 문서 인덱스 -Last updated: 2026-07-28 +Last updated: 2026-07-31 이 인덱스는 현재 코드베이스와 함께 유지해야 하는 문서만 추적한다. 계속 업데이트할 문서가 아니라면 삭제하거나, 오래 남겨야 하는 결정만 ADR로 옮긴다. @@ -51,6 +51,7 @@ Last updated: 2026-07-28 - `docs/adr/0050-retire-series-navigation-and-enforce-listed-post-policy.md` - `docs/adr/0052-use-repo-local-public-writing-review-workflow.md` - `docs/adr/0053-use-inline-table-of-contents-for-article-reading.md` +- `docs/adr/0054-adopt-cool-paper-and-plum-accent-palette.md` - `docs/blog-quality-guide.md` - `docs/content-publication-candidates.md` - `docs/database/db-schema.md` diff --git a/docs/adr/0054-adopt-cool-paper-and-plum-accent-palette.md b/docs/adr/0054-adopt-cool-paper-and-plum-accent-palette.md new file mode 100644 index 00000000..45bdd4a9 --- /dev/null +++ b/docs/adr/0054-adopt-cool-paper-and-plum-accent-palette.md @@ -0,0 +1,39 @@ +# 0054. 차가운 종이와 매화색 포인트 팔레트를 채택한다 + +Date: 2026-07-31 +Status: Accepted + +## 배경 + +Ark의 기존 무채색 Graphite Ink 지면은 차분하지만 행동 요소와 링크가 본문 +잉크에 묻혔다. 배경은 노란 기를 더하지 않은 종이색으로 유지하고, 매화에서 +가져온 홍자주를 단일 포인트로 사용한다. + +## 결정 + +- 기본 지면과 surface는 `#ECEEEF`로 둔다. +- 본문과 링크 텍스트에는 `#A6294D`를 사용한다. `#ECEEEF` 위 대비는 5.92:1이다. +- 버튼, 진행 표시, 선택된 페이지에는 `#D02D60`을 사용하고, 글자는 흰색으로 + 둔다. 흰색 위 대비는 4.97:1이다. +- hover와 고대비 모드에서는 더 어두운 `#8F2044`를 사용한다. +- 기존 Graphite Ink의 무채색 보조 텍스트와 구조선은 유지한다. + +## 결과 + +- 긴 읽기 지면은 쿨그레이 톤을 유지한다. +- 행동, 링크, 포커스가 한 가지 매화색 계열로 연결된다. +- 같은 색을 텍스트와 버튼 배경에 무리하게 재사용하지 않아 접근성 대비를 + 유지한다. + +## 검토한 대안 + +- `#D02D60` 단일 토큰: 버튼에는 적합하지만 `#ECEEEF` 위 본문 링크 대비가 + 4.27:1로 부족하다. +- `#DC2A61`: 매화 인상은 강하지만 버튼 배경과 흰색 글자 대비가 4.62:1로 + 경계선에 가깝다. +- 기존 무채색 포인트: 안전하지만 새 테마의 매화색 정체성이 드러나지 않는다. + +## Related History + +- [ADR 0034](0034-adopt-the-graphite-ink-palette.md): 기존 무채색 Graphite Ink + 팔레트 diff --git a/docs/adr/README.md b/docs/adr/README.md index 48a94020..087b5777 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -1,6 +1,6 @@ # Architecture Decision Records -Last updated: 2026-07-24 +Last updated: 2026-07-31 이 디렉터리는 커밋 히스토리에서 복원한 아키텍처 의사결정을 기록한다. ADR은 AI 협업 가이드와 별개의 문서다. 사람이 결정했든 AI가 초안을 @@ -71,6 +71,7 @@ ADR은 AI 협업 가이드와 별개의 문서다. 사람이 결정했든 AI가 | [0051](0051-use-viewport-specific-reading-layout-and-type-scale.md) | Accepted | viewport별 읽기 레이아웃과 타이포그래피 스케일을 사용한다 | | [0052](0052-use-repo-local-public-writing-review-workflow.md) | Accepted | 공개 글 검토에 repo-local writing review workflow를 사용한다 | | [0053](0053-use-inline-table-of-contents-for-article-reading.md) | Accepted | 글 읽기 흐름에 인라인 목차를 사용한다 | +| [0054](0054-adopt-cool-paper-and-plum-accent-palette.md) | Accepted | 차가운 종이와 매화색 포인트 팔레트를 채택한다 | ## 작성 조건 diff --git a/public/brand/graphite-blossom-mark.svg b/public/brand/graphite-blossom-mark.svg new file mode 100644 index 00000000..4db3d185 --- /dev/null +++ b/public/brand/graphite-blossom-mark.svg @@ -0,0 +1,20 @@ + + Graphite blossom mark + A transparent five-petal graphite plum blossom with a plum center. + + + + + + + + + + + + + + + + + diff --git a/public/brand/graphite-seal-blossom.svg b/public/brand/graphite-seal-blossom.svg new file mode 100644 index 00000000..4a1bcf3e --- /dev/null +++ b/public/brand/graphite-seal-blossom.svg @@ -0,0 +1,22 @@ + + Graphite seal blossom + An original five-petal plum blossom impressed into a graphite seal. + + + + + + + + + + + + + + + + + + + diff --git a/site/shell/AppShell/AppShell.test.tsx b/site/shell/AppShell/AppShell.test.tsx index 87cfce33..f7267ba4 100644 --- a/site/shell/AppShell/AppShell.test.tsx +++ b/site/shell/AppShell/AppShell.test.tsx @@ -27,6 +27,10 @@ describe('AppShell', () => { primaryNavigation.queryByRole('link', { name: 'Tech' }) ).not.toBeInTheDocument(); expect(screen.getAllByLabelText('Ark 외부 링크')).toHaveLength(1); + expect(screen.getByRole('link', { name: 'ark 홈으로 이동' })).toHaveTextContent( + 'ark' + ); + expect(screen.queryByAltText('')).not.toBeInTheDocument(); expect(container.querySelector('footer')).toContainElement( screen.getByLabelText('Ark 외부 링크') ); @@ -47,5 +51,9 @@ describe('AppShell', () => { 'aria-current', 'page' ); + expect(screen.getByAltText('')).toHaveAttribute( + 'src', + '/brand/graphite-blossom-mark.svg' + ); }); }); diff --git a/site/shell/AppShell/AppShell.tsx b/site/shell/AppShell/AppShell.tsx index 745d0b58..ab3bb730 100644 --- a/site/shell/AppShell/AppShell.tsx +++ b/site/shell/AppShell/AppShell.tsx @@ -81,7 +81,15 @@ export default function AppShell({ children }: AppShellProps) { aria-label="ark 홈으로 이동" className="ark-site-brand-link transition-colors hover:text-[var(--color-text-secondary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-bg-primary)]" > - ark + {pathname !== '/' ? ( + + ) : null} + ark diff --git a/styles/globals.css b/styles/globals.css index da59496b..231bd7e1 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -45,6 +45,7 @@ .ark-site-brand-link { display: flex; align-items: center; + gap: var(--space-2); min-height: 3rem; color: var(--color-text-primary); font-size: var(--text-base); @@ -54,6 +55,12 @@ pointer-events: auto; } +.ark-site-brand-mark { + width: 1.75rem; + height: 1.75rem; + flex: none; +} + .ark-site-content { grid-column: 2; grid-row: 1; @@ -893,7 +900,7 @@ .prose .workflow-scroll-fill { height: 100%; - background: var(--color-accent); + background: var(--color-accent-fill); transition: width 180ms ease; } diff --git a/styles/globals.test.ts b/styles/globals.test.ts index bf953d15..7278af69 100644 --- a/styles/globals.test.ts +++ b/styles/globals.test.ts @@ -92,7 +92,7 @@ describe('globals styles', () => { it('keeps inline code lighter than fenced code blocks', () => { expect(tokensContent).toContain('--color-code-inline-bg: #d8d8dc;'); expect(tokensContent).toContain('--color-code-inline-fg: #52525b;'); - expect(tokensContent).toContain('--color-code-bg: #3f3f46;'); + expect(tokensContent).toContain('--color-code-bg: #252525;'); expect(globalsContent).toContain( '.prose :not(pre) > code {\n background-color: var(--color-code-inline-bg);' ); diff --git a/styles/tokens.css b/styles/tokens.css index 39f1d674..a6f158ba 100644 --- a/styles/tokens.css +++ b/styles/tokens.css @@ -6,9 +6,10 @@ /* === Colors === */ /* Accent */ - --color-accent: #3f3f46; - --color-accent-hover: #252525; - --color-accent-foreground: #eaebea; + --color-accent: #a6294d; + --color-accent-fill: #d02d60; + --color-accent-hover: #8f2044; + --color-accent-foreground: #ffffff; /* Grey Scale */ --color-grey-900: #252525; @@ -28,10 +29,10 @@ --color-text-tertiary: #62626a; --color-text-disabled: #94949a; - --color-bg-primary: #eaebea; - --color-bg-secondary: #e2e2e5; - --color-bg-tertiary: #d8d8dc; - --color-surface: #eaebea; + --color-bg-primary: #eceeef; + --color-bg-secondary: #e2e4e7; + --color-bg-tertiary: #d8dade; + --color-surface: #eceeef; --color-border: #c8c8cc; --color-border-hover: #94949a; @@ -46,22 +47,22 @@ --mobile-nav-shadow: 0 8px 24px rgba(37, 37, 37, 0.12); --mobile-nav-text: var(--color-text-secondary); --mobile-nav-active-text: var(--color-text-primary); - --mobile-nav-active-bg: #e0e1e3; + --mobile-nav-active-bg: #e1e4e7; --mobile-nav-active-border: var(--color-border); --mobile-nav-hover-bg: var(--color-bg-secondary); - --mobile-nav-focus-ring: var(--color-accent); + --mobile-nav-focus-ring: var(--color-accent-fill); --mobile-nav-focus-offset: var(--mobile-nav-bg); /* Code Block Colors */ - --color-code-bg: #3f3f46; - --color-code-fg: #e2e2e5; + --color-code-bg: #252525; + --color-code-fg: #eceeef; --color-code-inline-bg: #d8d8dc; --color-code-inline-fg: #52525b; - --color-code-title-bg: #52525b; - --color-code-title-fg: #eaebea; - --color-code-highlight: rgba(234, 235, 234, 0.12); - --color-code-divider: rgba(234, 235, 234, 0.16); - --shiki-dark: #eaebea; + --color-code-title-bg: #3f3f46; + --color-code-title-fg: #eceeef; + --color-code-highlight: rgba(236, 238, 239, 0.12); + --color-code-divider: rgba(236, 238, 239, 0.16); + --shiki-dark: #eceeef; /* Feedback Colors */ --color-success: #3f3f46; @@ -254,7 +255,8 @@ --color-border: #62626a; --color-border-hover: #3f3f46; --color-divider: #94949a; - --color-accent: #252525; - --color-accent-hover: #252525; + --color-accent: #8f2044; + --color-accent-fill: #a6294d; + --color-accent-hover: #8f2044; } } diff --git a/styles/tokens.test.ts b/styles/tokens.test.ts index 55f2e14e..d733140e 100644 --- a/styles/tokens.test.ts +++ b/styles/tokens.test.ts @@ -31,17 +31,18 @@ describe('Ark paper token definitions', () => { expect(tokensContent).toContain('--mobile-nav-focus-offset'); }); - it('uses the Graphite Ink palette instead of dark-mode overrides', () => { - expect(tokensContent).toContain('--color-bg-primary: #eaebea;'); + it('uses the cool-paper and plum palette instead of dark-mode overrides', () => { + expect(tokensContent).toContain('--color-bg-primary: #eceeef;'); expect(tokensContent).toContain('--color-text-primary: #252525;'); - expect(tokensContent).toContain('--color-accent: #3f3f46;'); - expect(tokensContent).toContain('--color-surface: #eaebea;'); + expect(tokensContent).toContain('--color-accent: #a6294d;'); + expect(tokensContent).toContain('--color-accent-fill: #d02d60;'); + expect(tokensContent).toContain('--color-surface: #eceeef;'); expect(tokensContent).not.toContain('.dark {'); }); it('reuses the accent token for mobile navigation focus', () => { expect(tokensContent).toContain( - '--mobile-nav-focus-ring: var(--color-accent);' + '--mobile-nav-focus-ring: var(--color-accent-fill);' ); }); }); diff --git a/tooling/ark-graphite-intellij-theme/.gitignore b/tooling/ark-graphite-intellij-theme/.gitignore new file mode 100644 index 00000000..2c301d7e --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/.gitignore @@ -0,0 +1,3 @@ +/build/ +/dist/ +.DS_Store diff --git a/tooling/ark-graphite-intellij-theme/LICENSE b/tooling/ark-graphite-intellij-theme/LICENSE new file mode 100644 index 00000000..3732ca22 --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/LICENSE @@ -0,0 +1,198 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Eunwoo Park + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/tooling/ark-graphite-intellij-theme/README.md b/tooling/ark-graphite-intellij-theme/README.md new file mode 100644 index 00000000..02777798 --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/README.md @@ -0,0 +1,56 @@ +# Graphite Theme + +![Graphite Theme Kotlin editor preview](assets/overview-kotlin.png) + +## English + +Graphite Theme is a quiet paper-and-ink theme for IntelliJ Platform IDEs. + +Built from the design system of my personal blog, it pairs a soft paper +background with graphite ink. When the code gets loud, the screen stays +calm—one small aid for becoming the developer who does not get angry at the +compiler. :) + +## 한국어 + +개인 블로그를 운영하며 사용하던 디자인 시스템을 IntelliJ Platform 테마로 +만들었습니다. + +종이 배경에 먹색을 조합한 차분한 테마입니다. 코드가 시끄러워질수록 화면은 +조용하게. 컴파일러에게 화내지 않는 개발자가 되기 위한 작은 장치입니다. :) + +## Features + +- IntelliJ Light 기반 Paper / Graphite Ink palette +- D2Coding 13px editor and console scheme +- Paper-like editor background, graphite UI, low-saturation syntax colors + +## Install + +Install **Graphite Theme** from the JetBrains Marketplace: + +1. Open `Settings | Plugins | Marketplace`. +2. Search for `Graphite Theme` and install it. +3. Restart the IDE if prompted. +4. Select `Graphite Theme` from + `Settings | Appearance & Behavior | Appearance`. + +For offline installation, download the ZIP from [Releases](../../releases), +then choose `Plugins | ⚙ | Install Plugin from Disk...`. + +`D2Coding`이 설치되어 있지 않으면 IDE 기본 monospace font를 사용한다. + +## Build + +```sh +./package.sh +``` + +`dist/graphite-theme.zip`이 생성된다. 이 플러그인은 코드나 외부 +의존성이 없는 리소스 전용 테마다. + +## License + +Copyright 2026 Eunwoo Park. + +Distributed under the [Apache License 2.0](LICENSE). diff --git a/tooling/ark-graphite-intellij-theme/assets/icon-concepts.svg b/tooling/ark-graphite-intellij-theme/assets/icon-concepts.svg new file mode 100644 index 00000000..b824d8f7 --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/assets/icon-concepts.svg @@ -0,0 +1,71 @@ + + Graphite Theme icon concepts + Eight original icon directions using paper, graphite, and plum colors. + + + Graphite Theme — icon concept board + paper · graphite · plum / original reinterpretations of a five-petal rotation + + + + 01Ink-line plum + + + quiet, most legible + + + + 02Dry-brush plum + brush gesture, airy + + + + 03Seal blossom + + + stamp-like, strongest badge + + + + 04Graphite fracture + + + name-driven, distinctive + + + + 05Code blossom + + + developer signal, minimal + + + + 06Brush orbit + + + one stroke, restrained motion + + + + 07Moon branch + + + + calmest, editorial feel + + + + 08Window lattice + + + + architectural, most abstract + diff --git a/tooling/ark-graphite-intellij-theme/assets/overview-kotlin.png b/tooling/ark-graphite-intellij-theme/assets/overview-kotlin.png new file mode 100644 index 00000000..46f059dc Binary files /dev/null and b/tooling/ark-graphite-intellij-theme/assets/overview-kotlin.png differ diff --git a/tooling/ark-graphite-intellij-theme/assets/plum-to-pink-scale.svg b/tooling/ark-graphite-intellij-theme/assets/plum-to-pink-scale.svg new file mode 100644 index 00000000..984ac9cf --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/assets/plum-to-pink-scale.svg @@ -0,0 +1,23 @@ + + 10-step scale from #963B5E to #FF2262 + + + #963B5E → #FF2262 / 10 steps + + 01#963B5E + 02#A2385E + 03#AD355F + 04#B9335F + 05#C53060 + 06#D02D60 + 07#DC2A61 + 08#E82861 + 09#F32562 + 10#FF2262 + + diff --git a/tooling/ark-graphite-intellij-theme/package.sh b/tooling/ark-graphite-intellij-theme/package.sh new file mode 100755 index 00000000..6d5e5ece --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/package.sh @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu + +root_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +build_dir="$root_dir/build/ark-graphite-intellij-theme" +dist_dir="$root_dir/dist" + +rm -rf "$build_dir" +mkdir -p "$build_dir/lib" "$dist_dir" + +( + cd "$root_dir/src/main/resources" + jar --create --file "$build_dir/lib/ark-graphite-intellij-theme.jar" . +) + +rm -f "$dist_dir/graphite-theme.zip" "$dist_dir/ark-graphite-intellij-theme.zip" +( + cd "$root_dir/build" + zip -qr "$dist_dir/graphite-theme.zip" ark-graphite-intellij-theme +) diff --git a/tooling/ark-graphite-intellij-theme/src/main/resources/ArkGraphite.theme.json b/tooling/ark-graphite-intellij-theme/src/main/resources/ArkGraphite.theme.json new file mode 100644 index 00000000..94a3d238 --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/src/main/resources/ArkGraphite.theme.json @@ -0,0 +1,87 @@ +{ + "name": "Graphite Theme", + "author": "Eunwoo Park", + "dark": false, + "editorScheme": "/ArkGraphite.xml", + "ui": { + "*": { + "background": "#eaebea", + "foreground": "#252525" + }, + "Panel.background": "#eaebea", + "Editor.background": "#eaebea", + "Editor.foreground": "#252525", + "EditorPane.background": "#eaebea", + "TextField.background": "#f2f2f3", + "TextField.foreground": "#252525", + "TextField.inactiveBackground": "#e2e2e5", + "TextField.selectionBackground": "#d8d8dc", + "TextField.selectionForeground": "#252525", + "PasswordField.background": "#f2f2f3", + "ComboBox.background": "#f2f2f3", + "ComboBox.foreground": "#252525", + "ComboBox.disabledBackground": "#e2e2e5", + "Button.background": "#e2e2e5", + "Button.foreground": "#252525", + "Button.focusedBorderColor": "#3f3f46", + "Button.default.background": "#3f3f46", + "Button.default.foreground": "#eaebea", + "Component.borderColor": "#c8c8cc", + "Component.focusedBorderColor": "#3f3f46", + "Component.disabledBorderColor": "#d8d8dc", + "Focus.borderColor": "#3f3f46", + "Separator.foreground": "#d8d8dc", + "Separator.background": "#eaebea", + "ScrollBar.background": "#eaebea", + "ScrollBar.thumb": "#c8c8cc", + "ScrollBar.hoverTrackColor": "#e2e2e5", + "ScrollBar.hoverThumbColor": "#94949a", + "ToolTip.background": "#252525", + "ToolTip.foreground": "#eaebea", + "ToolTip.borderColor": "#3f3f46", + "List.background": "#eaebea", + "List.foreground": "#252525", + "List.selectionBackground": "#d8d8dc", + "List.selectionForeground": "#252525", + "Tree.background": "#eaebea", + "Tree.foreground": "#252525", + "Tree.selectionBackground": "#d8d8dc", + "Tree.selectionForeground": "#252525", + "Table.background": "#eaebea", + "Table.foreground": "#252525", + "Table.selectionBackground": "#d8d8dc", + "Table.selectionForeground": "#252525", + "TableHeader.background": "#e2e2e5", + "TableHeader.foreground": "#252525", + "Menu.background": "#f2f2f3", + "Menu.foreground": "#252525", + "MenuItem.background": "#f2f2f3", + "MenuItem.foreground": "#252525", + "MenuItem.selectionBackground": "#d8d8dc", + "MenuItem.selectionForeground": "#252525", + "PopupMenu.background": "#f2f2f3", + "Popup.border": "#c8c8cc", + "StatusBar.background": "#e2e2e5", + "StatusBar.foreground": "#52525b", + "ToolWindow.Header.background": "#eaebea", + "ToolWindow.Header.inactiveBackground": "#eaebea", + "ToolWindow.Header.borderColor": "#d8d8dc", + "ToolWindow.Button.selectedBackground": "#d8d8dc", + "ToolWindow.Button.selectedForeground": "#252525", + "ToolWindow.Button.hoverBackground": "#e2e2e5", + "EditorTabs.background": "#e2e2e5", + "EditorTabs.inactiveBackground": "#e2e2e5", + "EditorTabs.selectedBackground": "#eaebea", + "EditorTabs.selectedForeground": "#252525", + "EditorTabs.inactiveForeground": "#62626a", + "EditorTabs.underlinedTabBackground": "#eaebea", + "EditorTabs.underlineColor": "#3f3f46", + "EditorTabs.borderColor": "#c8c8cc", + "Notification.background": "#f2f2f3", + "Notification.borderColor": "#c8c8cc", + "Notification.foreground": "#252525", + "ProgressBar.background": "#e2e2e5", + "ProgressBar.foreground": "#3f3f46", + "VersionControl.Log.CommitGraph.color": "#3f3f46" + } +} diff --git a/tooling/ark-graphite-intellij-theme/src/main/resources/ArkGraphite.xml b/tooling/ark-graphite-intellij-theme/src/main/resources/ArkGraphite.xml new file mode 100644 index 00000000..deeae44f --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/src/main/resources/ArkGraphite.xml @@ -0,0 +1,83 @@ + + diff --git a/tooling/ark-graphite-intellij-theme/src/main/resources/META-INF/plugin.xml b/tooling/ark-graphite-intellij-theme/src/main/resources/META-INF/plugin.xml new file mode 100644 index 00000000..3e732d74 --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,33 @@ + + io.github.devwooyeon.graphite + Graphite Theme + 1.0.5 + Eunwoo Park (박은우) + + Graphite Theme is a quiet paper-and-ink theme for IntelliJ Platform IDEs.

+

Built from the design system of my personal blog, it pairs a soft paper + background with graphite ink. When the code gets loud, the screen stays + calm—one small aid for becoming the developer who does not get angry at the + compiler. :)

+
+

한국어

+

개인 블로그를 운영하며 사용하던 디자인 시스템을 IntelliJ Platform 테마로 + 만들었습니다.

+

종이 배경에 먹색을 조합한 차분한 테마입니다. 코드가 시끄러워질수록 화면은 + 조용하게. 컴파일러에게 화내지 않는 개발자가 되기 위한 작은 장치입니다. :)

+ ]]>
+ + + + + com.intellij.modules.platform + + + + +
diff --git a/tooling/ark-graphite-intellij-theme/src/main/resources/META-INF/pluginIcon.svg b/tooling/ark-graphite-intellij-theme/src/main/resources/META-INF/pluginIcon.svg new file mode 100644 index 00000000..801cd435 --- /dev/null +++ b/tooling/ark-graphite-intellij-theme/src/main/resources/META-INF/pluginIcon.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ui/Button/Button.tsx b/ui/Button/Button.tsx index 394e043a..b71f96a7 100644 --- a/ui/Button/Button.tsx +++ b/ui/Button/Button.tsx @@ -12,7 +12,7 @@ import { const variantStyles: Record = { primary: - 'bg-[var(--color-accent)] text-[var(--color-accent-foreground)] hover:opacity-80 active:scale-[0.98]', + 'bg-[var(--color-accent-fill)] text-[var(--color-accent-foreground)] hover:bg-[var(--color-accent-hover)] active:scale-[0.98]', secondary: 'bg-[var(--color-grey-100)] text-[var(--color-grey-900)] hover:bg-[var(--color-grey-200)] active:scale-[0.98]', tertiary: @@ -44,7 +44,7 @@ const Button = forwardRef( 'inline-flex items-center justify-center gap-2', 'font-medium transition-all', 'duration-[var(--duration-150)] ease-[var(--ease-default)]', - 'focus-visible:outline-2 focus-visible:outline-[var(--color-accent)] focus-visible:outline-offset-2', + 'focus-visible:outline-2 focus-visible:outline-[var(--color-accent-fill)] focus-visible:outline-offset-2', 'disabled:opacity-40 disabled:cursor-not-allowed disabled:pointer-events-none', variantStyles[variant], sizeStyles[size],