Skip to content

Commit c96b9cf

Browse files
authored
Merge pull request #4 from hirano00o/feat/dark-mode-build
feat: ダークモード対応ビルドを追加
2 parents 1bba225 + b9ee889 commit c96b9cf

8 files changed

Lines changed: 474 additions & 78 deletions

File tree

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,35 @@ https://github.com/owner/repo/blob/main/src/index.ts#L1-L10
9595
</p>
9696
```
9797

98+
## ダークモード
99+
100+
ダークテーマ対応サイト向けに、GitHub Dark Default テーマ準拠の別バンドルを用意しています。
101+
102+
```html
103+
<script src="https://cdn.jsdelivr.net/gh/hirano00o/git-code-embed@v0/dist/git-code-embed-dark.min.js"></script>
104+
```
105+
106+
### はてなブログ(ダークテーマ)での使い方
107+
108+
管理画面の **設定 → 詳細設定**`<head>` 要素欄に、ダーク版の URL を貼り付けます。
109+
110+
```html
111+
<script src="https://cdn.jsdelivr.net/gh/hirano00o/git-code-embed@v0/dist/git-code-embed-dark.min.js" defer></script>
112+
```
113+
114+
### ビルド
115+
116+
```bash
117+
# ライトモード(デフォルト) → dist/git-code-embed.min.js
118+
npm run build
119+
120+
# ダークモード → dist/git-code-embed-dark.min.js
121+
npm run build:dark
122+
123+
# 両方同時にビルド
124+
npm run build:all
125+
```
126+
98127
## 既知の制限
99128

100129
### スラッシュを含むブランチ名(例: `feature/my-branch`)は未対応

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

Lines changed: 180 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: 44 additions & 41 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esbuild.config.ts

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

3+
const dark = process.argv.includes("--dark");
4+
const theme = dark ? "dark" : "light";
5+
const outfile = dark
6+
? "dist/git-code-embed-dark.min.js"
7+
: "dist/git-code-embed.min.js";
8+
39
esbuild
410
.build({
511
entryPoints: ["src/main.ts"],
612
bundle: true,
713
minify: true,
814
format: "iife",
9-
outfile: "dist/git-code-embed.min.js",
15+
outfile,
1016
target: ["es2020", "chrome80", "firefox78", "safari14"],
1117
platform: "browser",
18+
define: {
19+
__THEME__: JSON.stringify(theme),
20+
},
1221
})
1322
.then(() => {
14-
console.log("Build complete: dist/git-code-embed.min.js");
23+
console.log(`Build complete: ${outfile}`);
1524
})
1625
.catch((err: unknown) => {
1726
console.error(err);

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"main": "dist/git-code-embed.min.js",
66
"scripts": {
77
"build": "tsx esbuild.config.ts",
8+
"build:dark": "tsx esbuild.config.ts --dark",
9+
"build:all": "tsx esbuild.config.ts && tsx esbuild.config.ts --dark",
810
"test": "vitest run",
911
"test:watch": "vitest"
1012
},

src/styles.ts

Lines changed: 91 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
/**
22
* CSS injected into the page as a single <style> tag.
33
* All class names use the `gce-` prefix to avoid collisions with host pages.
4+
*
5+
* Build-time constant __THEME__ selects the color palette.
6+
* Dead code elimination removes the unused palette from the bundle.
47
*/
5-
export const CSS = `
8+
9+
declare const __THEME__: string;
10+
11+
export const LIGHT_COLORS = `
612
:root {
7-
--gce-line-height: 1.5em;
8-
--gce-font-size: 13px;
9-
--gce-font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
10-
--gce-ui-font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
1113
--gce-bg: #f6f8fa;
1214
--gce-border: #d0d7de;
1315
--gce-header-bg: #f6f8fa;
@@ -18,6 +20,90 @@ export const CSS = `
1820
--gce-code-bg: #ffffff;
1921
}
2022
23+
.gce-container .hljs-keyword,
24+
.gce-container .hljs-selector-tag,
25+
.gce-container .hljs-built_in,
26+
.gce-container .hljs-name,
27+
.gce-container .hljs-tag { color: #cf222e; }
28+
29+
.gce-container .hljs-string,
30+
.gce-container .hljs-attr,
31+
.gce-container .hljs-symbol,
32+
.gce-container .hljs-bullet,
33+
.gce-container .hljs-addition { color: #0a3069; }
34+
35+
.gce-container .hljs-title,
36+
.gce-container .hljs-section,
37+
.gce-container .hljs-type,
38+
.gce-container .hljs-function { color: #8250df; }
39+
40+
.gce-container .hljs-variable,
41+
.gce-container .hljs-template-variable { color: #953800; }
42+
43+
.gce-container .hljs-comment,
44+
.gce-container .hljs-quote,
45+
.gce-container .hljs-deletion,
46+
.gce-container .hljs-meta { color: #6e7781; font-style: italic; }
47+
48+
.gce-container .hljs-number,
49+
.gce-container .hljs-regexp,
50+
.gce-container .hljs-literal,
51+
.gce-container .hljs-doctag { color: #0550ae; }
52+
`;
53+
54+
export const DARK_COLORS = `
55+
:root {
56+
--gce-bg: #161b22;
57+
--gce-border: #30363d;
58+
--gce-header-bg: #161b22;
59+
--gce-header-text: #e6edf3;
60+
--gce-header-link: #58a6ff;
61+
--gce-lineno-color: #8b949e;
62+
--gce-lineno-bg: #161b22;
63+
--gce-code-bg: #0d1117;
64+
}
65+
66+
.gce-container .hljs-keyword,
67+
.gce-container .hljs-selector-tag,
68+
.gce-container .hljs-built_in,
69+
.gce-container .hljs-name,
70+
.gce-container .hljs-tag { color: #ff7b72; }
71+
72+
.gce-container .hljs-string,
73+
.gce-container .hljs-attr,
74+
.gce-container .hljs-symbol,
75+
.gce-container .hljs-bullet,
76+
.gce-container .hljs-addition { color: #a5d6ff; }
77+
78+
.gce-container .hljs-title,
79+
.gce-container .hljs-section,
80+
.gce-container .hljs-type,
81+
.gce-container .hljs-function { color: #d2a8ff; }
82+
83+
.gce-container .hljs-variable,
84+
.gce-container .hljs-template-variable { color: #ffa657; }
85+
86+
.gce-container .hljs-comment,
87+
.gce-container .hljs-quote,
88+
.gce-container .hljs-deletion,
89+
.gce-container .hljs-meta { color: #8b949e; font-style: italic; }
90+
91+
.gce-container .hljs-number,
92+
.gce-container .hljs-regexp,
93+
.gce-container .hljs-literal,
94+
.gce-container .hljs-doctag { color: #79c0ff; }
95+
`;
96+
97+
const THEME_COLORS = __THEME__ === "dark" ? DARK_COLORS : LIGHT_COLORS;
98+
99+
export const CSS = `
100+
:root {
101+
--gce-line-height: 1.5em;
102+
--gce-font-size: 13px;
103+
--gce-font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
104+
--gce-ui-font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
105+
}
106+
${THEME_COLORS}
21107
.gce-container,
22108
.gce-container *,
23109
.gce-container *::before,
@@ -139,36 +225,6 @@ export const CSS = `
139225
text-decoration: none;
140226
}
141227
142-
.gce-container .hljs-keyword,
143-
.gce-container .hljs-selector-tag,
144-
.gce-container .hljs-built_in,
145-
.gce-container .hljs-name,
146-
.gce-container .hljs-tag { color: #cf222e; }
147-
148-
.gce-container .hljs-string,
149-
.gce-container .hljs-attr,
150-
.gce-container .hljs-symbol,
151-
.gce-container .hljs-bullet,
152-
.gce-container .hljs-addition { color: #0a3069; }
153-
154-
.gce-container .hljs-title,
155-
.gce-container .hljs-section,
156-
.gce-container .hljs-type,
157-
.gce-container .hljs-function { color: #8250df; }
158-
159-
.gce-container .hljs-variable,
160-
.gce-container .hljs-template-variable { color: #953800; }
161-
162-
.gce-container .hljs-comment,
163-
.gce-container .hljs-quote,
164-
.gce-container .hljs-deletion,
165-
.gce-container .hljs-meta { color: #6e7781; font-style: italic; }
166-
167-
.gce-container .hljs-number,
168-
.gce-container .hljs-regexp,
169-
.gce-container .hljs-literal,
170-
.gce-container .hljs-doctag { color: #0550ae; }
171-
172228
.gce-container .hljs-emphasis { font-style: italic; }
173229
174230
.gce-container .hljs-strong { font-weight: bold; }

test/styles.test.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { describe, expect, it } from "vitest";
2+
import { CSS, DARK_COLORS, LIGHT_COLORS } from "../src/styles";
3+
4+
describe("LIGHT_COLORS", () => {
5+
it("ライトテーマの背景色を含む", () => {
6+
expect(LIGHT_COLORS).toContain("--gce-bg: #f6f8fa");
7+
expect(LIGHT_COLORS).toContain("--gce-code-bg: #ffffff");
8+
});
9+
10+
it("ライトテーマのボーダー色を含む", () => {
11+
expect(LIGHT_COLORS).toContain("--gce-border: #d0d7de");
12+
});
13+
14+
it("ライトテーマのヘッダー色を含む", () => {
15+
expect(LIGHT_COLORS).toContain("--gce-header-text: #24292f");
16+
expect(LIGHT_COLORS).toContain("--gce-header-link: #0969da");
17+
});
18+
19+
it("ライトテーマの行番号色を含む", () => {
20+
expect(LIGHT_COLORS).toContain("--gce-lineno-color: #6e7781");
21+
expect(LIGHT_COLORS).toContain("--gce-lineno-bg: #f6f8fa");
22+
});
23+
24+
it("ライトテーマの hljs キーワード色を含む", () => {
25+
expect(LIGHT_COLORS).toContain("color: #cf222e");
26+
});
27+
28+
it("ライトテーマの hljs 文字列色を含む", () => {
29+
expect(LIGHT_COLORS).toContain("color: #0a3069");
30+
});
31+
32+
it("ライトテーマの hljs タイトル色を含む", () => {
33+
expect(LIGHT_COLORS).toContain("color: #8250df");
34+
});
35+
36+
it("ライトテーマの hljs 変数色を含む", () => {
37+
expect(LIGHT_COLORS).toContain("color: #953800");
38+
});
39+
40+
it("ライトテーマの hljs コメント色を含む", () => {
41+
expect(LIGHT_COLORS).toContain("color: #6e7781");
42+
});
43+
44+
it("ライトテーマの hljs 数値色を含む", () => {
45+
expect(LIGHT_COLORS).toContain("color: #0550ae");
46+
});
47+
});
48+
49+
describe("DARK_COLORS", () => {
50+
it("ダークテーマの背景色を含む", () => {
51+
expect(DARK_COLORS).toContain("--gce-bg: #161b22");
52+
expect(DARK_COLORS).toContain("--gce-code-bg: #0d1117");
53+
});
54+
55+
it("ダークテーマのボーダー色を含む", () => {
56+
expect(DARK_COLORS).toContain("--gce-border: #30363d");
57+
});
58+
59+
it("ダークテーマのヘッダー色を含む", () => {
60+
expect(DARK_COLORS).toContain("--gce-header-text: #e6edf3");
61+
expect(DARK_COLORS).toContain("--gce-header-link: #58a6ff");
62+
});
63+
64+
it("ダークテーマの行番号色を含む", () => {
65+
expect(DARK_COLORS).toContain("--gce-lineno-color: #8b949e");
66+
expect(DARK_COLORS).toContain("--gce-lineno-bg: #161b22");
67+
});
68+
69+
it("ダークテーマの hljs キーワード色を含む", () => {
70+
expect(DARK_COLORS).toContain("color: #ff7b72");
71+
});
72+
73+
it("ダークテーマの hljs 文字列色を含む", () => {
74+
expect(DARK_COLORS).toContain("color: #a5d6ff");
75+
});
76+
77+
it("ダークテーマの hljs タイトル色を含む", () => {
78+
expect(DARK_COLORS).toContain("color: #d2a8ff");
79+
});
80+
81+
it("ダークテーマの hljs 変数色を含む", () => {
82+
expect(DARK_COLORS).toContain("color: #ffa657");
83+
});
84+
85+
it("ダークテーマの hljs コメント色を含む", () => {
86+
expect(DARK_COLORS).toContain("color: #8b949e");
87+
});
88+
89+
it("ダークテーマの hljs 数値色を含む", () => {
90+
expect(DARK_COLORS).toContain("color: #79c0ff");
91+
});
92+
});
93+
94+
describe("CSS (テーマ: light)", () => {
95+
it("テーマ非依存の font-family 変数を含む", () => {
96+
expect(CSS).toContain("--gce-font-family:");
97+
expect(CSS).toContain("--gce-ui-font-family:");
98+
});
99+
100+
it("テーマ非依存の line-height と font-size を含む", () => {
101+
expect(CSS).toContain("--gce-line-height: 1.5em");
102+
expect(CSS).toContain("--gce-font-size: 13px");
103+
});
104+
105+
it("vitest の define により __THEME__ が light に解決され、ライトカラーを含む", () => {
106+
expect(CSS).toContain("--gce-bg: #f6f8fa");
107+
expect(CSS).not.toContain("--gce-bg: #161b22");
108+
});
109+
110+
it("構造 CSS(box-sizing, flex 等)を含む", () => {
111+
expect(CSS).toContain("box-sizing: border-box");
112+
expect(CSS).toContain("display: flex");
113+
});
114+
});

vitest.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ export default defineConfig({
55
environment: "jsdom",
66
include: ["test/**/*.test.ts"],
77
},
8+
define: {
9+
__THEME__: JSON.stringify("light"),
10+
},
811
});

0 commit comments

Comments
 (0)