Skip to content

Commit 4cd0c0d

Browse files
authored
Merge pull request #6 from hirano00o/feat/auto-theme-switching
fix: ダークモードでプレーンテキストが背景と同化する問題を修正
2 parents e5d2b97 + 4cb2ef1 commit 4cd0c0d

9 files changed

Lines changed: 463 additions & 38 deletions

README.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,30 +97,44 @@ https://github.com/owner/repo/blob/main/src/index.ts#L1-L10
9797

9898
## ダークモード
9999

100-
ダークテーマ対応サイト向けに、GitHub Dark Default テーマ準拠の別バンドルを用意しています。
100+
デフォルトの `git-code-embed.min.js``prefers-color-scheme` メディアクエリで OS のテーマ設定に自動追従します。
101+
ライトモード固定・ダークモード固定のバンドルも用意しています。
101102

102-
```html
103-
<script src="https://cdn.jsdelivr.net/gh/hirano00o/git-code-embed@v0/dist/git-code-embed-dark.min.js"></script>
104-
```
103+
| ファイル | 挙動 |
104+
|---|---|
105+
| `git-code-embed.min.js` | OS のダーク/ライト設定に自動追従(推奨) |
106+
| `git-code-embed-light.min.js` | ライトモード固定 |
107+
| `git-code-embed-dark.min.js` | ダークモード固定 |
105108

106-
### はてなブログ(ダークテーマ)での使い方
109+
### はてなブログでの使い方
107110

108-
管理画面の **設定 → 詳細設定**`<head>` 要素欄に、ダーク版の URL を貼り付けます。
111+
管理画面の **設定 → 詳細設定**`<head>` 要素欄に以下を貼り付けます。
112+
OS テーマに自動追従させる場合はデフォルトの URL をそのまま使用してください。
109113

110114
```html
115+
<!-- OS のダーク/ライト設定に自動追従(推奨) -->
116+
<script src="https://cdn.jsdelivr.net/gh/hirano00o/git-code-embed@v0/dist/git-code-embed.min.js" defer></script>
117+
118+
<!-- ダークモード固定 -->
111119
<script src="https://cdn.jsdelivr.net/gh/hirano00o/git-code-embed@v0/dist/git-code-embed-dark.min.js" defer></script>
120+
121+
<!-- ライトモード固定 -->
122+
<script src="https://cdn.jsdelivr.net/gh/hirano00o/git-code-embed@v0/dist/git-code-embed-light.min.js" defer></script>
112123
```
113124

114125
### ビルド
115126

116127
```bash
117-
# ライトモード(デフォルト) → dist/git-code-embed.min.js
128+
# オートテーマ(デフォルト、OS のダーク/ライト設定に自動追従) → dist/git-code-embed.min.js
118129
npm run build
119130

120-
# ダークモード → dist/git-code-embed-dark.min.js
131+
# ライトモード固定 → dist/git-code-embed-light.min.js
132+
npm run build:light
133+
134+
# ダークモード固定 → dist/git-code-embed-dark.min.js
121135
npm run build:dark
122136

123-
# 両方同時にビルド
137+
# 全バリアント同時ビルド
124138
npm run build:all
125139
```
126140

dist/git-code-embed-dark.min.js

Lines changed: 58 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/git-code-embed-light.min.js

Lines changed: 245 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/git-code-embed.min.js

Lines changed: 58 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esbuild.config.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import * as esbuild from "esbuild";
22

33
const dark = process.argv.includes("--dark");
4-
const theme = dark ? "dark" : "light";
4+
const auto = process.argv.includes("--auto");
5+
const theme = dark ? "dark" : auto ? "auto" : "light";
56
const outfile = dark
67
? "dist/git-code-embed-dark.min.js"
7-
: "dist/git-code-embed.min.js";
8+
: auto
9+
? "dist/git-code-embed.min.js"
10+
: "dist/git-code-embed-light.min.js";
811

