Skip to content

Commit

Permalink
Merge pull request #3 from phillip-hirsch/feature/Dynamically-fetch-a…
Browse files Browse the repository at this point in the history
…nd-display-color-themes-and-palettes

Feature: Fetch color schemes from iTerm2-Color-Schemes repository and display the color themes and palettes for each selection
  • Loading branch information
zerebos authored Oct 22, 2024
2 parents a8e9bb2 + 0478c77 commit 97c5ac7
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 8 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/lib/components/settings/Dropdown.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<script lang="ts">
type Props = {
value: string;
options: (string | {name: string, value: string})[]
options: (string | {name: string, value: string})[];
change?: () => void;
};
// eslint-disable-next-line prefer-const
let {value = $bindable(), options}: Props = $props();
let {value = $bindable(), options, change}: Props = $props();
</script>

<select bind:value>
<select bind:value onchange={change}>
{#each options as option, i (i)}
{#if typeof(option) === "string"}
<option value={option}>{option}</option>
Expand Down
18 changes: 18 additions & 0 deletions src/lib/components/settings/Theme.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import {setColorScheme} from "$lib/stores/config.svelte";
import Dropdown from "./Dropdown.svelte";
type Props = {
value: string;
options: (string | {name: string, value: string})[]
};
// eslint-disable-next-line prefer-const
let {value = $bindable(), options}: Props = $props();
async function change() {
await setColorScheme(value);
}
</script>

<Dropdown bind:value {options} {change} />
131 changes: 127 additions & 4 deletions src/lib/data/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ interface Panel extends BaseSettingType {
}

interface Group extends BaseSettingType {
settings: (Switch | Text | Number | Dropdown | Color | Palette | Keybinds)[];
settings: (Switch | Text | Number | Dropdown | Color | Palette | Keybinds | Theme)[];
// type: "group";
}

type SettingType = "switch" | "number" | "dropdown" | "text" | "color" | "palette" | "keybinds";
type SettingType = "switch" | "number" | "dropdown" | "text" | "color" | "palette" | "keybinds" | "theme";

interface BaseSettingItem extends BaseSettingType {
type: SettingType;
Expand Down Expand Up @@ -53,6 +53,12 @@ interface Dropdown extends BaseSettingItem {
options: (DropdownOption | string)[];
}

interface Theme extends BaseSettingItem {
type: "theme";
value: "string";
options: (DropdownOption | string)[];
}

interface Color extends BaseSettingItem {
value: HexColor;
type: "color";
Expand All @@ -69,6 +75,116 @@ interface Keybinds extends BaseSettingItem {
type: "keybinds";
}

interface ThemeResponse {
"type": string;
"encoding": string;
"size": number;
"name": string;
"path": string;
"content": string;
"sha": string;
"url": string;
"git_url": string;
"html_url": string;
"download_url": string;
"_links": {
"git": string;
"self": string;
"html": string;
}
}

export interface ColorScheme {
palette: HexColor[];
background?: HexColor;
foreground?: HexColor;
cursorColor?: HexColor;
selectionBackground?: HexColor;
selectionForeground?: HexColor;
}

const fetchThemeFiles = async () => {
const apiUrl = "https://api.github.com/repos/mbadolato/iTerm2-Color-Schemes/contents/ghostty";

const response = await fetch(apiUrl);

if (!response.ok) {
throw new Error(`Error fetching data: ${response.statusText}`);
}

const themeFiles = await response.json();

return {themeFiles};
};

// Function to convert raw string data into a JSON object
export const parseColorScheme = (input: string): ColorScheme => {
const colorScheme: ColorScheme = {palette: Array(256)};

// Split input by lines
const lines = input.split("\n");

lines.forEach((line) => {
if (line.startsWith("palette")) {
const [, rest] = line.split("palette =").map(part => part.trim());

if (rest) {
const [paletteIndex, color] = rest.split("=");
if (paletteIndex && color) {
const index = parseInt(paletteIndex.trim());
colorScheme.palette[index] = color.trim() as HexColor;
}
}
}
else {
const [key, value] = line.split("=").map(part => part.trim());

switch (key) {
case "background":
colorScheme.background = `#${value}`;
break;
case "foreground":
colorScheme.foreground = `#${value}`;
break;
case "cursor-color":
colorScheme.cursorColor = `#${value}`;
break;
case "selection-background":
colorScheme.selectionBackground = `#${value}`;
break;
case "selection-foreground":
colorScheme.selectionForeground = `#${value}`;
break;
default:
break;
}
}
});

return colorScheme;
};

export const fetchColorScheme = async (theme: string) => {
const apiUrl = `https://api.github.com/repos/mbadolato/iTerm2-Color-Schemes/contents/ghostty${theme ? "/" + theme : ""}`;

const response = await fetch(apiUrl,{
headers: {
Accept: "application/vnd.github.raw+json"
}
});

if (!response.ok) {
throw new Error(`Error fetching data: ${response.statusText}`);
}

const colorSchemeResponse = await response.text();

return {colorSchemeResponse};
};

const {themeFiles} = await fetchThemeFiles();
const themeFileNames = themeFiles && themeFiles.map((file: ThemeResponse) => file.name);

export default [
{
id: "application",
Expand Down Expand Up @@ -212,7 +328,14 @@ export default [
id: "general",
name: "",
settings: [
{id: "theme", name: "Color theme", note: "Any colors selected after setting this will overwrite the theme's colors.", type: "text", value: ""},
{
id: "theme",
name: "Color theme",
note: "Any colors selected after setting this will overwrite the theme's colors.",
type: "theme",
value: "",
options: ["", ...themeFileNames]
},
{id: "boldIsBright", name: "Bold text uses bright colors", type: "switch", value: false},
{id: "minimumContrast", name: "Minimum contrast", type: "number", value: 1, range: true, min: 1, max: 21, step: 0.1},
]
Expand Down Expand Up @@ -401,4 +524,4 @@ export default [
}
]
},
] as Panel[];
] as Panel[];
29 changes: 28 additions & 1 deletion src/lib/stores/config.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {dev} from "$app/environment";
import settings, {type KeybindString} from "$lib/data/settings";
import settings, {fetchColorScheme, parseColorScheme, type KeybindString, type ColorScheme} from "$lib/data/settings";
import type {HexColor} from "$lib/utils/colors";
// import defs from "../data/defaults.json";

Expand Down Expand Up @@ -74,6 +74,33 @@ export function load(conf: Partial<typeof config>) {
}
}

export async function setColorScheme(name: string) {
if (name === "") return resetColorScheme();
const {colorSchemeResponse} = await fetchColorScheme(name);
const colorScheme = parseColorScheme(colorSchemeResponse);
const keys = ["background", "foreground", "cursorColor", "selectionBackground", "selectionForeground"] as (keyof ColorScheme)[];
for (const key of keys) {
if (!colorScheme[key]) continue;
config[key] = colorScheme[key];
}

for (let c = 0; c < colorScheme.palette.length; c++) {
if (!colorScheme.palette[c]) continue;
config.palette[c] = colorScheme.palette[c];
}
}

export async function resetColorScheme() {
const keys = ["background", "foreground", "cursorColor", "selectionBackground", "selectionForeground"] as (keyof DefaultConfig)[];
for (const key of keys) {
config[key] = defaults[key];
}

for (let c = 0; c < defaults.palette.length; c++) {
config.palette[c] = defaults.palette[c];
}
}

export default config;


Expand Down
3 changes: 3 additions & 0 deletions src/routes/settings/[category]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import CursorPreview from "$lib/views/CursorPreview.svelte";
import PalettePreview from "$lib/views/PalettePreview.svelte";
import Admonition from "$lib/components/Admonition.svelte";
import Theme from "$lib/components/settings/Theme.svelte";
const category = $derived(settings.find(c => c.id === $page.params.category));
Expand Down Expand Up @@ -56,6 +57,8 @@
<Number bind:value={config[setting.id as keyof typeof config]} range={setting.range} min={setting.min} max={setting.max} step={setting.step} size={setting.size} />
{:else if setting.type === "dropdown"}
<Dropdown bind:value={config[setting.id as keyof typeof config]} options={setting.options} />
{:else if setting.type === "theme"}
<Theme bind:value={config[setting.id as keyof typeof config]} options={setting.options} />
{:else if setting.type === "color"}
<Color defaultValue={setting.value} bind:value={config[setting.id as keyof typeof config]} />
{:else if setting.type === "palette"}
Expand Down

0 comments on commit 97c5ac7

Please sign in to comment.