Skip to content

Commit 2c7d05a

Browse files
authored
feat(settings): add swatch previews to theme settings (Acode-Foundation#1931)
1 parent fd67733 commit 2c7d05a

File tree

2 files changed

+110
-36
lines changed

2 files changed

+110
-36
lines changed

src/pages/themeSetting/themeSetting.js

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { javascript } from "@codemirror/lang-javascript";
33
// For CodeMirror preview
44
import { EditorState } from "@codemirror/state";
55
import { oneDark } from "@codemirror/theme-one-dark";
6-
import { getThemeExtensions, getThemes } from "cm/themes";
6+
import { getThemeConfig, getThemeExtensions, getThemes } from "cm/themes";
77
import { basicSetup, EditorView } from "codemirror";
88
import Page from "components/page";
99
import searchBar from "components/searchbar";
@@ -111,15 +111,16 @@ export default function () {
111111

112112
const currentTheme = appSettings.value.appTheme;
113113
let $currentItem;
114-
themes.list().forEach((theme) => {
114+
themes.list().forEach((themeSummary) => {
115+
const theme = themes.get(themeSummary.id);
115116
const isCurrentTheme = theme.id === currentTheme;
116117
const isPremium = theme.version === "paid" && IS_FREE_VERSION;
117118
const $item = (
118119
<Item
119-
name={theme.name}
120+
name={themeSummary.name}
120121
isPremium={isPremium}
121122
isCurrent={isCurrentTheme}
122-
color={theme.primaryColor}
123+
swatches={getAppThemeSwatches(theme)}
123124
onclick={() => setAppTheme(theme, isPremium)}
124125
/>
125126
);
@@ -150,7 +151,7 @@ export default function () {
150151
<Item
151152
name={t.caption}
152153
isCurrent={isCurrent}
153-
isDark={t.isDark}
154+
swatches={getEditorThemeSwatches(t.id)}
154155
onclick={() => setEditorTheme({ caption: t.caption, theme: t.id })}
155156
/>
156157
);
@@ -245,19 +246,9 @@ export default function () {
245246
list.get(`[theme="${theme}"]`)?.check();
246247
}
247248

248-
function Item({ name, color, isDark, onclick, isCurrent, isPremium }) {
249+
function Item({ name, swatches, onclick, isCurrent, isPremium }) {
249250
const check = <span className="icon check"></span>;
250251
const star = <span className="icon stars"></span>;
251-
let style = {};
252-
let className = "icon color";
253-
254-
if (color) {
255-
style = { color };
256-
} else if (isDark) {
257-
className += " dark";
258-
} else {
259-
className += " light";
260-
}
261252

262253
const $el = (
263254
<div
@@ -266,7 +257,7 @@ export default function () {
266257
className="list-item"
267258
onclick={onclick}
268259
>
269-
<span style={style} className={className}></span>
260+
{createSwatchPreview(swatches)}
270261
<div className="container">
271262
<span className="text">{name}</span>
272263
</div>
@@ -285,4 +276,51 @@ export default function () {
285276
};
286277
return $el;
287278
}
279+
280+
function createSwatchPreview(swatches) {
281+
const colors = [...new Set((swatches || []).filter(Boolean))].slice(0, 3);
282+
while (colors.length < 3) {
283+
colors.push(colors[colors.length - 1] || "var(--border-color)");
284+
}
285+
286+
return (
287+
<div className="theme-swatch-slot" aria-hidden="true">
288+
<div className="theme-swatch-preview">
289+
<span
290+
className="theme-swatch theme-swatch-main"
291+
style={{ backgroundColor: colors[0] }}
292+
></span>
293+
<span
294+
className="theme-swatch"
295+
style={{ backgroundColor: colors[1] }}
296+
></span>
297+
<span
298+
className="theme-swatch"
299+
style={{ backgroundColor: colors[2] }}
300+
></span>
301+
</div>
302+
</div>
303+
);
304+
}
305+
306+
function getAppThemeSwatches(theme) {
307+
if (!theme) {
308+
return [
309+
"var(--primary-color)",
310+
"var(--secondary-color)",
311+
"var(--active-color)",
312+
];
313+
}
314+
315+
return [theme.primaryColor, theme.secondaryColor, theme.activeColor];
316+
}
317+
318+
function getEditorThemeSwatches(themeId) {
319+
const config = getThemeConfig(themeId);
320+
return [
321+
config.background,
322+
config.keyword || config.function || config.foreground,
323+
config.string || config.variable || config.foreground,
324+
];
325+
}
288326
}
Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,55 @@
1-
#theme-setting {
2-
display: flex;
3-
flex-direction: column;
4-
5-
#theme-preview:not(:empty) {
6-
height: 120px;
7-
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
8-
box-shadow: 0 0 4px var(--box-shadow-color);
9-
pointer-events: none;
10-
}
11-
12-
.icon.color.custom::before {
13-
background-color: var(--primary-color);
14-
}
15-
16-
#theme-list {
17-
flex: 1;
18-
}
19-
}
1+
#theme-setting {
2+
display: flex;
3+
flex-direction: column;
4+
5+
#theme-preview:not(:empty) {
6+
height: 120px;
7+
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
8+
box-shadow: 0 0 4px var(--box-shadow-color);
9+
pointer-events: none;
10+
}
11+
12+
#theme-preview .cm-editor {
13+
width: 100%;
14+
}
15+
16+
#theme-list {
17+
flex: 1;
18+
}
19+
20+
.theme-swatch-slot {
21+
display: flex;
22+
align-items: center;
23+
justify-content: center;
24+
width: 60px;
25+
min-width: 60px;
26+
height: 60px;
27+
flex-shrink: 0;
28+
}
29+
30+
.theme-swatch-preview {
31+
display: grid;
32+
grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
33+
grid-template-rows: repeat(2, minmax(0, 1fr));
34+
width: 1.5rem;
35+
min-width: 1.5rem;
36+
height: 1.5rem;
37+
padding: 0.08rem;
38+
box-sizing: border-box;
39+
border: 1px solid var(--border-color);
40+
border: 1px solid color-mix(in srgb, var(--border-color), transparent 18%);
41+
border-radius: 0.45rem;
42+
background: var(--secondary-color);
43+
overflow: hidden;
44+
}
45+
46+
.theme-swatch {
47+
display: block;
48+
min-width: 0;
49+
min-height: 0;
50+
}
51+
52+
.theme-swatch-main {
53+
grid-row: 1 / 3;
54+
}
55+
}

0 commit comments

Comments
 (0)