912
esbuild
1013
.build({

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "git-code-embed",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "Embed GitHub code snippets with syntax highlighting in blog posts",
55
"main": "dist/git-code-embed.min.js",
66
"scripts": {
7-
"build": "tsx esbuild.config.ts",
7+
"build": "tsx esbuild.config.ts --auto",
8+
"build:light": "tsx esbuild.config.ts",
89
"build:dark": "tsx esbuild.config.ts --dark",
9-
"build:all": "tsx esbuild.config.ts && tsx esbuild.config.ts --dark",
10+
"build:all": "tsx esbuild.config.ts --auto && tsx esbuild.config.ts && tsx esbuild.config.ts --dark",
1011
"test": "vitest run",
1112
"test:watch": "vitest"
1213
},

src/styles.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const LIGHT_COLORS = `
1818
--gce-lineno-color: #6e7781;
1919
--gce-lineno-bg: #f6f8fa;
2020
--gce-code-bg: #ffffff;
21+
--gce-code-text: #24292f;
2122
--gce-scrollbar-thumb: #afb8c1;
2223
}
2324
@@ -62,6 +63,7 @@ export const DARK_COLORS = `
6263
--gce-lineno-color: #8b949e;
6364
--gce-lineno-bg: #161b22;
6465
--gce-code-bg: #0d1117;
66+
--gce-code-text: #e6edf3;
6567
--gce-scrollbar-thumb: #484f58;
6668
}
6769
@@ -96,7 +98,15 @@ export const DARK_COLORS = `
9698
.gce-container .hljs-doctag { color: #79c0ff; }
9799
`;
98100

99-
const THEME_COLORS = __THEME__ === "dark" ? DARK_COLORS : LIGHT_COLORS;
101+
export function buildThemeCSS(theme: string): string {
102+
if (theme === "dark") return DARK_COLORS;
103+
if (theme === "auto") {
104+
return `${LIGHT_COLORS}\n@media (prefers-color-scheme: dark) {\n${DARK_COLORS}\n}`;
105+
}
106+
return LIGHT_COLORS;
107+
}
108+
109+
const THEME_COLORS = buildThemeCSS(__THEME__);
100110

101111
export const CSS = `
102112
:root {
@@ -219,6 +229,7 @@ ${THEME_COLORS}
219229
.gce-container .gce-table td.gce-code {
220230
width: 100%;
221231
padding: 0 16px;
232+
color: var(--gce-code-text);
222233
line-height: var(--gce-line-height);
223234
white-space: pre;
224235
vertical-align: top;

test/styles.test.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { CSS, DARK_COLORS, LIGHT_COLORS } from "../src/styles";
2+
import { buildThemeCSS, CSS, DARK_COLORS, LIGHT_COLORS } from "../src/styles";
33

44
describe("LIGHT_COLORS", () => {
55
it("ライトテーマの背景色を含む", () => {
@@ -45,6 +45,10 @@ describe("LIGHT_COLORS", () => {
4545
expect(LIGHT_COLORS).toContain("color: #0550ae");
4646
});
4747

48+
it("ライトテーマの基本テキスト色を含む", () => {
49+
expect(LIGHT_COLORS).toContain("--gce-code-text: #24292f");
50+
});
51+
4852
it("ライトテーマのスクロールバー thumb 色を含む", () => {
4953
expect(LIGHT_COLORS).toContain("--gce-scrollbar-thumb: #afb8c1");
5054
});
@@ -94,11 +98,56 @@ describe("DARK_COLORS", () => {
9498
expect(DARK_COLORS).toContain("color: #79c0ff");
9599
});
96100

101+
it("ダークテーマの基本テキスト色を含む", () => {
102+
expect(DARK_COLORS).toContain("--gce-code-text: #e6edf3");
103+
});
104+
97105
it("ダークテーマのスクロールバー thumb 色を含む", () => {
98106
expect(DARK_COLORS).toContain("--gce-scrollbar-thumb: #484f58");
99107
});
100108
});
101109

110+
describe("buildThemeCSS", () => {
111+
it('"light" → LIGHT_COLORS のみ返す', () => {
112+
expect(buildThemeCSS("light")).toBe(LIGHT_COLORS);
113+
});
114+
115+
it('"dark" → DARK_COLORS のみ返す', () => {
116+
expect(buildThemeCSS("dark")).toBe(DARK_COLORS);
117+
});
118+
119+
it('"auto" → LIGHT_COLORS を含む', () => {
120+
expect(buildThemeCSS("auto")).toContain(LIGHT_COLORS);
121+
});
122+
123+
it('"auto" → DARK_COLORS が @media (prefers-color-scheme: dark) で囲まれている', () => {
124+
const css = buildThemeCSS("auto");
125+
const mediaStart = css.indexOf("@media (prefers-color-scheme: dark)");
126+
expect(mediaStart).toBeGreaterThan(-1);
127+
// DARK_COLORS はメディアクエリブロック内に含まれる
128+
const afterMedia = css.slice(mediaStart);
129+
expect(afterMedia).toContain(DARK_COLORS);
130+
});
131+
132+
it('"auto" → ダーク側の --gce-code-text が @media ブロック内に現れる', () => {
133+
const css = buildThemeCSS("auto");
134+
const mediaStart = css.indexOf("@media (prefers-color-scheme: dark)");
135+
expect(mediaStart).toBeGreaterThan(-1);
136+
const afterMedia = css.slice(mediaStart);
137+
expect(afterMedia).toContain("--gce-code-text: #e6edf3");
138+
});
139+
140+
it('"auto" → LIGHT_COLORS が DARK_COLORS より前に現れる', () => {
141+
const css = buildThemeCSS("auto");
142+
expect(css.indexOf(LIGHT_COLORS)).toBeLessThan(css.indexOf(DARK_COLORS));
143+
});
144+
145+
it('不明な値 → LIGHT_COLORS にフォールバック', () => {
146+
expect(buildThemeCSS("unknown")).toBe(LIGHT_COLORS);
147+
expect(buildThemeCSS("")).toBe(LIGHT_COLORS);
148+
});
149+
});
150+
102151
describe("CSS (テーマ: light)", () => {
103152
it("テーマ非依存の font-family 変数を含む", () => {
104153
expect(CSS).toContain("--gce-font-family:");
@@ -120,6 +169,12 @@ describe("CSS (テーマ: light)", () => {
120169
expect(CSS).toContain("display: flex");
121170
});
122171

172+
it("td.gce-code に基本テキスト色の CSS 変数を含む", () => {
173+
const match = CSS.match(/\.gce-container \.gce-table td\.gce-code \{([^}]*)\}/);
174+
expect(match).not.toBeNull();
175+
expect(match![1]).toContain("color: var(--gce-code-text)");
176+
});
177+
123178
it("scrollbar-color サポートブラウザ向けの @supports ブロックを含む", () => {
124179
expect(CSS).toContain("@supports (scrollbar-color: auto)");
125180
expect(CSS).toContain("scrollbar-color: var(--gce-scrollbar-thumb) var(--gce-code-bg)");

0 commit comments

Comments
 (0)