diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8521ae1b25..cf73c83c6d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -43,6 +43,7 @@ /styles/instagram @GenShibe /styles/invokeai @ryanccn /styles/jisho @Lichthagel +/styles/keybr.com @TadoTheMiner /styles/keyoxide @uncenter /styles/lastfm @AnubisNekhet /styles/lemmy @Gandalf-the-Blue diff --git a/.github/ISSUE_TEMPLATE/userstyle.yml b/.github/ISSUE_TEMPLATE/userstyle.yml index b154ec326e..979fae84b6 100644 --- a/.github/ISSUE_TEMPLATE/userstyle.yml +++ b/.github/ISSUE_TEMPLATE/userstyle.yml @@ -16,7 +16,7 @@ body: label: What userstyles are you seeing the problem on? description: "Don't worry about the `lbl:` prefix, it allows issues to be automatically labeled!" multiple: true - options: ["lbl:advent-of-code", "lbl:alternativeto", "lbl:amplenote", "lbl:anilist", "lbl:arch-wiki", "lbl:boringproxy", "lbl:brave-search", "lbl:bsky", "lbl:bstats", "lbl:canvas-lms", "lbl:chatgpt", "lbl:chatreplay", "lbl:chess.com", "lbl:cinny", "lbl:codeberg", "lbl:cobalt", "lbl:crates.io", "lbl:crowdin", "lbl:deepl", "lbl:docs.rs", "lbl:duckduckgo", "lbl:ecosia", "lbl:elk", "lbl:freedesktop", "lbl:formative", "lbl:github", "lbl:gmail", "lbl:go.dev", "lbl:google", "lbl:google-drive", "lbl:google-photos", "lbl:graphite", "lbl:google-gemini", "lbl:hackage", "lbl:hacker-news", "lbl:have-i-been-pwned", "lbl:holodex", "lbl:home-manager-options-search", "lbl:homepage", "lbl:hoppscotch", "lbl:learn-x-in-y-minutes", "lbl:hyperpipe", "lbl:ichi.moe", "lbl:inoreader", "lbl:instagram", "lbl:invidious", "lbl:invokeai", "lbl:jisho", "lbl:keyoxide", "lbl:lastfm", "lbl:lemmy", "lbl:libreddit", "lbl:lichess", "lbl:lingva", "lbl:linkedin", "lbl:listenbrainz", "lbl:mastodon", "lbl:mdbook", "lbl:mdn", "lbl:modrinth", "lbl:microsoft-word", "lbl:migadu-webmail", "lbl:minesweeper", "lbl:namemc", "lbl:nitter", "lbl:nixos-search", "lbl:wiki.nixos.org", "lbl:npm", "lbl:ollama", "lbl:openmediavault", "lbl:paste.rs", "lbl:perplexity", "lbl:phanpy", "lbl:picrew", "lbl:pinterest", "lbl:planet-minecraft", "lbl:porkbun", "lbl:pronouns.page", "lbl:proton", "lbl:pypi", "lbl:quizlet", "lbl:raindrop", "lbl:reddit", "lbl:rentry.co", "lbl:searxng", "lbl:shinigami-eyes", "lbl:snapchat-web", "lbl:spotify-web", "lbl:stack-overflow", "lbl:startpage", "lbl:stylus", "lbl:substack", "lbl:syncthing", "lbl:tabnews", "lbl:tldraw", "lbl:trinket", "lbl:tuta", "lbl:twitch", "lbl:twitter", "lbl:vercel", "lbl:vikunja", "lbl:web.dev", "lbl:whatsapp-web", "lbl:wikipedia", "lbl:wikiwand", "lbl:youtube"] + options: ["lbl:advent-of-code", "lbl:alternativeto", "lbl:amplenote", "lbl:anilist", "lbl:arch-wiki", "lbl:boringproxy", "lbl:brave-search", "lbl:bsky", "lbl:bstats", "lbl:canvas-lms", "lbl:chatgpt", "lbl:chatreplay", "lbl:chess.com", "lbl:cinny", "lbl:codeberg", "lbl:cobalt", "lbl:crates.io", "lbl:crowdin", "lbl:deepl", "lbl:docs.rs", "lbl:duckduckgo", "lbl:ecosia", "lbl:elk", "lbl:freedesktop", "lbl:formative", "lbl:github", "lbl:gmail", "lbl:go.dev", "lbl:google", "lbl:google-drive", "lbl:google-photos", "lbl:graphite", "lbl:google-gemini", "lbl:hackage", "lbl:hacker-news", "lbl:have-i-been-pwned", "lbl:holodex", "lbl:home-manager-options-search", "lbl:homepage", "lbl:hoppscotch", "lbl:learn-x-in-y-minutes", "lbl:hyperpipe", "lbl:ichi.moe", "lbl:inoreader", "lbl:instagram", "lbl:invidious", "lbl:invokeai", "lbl:jisho", "lbl:keybr.com", "lbl:keyoxide", "lbl:lastfm", "lbl:lemmy", "lbl:libreddit", "lbl:lichess", "lbl:lingva", "lbl:linkedin", "lbl:listenbrainz", "lbl:mastodon", "lbl:mdbook", "lbl:mdn", "lbl:modrinth", "lbl:microsoft-word", "lbl:migadu-webmail", "lbl:minesweeper", "lbl:namemc", "lbl:nitter", "lbl:nixos-search", "lbl:wiki.nixos.org", "lbl:npm", "lbl:ollama", "lbl:openmediavault", "lbl:paste.rs", "lbl:perplexity", "lbl:phanpy", "lbl:picrew", "lbl:pinterest", "lbl:planet-minecraft", "lbl:porkbun", "lbl:pronouns.page", "lbl:proton", "lbl:pypi", "lbl:quizlet", "lbl:raindrop", "lbl:reddit", "lbl:rentry.co", "lbl:searxng", "lbl:shinigami-eyes", "lbl:snapchat-web", "lbl:spotify-web", "lbl:stack-overflow", "lbl:startpage", "lbl:stylus", "lbl:substack", "lbl:syncthing", "lbl:tabnews", "lbl:tldraw", "lbl:trinket", "lbl:tuta", "lbl:twitch", "lbl:twitter", "lbl:vercel", "lbl:vikunja", "lbl:web.dev", "lbl:whatsapp-web", "lbl:wikipedia", "lbl:wikiwand", "lbl:youtube"] validations: required: true - type: textarea diff --git a/.github/issue-labeler.yml b/.github/issue-labeler.yml index 031d0db348..cc9f435709 100644 --- a/.github/issue-labeler.yml +++ b/.github/issue-labeler.yml @@ -95,6 +95,8 @@ invokeai: - '/lbl:invokeai(,.*)?$/gm' jisho: - '/lbl:jisho(,.*)?$/gm' +keybr.com: + - '/lbl:keybr.com(,.*)?$/gm' keyoxide: - '/lbl:keyoxide(,.*)?$/gm' lastfm: diff --git a/.github/labels.yml b/.github/labels.yml index 1ac28950dc..62c01d623b 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -143,6 +143,9 @@ - name: jisho description: Jisho color: '#a6da95' +- name: keybr.com + description: keybr.com + color: '#cad3f5' - name: keyoxide description: Keyoxide color: '#c6a0f6' diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml index 98ac8fade3..6d1d5a2edc 100644 --- a/.github/pr-labeler.yml +++ b/.github/pr-labeler.yml @@ -47,6 +47,7 @@ instagram: styles/instagram/**/* invidious: styles/invidious/**/* invokeai: styles/invokeai/**/* jisho: styles/jisho/**/* +keybr.com: styles/keybr.com/**/* keyoxide: styles/keyoxide/**/* lastfm: styles/lastfm/**/* lemmy: styles/lemmy/**/* diff --git a/.github/workflows/generate-format.yml b/.github/workflows/generate-format.yml index c1ef785fa7..deda40773a 100644 --- a/.github/workflows/generate-format.yml +++ b/.github/workflows/generate-format.yml @@ -34,7 +34,7 @@ jobs: deno-version: v1.x - name: Generate health files - run: deno task ci:generate + run: deno task generate - name: Commit changes uses: EndBug/add-and-commit@v9 diff --git a/.github/workflows/lint-build.yml b/.github/workflows/lint-build.yml index f8fe62599c..1f70c93b77 100644 --- a/.github/workflows/lint-build.yml +++ b/.github/workflows/lint-build.yml @@ -45,8 +45,8 @@ jobs: with: deno-version: v1.x - - name: Generate import file - run: deno task ci:generate-import + - name: Generate Stylus import file + run: deno task stylus-import - name: Upload Release Artifacts run: gh release upload --clobber all-userstyles-export ./dist/import.json diff --git a/.github/workflows/maintainers.yml b/.github/workflows/maintainers.yml index f046063086..bd86f9062e 100644 --- a/.github/workflows/maintainers.yml +++ b/.github/workflows/maintainers.yml @@ -23,6 +23,6 @@ jobs: - name: Sync maintainers if: ${{ github.repository == 'catppuccin/userstyles' && github.ref == 'refs/heads/main' }} - run: deno task ci:sync-maintainers + run: deno task sync-maintainers env: GITHUB_TOKEN: ${{ secrets.USERSTYLES_TOKEN }} diff --git a/README.md b/README.md index c5aa309229..ffe985f229 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ See [CONTRIBUTING.md](docs/CONTRIBUTING.md). - [Have I Been Pwned](styles/have-i-been-pwned) - [homepage](styles/homepage) - [inoreader](styles/inoreader) +- [keybr.com](styles/keybr.com) - [Microsoft Word](styles/microsoft-word) - [openmediavault](styles/openmediavault) - [Porkbun](styles/porkbun) diff --git a/deno.json b/deno.json index ef432d1387..61134ef8b4 100644 --- a/deno.json +++ b/deno.json @@ -11,7 +11,7 @@ "@std/path": "jsr:@std/path@^1.0.6", "@std/yaml": "jsr:@std/yaml@^1.0.5", "ajv": "npm:ajv@8.17.1", - "catppuccin-repo/": "https://raw.githubusercontent.com/catppuccin/catppuccin/d4f2666c2b04337f0a8632713de0889d9a7d332d/", + "@catppuccin/catppuccin/": "https://raw.githubusercontent.com/catppuccin/catppuccin/d4f2666c2b04337f0a8632713de0889d9a7d332d/", "handlebars": "npm:handlebars@4.7.8", "json-schema-to-typescript": "npm:json-schema-to-typescript@15.0.2", "less": "npm:less@4.2.0", @@ -25,13 +25,22 @@ "usercss-meta": "npm:usercss-meta@0.12.0" }, "tasks": { - "ci:generate": "deno run -A ./scripts/generate/main.ts", - "ci:generate-import": "deno run -A ./scripts/import-styles/main.ts", - "ci:sync-maintainers": "deno run -A ./scripts/sync-maintainers/main.ts", + "generate": "deno run -A ./scripts/generate/main.ts", + "stylus-import": "deno run -A ./scripts/stylus-import/main.ts", + "sync-maintainers": "deno run -A ./scripts/sync-maintainers/main.ts", "lint": "deno run -A ./scripts/lint/main.ts", "lint:fix": "deno task lint --fix", - "update-types": "deno run -A ./scripts/update-types.ts", + "update-types": "deno run -A ./scripts/types/update-types.ts", "format": "deno run -A npm:prettier@3.2.4 --write ." }, - "nodeModulesDir": true + "nodeModulesDir": true, + "fmt": { + "include": ["scripts/**/*.ts"] + }, + "lint": { + "rules": { + "tags": ["recommended"], + "include": ["verbatim-module-syntax"] + } + } } diff --git a/docs/userstyle-creation.md b/docs/userstyle-creation.md index b234144a17..a19e100b36 100644 --- a/docs/userstyle-creation.md +++ b/docs/userstyle-creation.md @@ -28,6 +28,9 @@ To request a website to be themed, please create a [Port Request](https://github ### Creating userstyles +> [!IMPORTANT] +> Websites should be popular or otherwise commonly known by members of the Catppuccin community; personal or niche sites may not meet the criteria. If you are unsure if a website qualifies, consider creating a [discussion](https://github.com/catppuccin/catppuccin/discussions/new?category=port-requests) before submitting an initial PR. + To create a userstyle, follow the instructions below. If you run into any difficulties or have any questions, please check our [Tips and tricks](./tips-and-tricks.md) page first. 1. Fork this repository. diff --git a/scripts/_prettier.ts b/scripts/_prettier.ts deleted file mode 100644 index f23645d5b2..0000000000 --- a/scripts/_prettier.ts +++ /dev/null @@ -1 +0,0 @@ -import "npm:prettier@3.2.4"; diff --git a/scripts/constants.ts b/scripts/constants.ts new file mode 100644 index 0000000000..83aab78fcf --- /dev/null +++ b/scripts/constants.ts @@ -0,0 +1,18 @@ +import PORTS_SCHEMA from "@catppuccin/catppuccin/resources/ports.schema.json" with { + type: "json", +}; +import USERSTYLES_SCHEMA from "@/userstyles.schema.json" with { + type: "json", +}; + +import * as path from "@std/path"; + +const ROOT = import.meta.dirname; +if (!ROOT) throw new Error("ROOT was not located."); + +/** + * Absolute path to the repository. + */ +export const REPO_ROOT = path.join(ROOT, ".."); + +export { PORTS_SCHEMA, USERSTYLES_SCHEMA }; diff --git a/scripts/deps.ts b/scripts/deps.ts deleted file mode 100644 index 295b92de45..0000000000 --- a/scripts/deps.ts +++ /dev/null @@ -1,20 +0,0 @@ -import portsSchema from "catppuccin-repo/resources/ports.schema.json" with { - type: "json", -}; -import userStylesSchema from "@/userstyles.schema.json" with { - type: "json", -}; - -import { join } from "@std/path"; - -const ROOT = import.meta.dirname; -if (!ROOT) { - throw new Error("ROOT was not located."); -} - -/** - * absolute path to the repository - */ -export const REPO_ROOT = join(ROOT, ".."); - -export { portsSchema, userStylesSchema }; diff --git a/scripts/generate/labels.ts b/scripts/generate/labels.ts index 56bed9a39f..9665c4ba2b 100644 --- a/scripts/generate/labels.ts +++ b/scripts/generate/labels.ts @@ -1,10 +1,11 @@ -import { join } from "@std/path"; +import type { UserstylesSchema } from "@/types/mod.ts"; +import { REPO_ROOT } from "@/constants.ts"; + +import * as path from "@std/path"; +import * as yaml from "@std/yaml"; -import { REPO_ROOT } from "@/deps.ts"; -import { updateFile } from "@/generate/utils.ts"; -import { UserStylesSchema } from "@/types/mod.ts"; -import { stringify } from "@std/yaml"; import { type ColorName, flavors } from "@catppuccin/palette"; +import { writeWithPreamble } from "@/generate/utils.ts"; /** * Macchiato color definitions as hex values. @@ -17,12 +18,11 @@ const macchiatoHex = flavors.macchiato.colorEntries const toIssueLabel = (slug: string | number) => `lbl:${slug}`; -export const syncIssueLabels = async ( - userstyles: UserStylesSchema.Userstyles, -) => { - updateFile( - join(REPO_ROOT, ".github/issue-labeler.yml"), - stringify( +export async function syncIssueLabels(userstyles: UserstylesSchema.Userstyles) { + // .github/issue-labeler.yml + await writeWithPreamble( + path.join(REPO_ROOT, ".github/issue-labeler.yml"), + yaml.stringify( Object.entries(userstyles) .reduce((acc, [key]) => { acc[key.toString()] = [`/${toIssueLabel(key)}(,.*)?$/gm`]; @@ -31,13 +31,14 @@ export const syncIssueLabels = async ( ), ); - const userstyleIssueContent = Deno.readTextFileSync(join( + // .github/ISSUE_TEMPLATE/userstyle.yml + const userstyleIssueTemplate = Deno.readTextFileSync(path.join( REPO_ROOT, "scripts/generate/templates/userstyle-issue.yml", )); - Deno.writeTextFileSync( - join(REPO_ROOT, ".github/ISSUE_TEMPLATE/userstyle.yml"), - userstyleIssueContent.replace( + await Deno.writeTextFile( + path.join(REPO_ROOT, ".github/ISSUE_TEMPLATE/userstyle.yml"), + userstyleIssueTemplate.replace( `"$LABELS"`, `${ Object.entries(userstyles) @@ -48,9 +49,9 @@ export const syncIssueLabels = async ( ); // .github/pr-labeler.yml - updateFile( - join(REPO_ROOT, ".github/pr-labeler.yml"), - stringify( + await writeWithPreamble( + path.join(REPO_ROOT, ".github/pr-labeler.yml"), + yaml.stringify( Object.entries(userstyles) .reduce((acc, [key]) => { acc[`${key}`] = `styles/${key}/**/*`; @@ -60,15 +61,17 @@ export const syncIssueLabels = async ( ); // .github/labels.yml - const syncLabelsContent = Object.entries(userstyles) - .map(([slug, style]) => { - return { - name: slug, - description: [style.name].flat().join(", "), - color: style.color ? macchiatoHex[style.color] : macchiatoHex.blue, - }; - }); - const syncLabels = join(REPO_ROOT, ".github/labels.yml"); - // deno-lint-ignore no-explicit-any - await updateFile(syncLabels, stringify(syncLabelsContent as any)); -}; + await writeWithPreamble( + path.join(REPO_ROOT, ".github/labels.yml"), + yaml.stringify( + Object.entries(userstyles) + .map(([slug, style]) => { + return { + name: slug, + description: [style.name].flat().join(", "), + color: style.color ? macchiatoHex[style.color] : macchiatoHex.blue, + }; + }), + ), + ); +} diff --git a/scripts/generate/main.ts b/scripts/generate/main.ts index 48e58f6b81..8fefd6ae54 100755 --- a/scripts/generate/main.ts +++ b/scripts/generate/main.ts @@ -1,36 +1,14 @@ -#!/usr/bin/env -S deno run -A -import { join } from "@std/path"; -import { portsSchema, REPO_ROOT, userStylesSchema } from "@/deps.ts"; -import type { PortsSchema, UserStylesSchema } from "@/types/mod.ts"; +import * as path from "@std/path"; +import { REPO_ROOT } from "@/constants.ts"; import { syncIssueLabels } from "@/generate/labels.ts"; import { generateMainReadme } from "@/generate/readme-repo.ts"; import { generateStyleReadmes } from "@/generate/readme-styles.ts"; -import { updateFile } from "@/generate/utils.ts"; -import { validateYaml } from "@/utils.ts"; +import { writeWithPreamble } from "@/generate/utils.ts"; +import { getPortsData, getUserstylesData } from "@/utils.ts"; -const userstylesYaml = Deno.readTextFileSync( - join(REPO_ROOT, "scripts/userstyles.yml"), -); -const portsYaml = await fetch( - "https://raw.githubusercontent.com/catppuccin/catppuccin/main/resources/ports.yml", -).then((res) => res.text()); - -const [portsData, userstylesData] = await Promise.all([ - await validateYaml( - portsYaml, - portsSchema, - ), - await validateYaml( - userstylesYaml, - userStylesSchema, - ), -]); - -if (!userstylesData.userstyles) { - console.error("No userstyles found"); - Deno.exit(1); -} +const userstylesData = getUserstylesData(); +const portsData = await getPortsData(); /** * Generate the main README.md, listing all ports as a table of contents @@ -67,9 +45,11 @@ const maintainersCodeOwners = () => { }; const userstylesStaffCodeOwners = () => { const paths = ["/.github/", "/scripts/", "/template/"]; - return paths.map((path) => `${path} @catppuccin/userstyles-staff`).join("\n"); + return paths.map((path) => `${path} @catppuccin/userstyles-staff`).join( + "\n", + ); }; -await updateFile( - join(REPO_ROOT, ".github/CODEOWNERS"), +await writeWithPreamble( + path.join(REPO_ROOT, ".github/CODEOWNERS"), `${maintainersCodeOwners()}\n\n${userstylesStaffCodeOwners()}`, ); diff --git a/scripts/generate/readme-repo.ts b/scripts/generate/readme-repo.ts index 652322d2e4..ab0eca0288 100644 --- a/scripts/generate/readme-repo.ts +++ b/scripts/generate/readme-repo.ts @@ -1,20 +1,21 @@ -import { join } from "@std/path"; +import type { PortsSchema, UserstylesSchema } from "@/types/mod.ts"; +import { REPO_ROOT } from "@/constants.ts"; + +import * as path from "@std/path"; import Handlebars from "handlebars"; -import { REPO_ROOT } from "@/deps.ts"; -import { PortsSchema, UserStylesSchema } from "@/types/mod.ts"; -import { updateFile, updateReadme } from "@/generate/utils.ts"; +import { updateReadme } from "@/generate/utils.ts"; type MappedPorts = { [k: string]: ( - UserStylesSchema.Userstyle & { path: string } + UserstylesSchema.Userstyle & { path: string } )[]; }; -export const generateMainReadme = async ( - userstyles: UserStylesSchema.Userstyles, +export async function generateMainReadme( + userstyles: UserstylesSchema.Userstyles, portsData: PortsSchema.PortsSchema, -) => { +) { if (!portsData.categories) throw ("Ports data is missing categories"); const categorized = Object.entries(userstyles) @@ -23,7 +24,11 @@ export const generateMainReadme = async ( // only care about the first (primary) category in the categories array acc[categories[0]] ??= []; - acc[categories[0]].push({ path: `styles/${slug}`, categories, ...port }); + acc[categories[0]].push({ + path: `styles/${slug}`, + categories, + ...port, + }); // Sort by name, first array entry if necessary acc[categories[0]].sort((a, b) => @@ -53,7 +58,13 @@ export const generateMainReadme = async ( emoji: meta.emoji, name: meta.name, ports: ports.map( - ({ name, path, "current-maintainers": currentMaintainers }) => { + ( + { + name, + path, + "current-maintainers": currentMaintainers, + }, + ) => { return { name: [name].flat(), maintained: currentMaintainers.length > 0, @@ -65,14 +76,13 @@ export const generateMainReadme = async ( }), }); - const readmePath = join(REPO_ROOT, "README.md"); - await updateFile( + const readmePath = path.join(REPO_ROOT, "README.md"); + await Deno.writeTextFile( readmePath, updateReadme({ readme: Deno.readTextFileSync(readmePath), section: "userstyles", newContent: portContent, }), - false, ).catch((e) => console.error(e)); -}; +} diff --git a/scripts/generate/readme-styles.ts b/scripts/generate/readme-styles.ts index a9e384320e..0188b955f0 100644 --- a/scripts/generate/readme-styles.ts +++ b/scripts/generate/readme-styles.ts @@ -1,6 +1,7 @@ -import { UserStylesSchema } from "@/types/mod.ts"; -import { join } from "@std/path"; -import { REPO_ROOT } from "@/deps.ts"; +import type { UserstylesSchema } from "@/types/mod.ts"; +import { REPO_ROOT } from "@/constants.ts"; + +import * as path from "@std/path"; import Handlebars from "handlebars"; // we can have some nice things :) @@ -14,8 +15,8 @@ Handlebars.registerHelper( ); const heading = ( - name: UserStylesSchema.Name, - link: UserStylesSchema.ApplicationLink, + name: UserstylesSchema.Name, + link: UserstylesSchema.ApplicationLink, ) => { const [nameArray, linkArray] = [[name].flat(), [link].flat()]; @@ -30,11 +31,11 @@ const heading = ( }); }; -const extractName = ( +function extractName( collaborators?: - | UserStylesSchema.CurrentMaintainers - | UserStylesSchema.PastMaintainers, -) => { + | UserstylesSchema.CurrentMaintainers + | UserstylesSchema.PastMaintainers, +) { // no-op when undefined if (!collaborators) return; // set the name to the github.com/ @@ -42,12 +43,10 @@ const extractName = ( c.name ??= c.url.split("/").pop(); return c; }); -}; +} -export const generateStyleReadmes = ( - userstyles: UserStylesSchema.Userstyles, -) => { - const stylesReadmePath = join( +export function generateStyleReadmes(userstyles: UserstylesSchema.Userstyles) { + const stylesReadmePath = path.join( REPO_ROOT, "scripts/generate/templates/userstyle.md", ); @@ -77,9 +76,9 @@ export const generateStyleReadmes = ( }, }); Deno.writeTextFile( - join(REPO_ROOT, "styles", slug.toString(), "README.md"), + path.join(REPO_ROOT, "styles", slug.toString(), "README.md"), readmeContent, ).catch((e) => console.error(e)); }, ); -}; +} diff --git a/scripts/generate/utils.ts b/scripts/generate/utils.ts index 1293f5b52e..cfee4aac49 100644 --- a/scripts/generate/utils.ts +++ b/scripts/generate/utils.ts @@ -1,15 +1,14 @@ -export const updateFile = ( +export function writeWithPreamble( filePath: string, fileContent: string, - comment = true, -) => { - const preamble = comment - ? "# THIS FILE IS AUTOGENERATED. DO NOT EDIT IT BY HAND.\n" - : ""; - return Deno.writeTextFile(filePath, preamble + fileContent); -}; +) { + return Deno.writeTextFile( + filePath, + "# THIS FILE IS AUTOGENERATED. DO NOT EDIT IT BY HAND.\n" + fileContent, + ); +} -export const updateReadme = ({ +export function updateReadme({ readme, section, newContent, @@ -17,20 +16,18 @@ export const updateReadme = ({ readme: string; section: string; newContent: string; -}): string => { +}): string { const preamble = ""; const startMarker = ``; const endMarker = ``; const wrapped = `${startMarker}\n${preamble}\n${newContent}\n${endMarker}`; - if ( - !(readme.includes(startMarker) && readme.includes(endMarker)) - ) { + if (!(readme.includes(startMarker) && readme.includes(endMarker))) { throw new Error("Markers not found in README.md"); } const pre = readme.split(startMarker)[0]; const end = readme.split(endMarker)[1]; return pre + wrapped + end; -}; +} diff --git a/scripts/lint/file-checker.ts b/scripts/lint/file-checker.ts index ccdcc30988..d4223a7f04 100644 --- a/scripts/lint/file-checker.ts +++ b/scripts/lint/file-checker.ts @@ -1,8 +1,9 @@ -import { exists } from "@std/fs"; -import { join, relative } from "@std/path"; +import { REPO_ROOT } from "@/constants.ts"; + +import * as fs from "@std/fs"; +import * as path from "@std/path"; import core from "@actions/core"; -import { REPO_ROOT } from "@/deps.ts"; import { log } from "@/logger.ts"; const requiredFiles = [ @@ -10,19 +11,19 @@ const requiredFiles = [ "preview.webp", ]; -export const checkForMissingFiles = async () => { - const stylesRoot = join(REPO_ROOT, "styles"); +export async function checkForMissingFiles() { + const stylesRoot = path.join(REPO_ROOT, "styles"); const missingFiles: string[] = []; for await (const entry of Deno.readDir(stylesRoot)) { if (!entry.isDirectory) continue; - const styleRoot = join(stylesRoot, entry.name); + const styleRoot = path.join(stylesRoot, entry.name); await Promise.all(requiredFiles.map(async (f) => { - const fp = join(styleRoot, f); - const rfp = relative(REPO_ROOT, fp); + const fp = path.join(styleRoot, f); + const rfp = path.relative(REPO_ROOT, fp); - if (!(await exists(fp))) { + if (!(await fs.exists(fp))) { missingFiles.push(rfp); } })); @@ -35,10 +36,10 @@ export const checkForMissingFiles = async () => { .addList(missingFiles) .write(); } else { - missingFiles.map((f) => { - log.error(`File does not exist`, { file: f }); - }); + for (const file of missingFiles) { + log.error(`File does not exist`, { file }); + } } return missingFiles.length === 0; -}; +} diff --git a/scripts/lint/main.ts b/scripts/lint/main.ts index bc66f11c7a..22e7a199de 100755 --- a/scripts/lint/main.ts +++ b/scripts/lint/main.ts @@ -1,11 +1,11 @@ -#!/usr/bin/env -S deno run -A -import { walk } from "@std/fs"; +import { REPO_ROOT } from "@/constants.ts"; + import { parseArgs } from "@std/cli"; -import { basename, dirname, join, relative } from "@std/path"; +import * as fs from "@std/fs"; +import * as path from "@std/path"; // @ts-types="npm:@types/less"; import less from "less"; -import { REPO_ROOT } from "@/deps.ts"; import { checkForMissingFiles } from "@/lint/file-checker.ts"; import { log } from "@/logger.ts"; import { verifyMetadata } from "@/lint/metadata.ts"; @@ -15,7 +15,7 @@ import stylelintConfig from "../../.stylelintrc.js"; const args = parseArgs(Deno.args, { boolean: ["fix"] }); const subDir = args._[0]?.toString() ?? ""; -const stylesheets = walk(join(REPO_ROOT, "styles", subDir), { +const stylesheets = fs.walk(path.join(REPO_ROOT, "styles", subDir), { includeFiles: true, includeDirs: false, includeSymlinks: false, @@ -26,8 +26,8 @@ const { userstyles } = getUserstylesData(); let failed = false; for await (const entry of stylesheets) { - const dir = basename(dirname(entry.path)); - const file = relative(REPO_ROOT, entry.path); + const dir = path.basename(path.dirname(entry.path)); + const file = path.relative(REPO_ROOT, entry.path); let content = await Deno.readTextFile(entry.path); diff --git a/scripts/lint/metadata.ts b/scripts/lint/metadata.ts index 5f33f135d0..f0a2138239 100644 --- a/scripts/lint/metadata.ts +++ b/scripts/lint/metadata.ts @@ -1,27 +1,28 @@ -// @ts-types="@/types/usercss-meta.d.ts"; -import usercssMeta from "usercss-meta"; +import type { Userstyles } from "@/types/userstyles.d.ts"; +import type { WalkEntry } from "@std/fs"; +import { REPO_ROOT } from "@/constants.ts"; + import * as color from "@std/fmt/colors"; +import * as path from "@std/path"; import { sprintf } from "@std/fmt/printf"; -import type { WalkEntry } from "@std/fs"; -import { join, relative } from "@std/path"; -import { REPO_ROOT } from "@/deps.ts"; +// @ts-types="@/types/usercss-meta.d.ts"; +import usercssMeta from "usercss-meta"; import { log } from "@/logger.ts"; import { formatListOfItems } from "@/utils.ts"; -import type { Userstyles } from "@/types/userstyles.d.ts"; -export const verifyMetadata = async ( +export async function verifyMetadata( entry: WalkEntry, content: string, userstyle: string, userstyles: Userstyles, fix: boolean, -) => { +) { // `usercss-meta` prohibits any '\r' characters, which seem to be present on Windows. content = content.replaceAll("\r\n", "\n"); - const assert = assertions(userstyle, userstyles); - const file = relative(REPO_ROOT, entry.path); + const assertions = generateAssertions(userstyle, userstyles); + const file = path.relative(REPO_ROOT, entry.path); const { metadata, errors: parsingErrors } = usercssMeta.parse(content, { allowErrors: true, @@ -29,28 +30,28 @@ export const verifyMetadata = async ( const lines = content.split("\n"); // Pretty print / annotate the parsing errors. - parsingErrors.map((e) => { + for (const error of parsingErrors) { let startLine; - if (e.index !== undefined && !Number.isNaN(e.index)) { + if (error.index !== undefined && !Number.isNaN(error.index)) { startLine = 0; for (const line of lines) { startLine++; - e.index -= line.length + 1; - if (e.index < 0) break; + error.index -= line.length + 1; + if (error.index < 0) break; } } // Skip "missing mandatory metadata property" ParseError, assertions checks below will cover. - if (e.code === "missingMandatory") return; + if (error.code === "missingMandatory") continue; - log.error(e.message, { + log.error(error.message, { file, startLine, content, }); - }); + } - for (const [key, expected] of Object.entries(assert)) { + for (const [key, expected] of Object.entries(assertions)) { const current = metadata[key]; const atKey = "@" + key; @@ -80,7 +81,7 @@ export const verifyMetadata = async ( } const template = (await Deno.readTextFile( - join(REPO_ROOT, "template/catppuccin.user.css"), + path.join(REPO_ROOT, "template/catppuccin.user.css"), )) .split("\n"); @@ -138,12 +139,12 @@ export const verifyMetadata = async ( return { globalVars, - isLess: metadata.preprocessor === assert.preprocessor, + isLess: metadata.preprocessor === assertions.preprocessor, fixed: content, }; -}; +} -const assertions = (userstyle: string, userstyles: Userstyles) => { +function generateAssertions(userstyle: string, userstyles: Userstyles) { const prefix = "https://github.com/catppuccin/userstyles"; if (!userstyles[userstyle]) { @@ -175,4 +176,4 @@ const assertions = (userstyle: string, userstyles: Userstyles) => { license: "MIT", preprocessor: "less", }; -}; +} diff --git a/scripts/lint/stylelint.ts b/scripts/lint/stylelint.ts index a2e7d6044f..85c34ce576 100644 --- a/scripts/lint/stylelint.ts +++ b/scripts/lint/stylelint.ts @@ -1,44 +1,50 @@ -import * as color from "@std/fmt/colors"; import type { WalkEntry } from "@std/fs"; -import { relative } from "@std/path"; +import { REPO_ROOT } from "@/constants.ts"; + +import * as color from "@std/fmt/colors"; +import * as path from "@std/path"; import "postcss-less"; import stylelint from "stylelint"; import "stylelint-config-standard"; import "stylelint-config-recommended"; -import { REPO_ROOT } from "@/deps.ts"; import { log } from "@/logger.ts"; -export const lint = ( +export async function lint( entry: WalkEntry, content: string, fix: boolean, config: stylelint.Config, -) => - stylelint.lint({ code: content, config, fix }) - .then(({ results, code }) => { - if (code) { - Deno.writeTextFileSync(entry.path, code); - } - results.map((result) => { - result.warnings.map((warning) => { - // Some cleanup for fancier logging - dims the rule name. - const message = warning.text?.replace( - new RegExp(`\\(?${warning.rule}\\)?`), - color.dim(`(${warning.rule})`), - ) ?? "unspecified stylelint error"; - - log.log(message, { - file: relative(REPO_ROOT, entry.path), - startLine: warning.line, - endLine: warning.endLine, - startColumn: warning.column, - endColumn: warning.endColumn, - content, - }, warning.severity); - }); - - if (result.warnings.length > 0) throw new Error("stylelint error"); - }); - }); +) { + const { results, code } = await stylelint.lint({ + code: content, + config, + fix, + }); + + if (code) { + Deno.writeTextFileSync(entry.path, code); + } + + for (const result of results) { + for (const warning of result.warnings) { + // Some cleanup for fancier logging - dims the rule name. + const message = warning.text?.replace( + new RegExp(`\\(?${warning.rule}\\)?`), + color.dim(`(${warning.rule})`), + ) ?? "unspecified stylelint error"; + + log.log(message, { + file: path.relative(REPO_ROOT, entry.path), + startLine: warning.line, + endLine: warning.endLine, + startColumn: warning.column, + endColumn: warning.endColumn, + content, + }, warning.severity); + } + + if (result.warnings.length > 0) throw new Error("stylelint error"); + } +} diff --git a/scripts/logger.ts b/scripts/logger.ts index 08a55f38a3..85df45f278 100644 --- a/scripts/logger.ts +++ b/scripts/logger.ts @@ -7,11 +7,11 @@ export type LoggerProps = core.AnnotationProperties & { content?: string; }; -const prettyPrint = ( +function prettyPrint( message: string, props: LoggerProps, severity: "error" | "warning" = "warning", -) => { +) { const { file, startColumn, startLine } = props; const lines = (props.content ?? "").split("\n"); @@ -73,7 +73,7 @@ const prettyPrint = ( ); console.log("\n" + logs.join("\n")); -}; +} export const log = { failed: false, diff --git a/scripts/import-styles/main.ts b/scripts/stylus-import/main.ts similarity index 84% rename from scripts/import-styles/main.ts rename to scripts/stylus-import/main.ts index 5d655425b8..2de693ead4 100644 --- a/scripts/import-styles/main.ts +++ b/scripts/stylus-import/main.ts @@ -1,11 +1,10 @@ -#!/usr/bin/env -S deno run -A +import { REPO_ROOT } from "@/constants.ts"; + +import * as path from "@std/path"; import usercssMeta from "usercss-meta"; import { ensureDir, walk } from "@std/fs"; -import { join } from "@std/path"; - -import { REPO_ROOT } from "@/deps.ts"; -const stylesheets = walk(join(REPO_ROOT, "styles"), { +const stylesheets = walk(path.join(REPO_ROOT, "styles"), { includeFiles: true, includeDirs: false, includeSymlinks: false, diff --git a/scripts/sync-maintainers/main.ts b/scripts/sync-maintainers/main.ts index b5945c1fb9..faabff8f8b 100755 --- a/scripts/sync-maintainers/main.ts +++ b/scripts/sync-maintainers/main.ts @@ -1,8 +1,8 @@ -#!/usr/bin/env -S deno run -A +import type { Userstyle } from "@/types/userstyles.d.ts"; + import * as assert from "@std/assert"; -import { Octokit } from "@octokit/rest"; -import type { UserStylesSchema } from "@/types/mod.ts"; +import { Octokit } from "@octokit/rest"; import { getUserstylesData } from "@/utils.ts"; const octokit = new Octokit({ auth: Deno.env.get("GITHUB_TOKEN") }); @@ -14,7 +14,7 @@ const { userstyles } = getUserstylesData(); const maintainers = [ ...new Set( Object.values(userstyles).flatMap(( - style: UserStylesSchema.Userstyle, + style: Userstyle, ) => style["current-maintainers"].map((m) => { const username = m.url.split("github.com/")?.pop(); @@ -34,7 +34,7 @@ const teamMembers = await octokit.teams }) .then((res) => res.data.map((m) => m.login.toLowerCase())); -const syncMaintainers = async () => { +async function syncMaintainers() { if (!maintainers) return; if (assert.equal(maintainers, teamMembers)) { console.log("Maintainers are in sync"); @@ -60,11 +60,13 @@ const syncMaintainers = async () => { ...team, username: m, }); - console.log(`Removed ${m} from the ${team.org}/${team.team_slug} team.`); + console.log( + `Removed ${m} from the ${team.org}/${team.team_slug} team.`, + ); } console.log( `${toRemove.length} users removed from the ${team.org}/${team.team_slug} team.`, ); -}; +} await syncMaintainers(); diff --git a/scripts/types/mod.ts b/scripts/types/mod.ts index d5f9d03acc..b424f66368 100644 --- a/scripts/types/mod.ts +++ b/scripts/types/mod.ts @@ -1,9 +1,2 @@ -export * as UserStylesSchema from "@/types/userstyles.d.ts"; -export * as PortsSchema from "catppuccin-repo/resources/types/ports.d.ts"; - -import { Entries } from "type-fest"; -declare global { - interface ObjectConstructor { - entries(o: T): Entries; - } -} +export * as UserstylesSchema from "@/types/userstyles.d.ts"; +export * as PortsSchema from "@catppuccin/catppuccin/resources/types/ports.d.ts"; diff --git a/scripts/types/update-types.ts b/scripts/types/update-types.ts new file mode 100755 index 0000000000..12c2c20f38 --- /dev/null +++ b/scripts/types/update-types.ts @@ -0,0 +1,15 @@ +import { REPO_ROOT, USERSTYLES_SCHEMA } from "@/constants.ts"; + +import * as path from "@std/path"; +import { compile, type JSONSchema } from "json-schema-to-typescript"; + +const TYPES_ROOT = path.join(REPO_ROOT, "scripts/types"); + +const types = await compile( + USERSTYLES_SCHEMA as JSONSchema, + "UserstylesSchema", + { + bannerComment: "// deno-fmt-ignore-file", + }, +); +Deno.writeTextFileSync(path.join(TYPES_ROOT, "userstyles.d.ts"), types); diff --git a/scripts/update-types.ts b/scripts/update-types.ts deleted file mode 100755 index a3303e966b..0000000000 --- a/scripts/update-types.ts +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env -S deno run -A -// deno-lint-ignore-file no-explicit-any -import { join } from "@std/path"; -import { compile, Options } from "json-schema-to-typescript"; -import { REPO_ROOT, userStylesSchema } from "@/deps.ts"; - -const options = { - bannerComment: "// deno-fmt-ignore-file", -} satisfies Partial; - -const TYPES_ROOT = join(REPO_ROOT, "scripts/types"); - -compile(userStylesSchema as any, "UserstylesSchema", options) - .then((ts) => - Deno.writeTextFileSync(join(TYPES_ROOT, "userstyles.d.ts"), ts) - ); diff --git a/scripts/userstyles.yml b/scripts/userstyles.yml index 3463eaabe4..d033be7c31 100644 --- a/scripts/userstyles.yml +++ b/scripts/userstyles.yml @@ -147,6 +147,9 @@ collaborators: url: https://github.com/Lichthagel - &comfysage url: https://github.com/comfysage + - &TadoTheMiner + name: jan Tatesa + url: https://github.com/TadoTheMiner userstyles: advent-of-code: @@ -534,6 +537,13 @@ userstyles: readme: app-link: "https://jisho.org" current-maintainers: [*Lichthagel] + keybr.com: + name: keybr.com + categories: [productivity] + color: text + readme: + app-link: "https://keybr.com" + current-maintainers: [*TadoTheMiner] keyoxide: name: Keyoxide categories: [development] diff --git a/scripts/utils.ts b/scripts/utils.ts index 373df74bab..dc0a1a8239 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -1,10 +1,11 @@ -import Ajv, { Schema } from "ajv"; -import { parse } from "@std/yaml"; -import { join } from "@std/path"; -import { SetRequired } from "type-fest/source/set-required.d.ts"; +import type { PortsSchema, UserstylesSchema } from "@/types/mod.ts"; +import type { SetRequired } from "type-fest/source/set-required.d.ts"; +import { PORTS_SCHEMA, REPO_ROOT, USERSTYLES_SCHEMA } from "@/constants.ts"; -import { REPO_ROOT, userStylesSchema } from "@/deps.ts"; -import { UserstylesSchema } from "@/types/userstyles.d.ts"; +import * as yaml from "@std/yaml"; +import * as path from "@std/path"; + +import Ajv, { type Schema } from "ajv"; import { log } from "@/logger.ts"; import { sprintf } from "@std/fmt/printf"; @@ -13,13 +14,14 @@ import { sprintf } from "@std/fmt/printf"; * @param schema A JSON schema * @returns A promise that resolves to the parsed YAML content, verified against the schema. Rejects if the content is invalid. */ -export const validateYaml = ( +export function validateYaml( content: string, schema: Schema, -): T => { + file: string, +): T { const ajv = new Ajv.default(); const validate = ajv.compile(schema); - const data = parse(content); + const data = yaml.parse(content); if (!validate(data)) { log.error( @@ -34,28 +36,29 @@ export const validateYaml = ( ) ).join(" and "), { - file: "scripts/userstyles.yml", + file, }, ); Deno.exit(1); } return data as T; -}; +} /** * Utility function that calls {@link validateYaml} on the userstyles.yml file. * Fails when data.userstyles is undefined. */ -export const getUserstylesData = (): Userstyles => { +export function getUserstylesData(): Userstyles { const content = Deno.readTextFileSync( - join(REPO_ROOT, "scripts/userstyles.yml"), + path.join(REPO_ROOT, "scripts/userstyles.yml"), ); try { - const data = validateYaml( + const data = validateYaml( content, - userStylesSchema, + USERSTYLES_SCHEMA, + "scripts/userstyles.yml", ); for (const field of ["userstyles", "collaborators"] as const) { @@ -69,7 +72,7 @@ export const getUserstylesData = (): Userstyles => { return data as Userstyles; } catch (err) { - if (err.name === "SyntaxError") { + if (err instanceof Error && err.name === "SyntaxError") { const groups = /(?.*) at line (?\d+), column (?\d+):[\S\s]*/ .exec(err.message)?.groups; @@ -87,7 +90,25 @@ export const getUserstylesData = (): Userstyles => { Deno.exit(1); } -}; +} + +/** + * Utility function that calls {@link validateYaml} on the ports.yml file. + * Fails when data.userstyles is undefined. + */ +export async function getPortsData(): Promise { + const content = await fetch( + "https://raw.githubusercontent.com/catppuccin/catppuccin/main/resources/ports.yml", + ).then((res) => res.text()); + + const data = validateYaml( + content, + PORTS_SCHEMA, + "ports.yml", + ); + + return data; +} /** * Utility function that formats a list of items into the "x, y, ..., and z" format. @@ -98,7 +119,7 @@ export const getUserstylesData = (): Userstyles => { * @example * formatListOfItems(['x', 'y', 'z']); // 'x, y, and z' */ -export const formatListOfItems = (items: unknown[]): string => { +export function formatListOfItems(items: unknown[]): string { // If there are two items, connect them with an "and". if (items.length === 2) return items.join(" and "); // Otherwise, there is either just one item or more than two items. @@ -110,6 +131,9 @@ export const formatListOfItems = (items: unknown[]): string => { // Otherwise, it is some item in the middle of the list and we can just add it as a comma followed by the item to the string. return prev + `, ${curr}`; }) as string; -}; +} -type Userstyles = SetRequired; +type Userstyles = SetRequired< + UserstylesSchema.UserstylesSchema, + "userstyles" | "collaborators" +>; diff --git a/styles/chess.com/catppuccin.user.css b/styles/chess.com/catppuccin.user.css index 5fdbb7fc1a..9ef3498122 100644 --- a/styles/chess.com/catppuccin.user.css +++ b/styles/chess.com/catppuccin.user.css @@ -2,7 +2,7 @@ @name Chess.com Catppuccin @namespace github.com/catppuccin/userstyles/styles/chess.com @homepageURL https://github.com/catppuccin/userstyles/tree/main/styles/chess.com -@version 0.2.1 +@version 0.2.2 @updateURL https://github.com/catppuccin/userstyles/raw/main/styles/chess.com/catppuccin.user.css @supportURL https://github.com/catppuccin/userstyles/issues?q=is%3Aopen+is%3Aissue+label%3Achess.com @description Soothing pastel theme for Chess.com @@ -300,8 +300,14 @@ } } - #tb .toolbar-action-icon { - color: @subtext1; + #tb { + .toolbar-action-icon { + color: @subtext1; + } + + .toolbar-action-wrapper:hover .toolbar-action-icon { + color: @text !important; + } } #sb { @@ -516,6 +522,10 @@ } } + .coach-nudges-modal-component { + background: @mantle; + } + .ready-to-play-banner-component { background-color: @mantle; diff --git a/styles/keybr.com/README.md b/styles/keybr.com/README.md new file mode 100644 index 0000000000..56f572c8b6 --- /dev/null +++ b/styles/keybr.com/README.md @@ -0,0 +1,36 @@ + + + +

+ Logo
+ + Catppuccin for keybr.com + +

+ +

+ + +

+ +

+ +

+ + + +## 💝 Current Maintainer +- [jan Tatesa](https://github.com/TadoTheMiner) + + +  + +

+ +

+ +

+ Copyright © 2021-present Catppuccin Org +

+ + diff --git a/styles/keybr.com/catppuccin.user.css b/styles/keybr.com/catppuccin.user.css new file mode 100644 index 0000000000..300b2610b2 --- /dev/null +++ b/styles/keybr.com/catppuccin.user.css @@ -0,0 +1,151 @@ +/* ==UserStyle== +@name keybr.com Catppuccin +@namespace github.com/catppuccin/userstyles/styles/keybr.com +@homepageURL https://github.com/catppuccin/userstyles/tree/main/styles/keybr.com +@version 0.0.2 +@updateURL https://github.com/catppuccin/userstyles/raw/main/styles/keybr.com/catppuccin.user.css +@supportURL https://github.com/catppuccin/userstyles/issues?q=is%3Aopen+is%3Aissue+label%3Akeybr.com +@description Soothing pastel theme for keybr.com +@author Catppuccin +@license MIT + +@preprocessor less +@var select lightFlavor "Light Flavor" ["latte:Latte*", "frappe:Frappé", "macchiato:Macchiato", "mocha:Mocha"] +@var select darkFlavor "Dark Flavor" ["latte:Latte", "frappe:Frappé", "macchiato:Macchiato", "mocha:Mocha*"] +@var select accentColor "Accent" ["rosewater:Rosewater", "flamingo:Flamingo", "pink:Pink", "mauve:Mauve*", "red:Red", "maroon:Maroon", "peach:Peach", "yellow:Yellow", "green:Green", "teal:Teal", "blue:Blue", "sapphire:Sapphire", "sky:Sky", "lavender:Lavender", "subtext0:Gray"] +==/UserStyle== */ + +@-moz-document domain('keybr.com') { + html[data-color="dark"] { + #catppuccin(@darkFlavor, @accentColor); + } + html[data-color="light"] { + #catppuccin(@lightFlavor, @accentColor); + } + html[data-color="system"] { + @media (prefers-color-scheme: light) { + #catppuccin(@lightFlavor, @accentColor); + } + @media (prefers-color-scheme: dark) { + #catppuccin(@darkFlavor, @accentColor); + } + } + + #catppuccin(@lookup, @accent) { + @rosewater: @catppuccin[@@lookup][@rosewater]; + @flamingo: @catppuccin[@@lookup][@flamingo]; + @pink: @catppuccin[@@lookup][@pink]; + @mauve: @catppuccin[@@lookup][@mauve]; + @red: @catppuccin[@@lookup][@red]; + @maroon: @catppuccin[@@lookup][@maroon]; + @peach: @catppuccin[@@lookup][@peach]; + @yellow: @catppuccin[@@lookup][@yellow]; + @green: @catppuccin[@@lookup][@green]; + @teal: @catppuccin[@@lookup][@teal]; + @sky: @catppuccin[@@lookup][@sky]; + @sapphire: @catppuccin[@@lookup][@sapphire]; + @blue: @catppuccin[@@lookup][@blue]; + @lavender: @catppuccin[@@lookup][@lavender]; + @text: @catppuccin[@@lookup][@text]; + @subtext1: @catppuccin[@@lookup][@subtext1]; + @subtext0: @catppuccin[@@lookup][@subtext0]; + @overlay2: @catppuccin[@@lookup][@overlay2]; + @overlay1: @catppuccin[@@lookup][@overlay1]; + @overlay0: @catppuccin[@@lookup][@overlay0]; + @surface2: @catppuccin[@@lookup][@surface2]; + @surface1: @catppuccin[@@lookup][@surface1]; + @surface0: @catppuccin[@@lookup][@surface0]; + @base: @catppuccin[@@lookup][@base]; + @mantle: @catppuccin[@@lookup][@mantle]; + @crust: @catppuccin[@@lookup][@crust]; + @accent-color: @catppuccin[@@lookup][@@accent]; + + color-scheme: if(@lookup = latte, light, dark); + + ::selection { + background-color: fade(@accent-color, 30%); + } + + input, + textarea { + &::placeholder { + color: @subtext0 !important; + } + } + + --primary-d2: @overlay0; + --primary-d1: @overlay0; + --primary: @base; + --primary-l1: @crust; + --primary-l2: @mantle; + --secondary-d1: @subtext0; + --secondary: @text; + --secondary-l1: @subtext0; + --secondary-l2: @accent-color; + --secondary-f1: @subtext0; + --secondary-f2: @subtext0; + --accent-d2: @accent-color; + --accent-d1: @accent-color; + --accent: @accent-color; + --accent-l1: @accent-color; + --accent-l2: @accent-color; + --error-d1: @red; + --error: @red; + --error-l1: @red; + --shadow-color: fade(@crust, 88%); + --slow-key-color: @red; + --fast-key-color: @green; + --Chart-speed__color: @green; + --Chart-accuracy__color: @peach; + --Chart-complexity__color: @pink; + --Chart-threshold__color: @maroon; + --Chart-hist-h__color: @lavender; + --Chart-hist-m__color: @maroon; + --Chart-hist-r__color: @mauve; + --KeyboardKey-pointer__color: @accent-color; + --KeyboardKey-symbol__color: @crust; + --pinky-zone-color: @green; + --ring-zone-color: @teal; + --middle-zone-color: @yellow; + --left-index-zone-color: @blue; + --right-index-zone-color: @maroon; + --thumb-zone-color: @mauve; + --effort-0-color: @crust; + --effort-1-color: @crust; + --effort-2-color: @accent-color; + --effort-3-color: @accent-color; + --Value--more__color: @green; + --Value--less__color: @red; + --KeyboardKey-button--depressed__color: @accent-color; + --LessonKey--included__color: @crust; + --LessonKey--uncalibrated__background-color: @surface0; + --LessonKey--excluded__background-color: @surface0; + --LessonKey--excluded__color: @overlay0; + --DailyGoal-bar__color: @accent-color; + --KeyboardKey-button__color: @accent-color; + --textinput__color: @text; + --textinput--special__color: @subtext1; + --textinput--hit__color: @subtext0; + --textinput--miss__color: @red; + --syntax-keyword: @mauve; + --syntax-string: @green; + --syntax-number: @peach; + --syntax-comment: @overlay2; + --MenuItem__background-color: @mantle; + --MenuItem__color: @text; + --MenuItem--hover__background-color: @surface0; + --MenuItem--hover__color: @text; + --KeyboardKey-symbol--dead__color: @red; + --KeyboardKey-symbol--ligature__color: @blue; + } +} + +/* prettier-ignore */ +@catppuccin: { + @latte: { @rosewater: #dc8a78; @flamingo: #dd7878; @pink: #ea76cb; @mauve: #8839ef; @red: #d20f39; @maroon: #e64553; @peach: #fe640b; @yellow: #df8e1d; @green: #40a02b; @teal: #179299; @sky: #04a5e5; @sapphire: #209fb5; @blue: #1e66f5; @lavender: #7287fd; @text: #4c4f69; @subtext1: #5c5f77; @subtext0: #6c6f85; @overlay2: #7c7f93; @overlay1: #8c8fa1; @overlay0: #9ca0b0; @surface2: #acb0be; @surface1: #bcc0cc; @surface0: #ccd0da; @base: #eff1f5; @mantle: #e6e9ef; @crust: #dce0e8; }; + @frappe: { @rosewater: #f2d5cf; @flamingo: #eebebe; @pink: #f4b8e4; @mauve: #ca9ee6; @red: #e78284; @maroon: #ea999c; @peach: #ef9f76; @yellow: #e5c890; @green: #a6d189; @teal: #81c8be; @sky: #99d1db; @sapphire: #85c1dc; @blue: #8caaee; @lavender: #babbf1; @text: #c6d0f5; @subtext1: #b5bfe2; @subtext0: #a5adce; @overlay2: #949cbb; @overlay1: #838ba7; @overlay0: #737994; @surface2: #626880; @surface1: #51576d; @surface0: #414559; @base: #303446; @mantle: #292c3c; @crust: #232634; }; + @macchiato: { @rosewater: #f4dbd6; @flamingo: #f0c6c6; @pink: #f5bde6; @mauve: #c6a0f6; @red: #ed8796; @maroon: #ee99a0; @peach: #f5a97f; @yellow: #eed49f; @green: #a6da95; @teal: #8bd5ca; @sky: #91d7e3; @sapphire: #7dc4e4; @blue: #8aadf4; @lavender: #b7bdf8; @text: #cad3f5; @subtext1: #b8c0e0; @subtext0: #a5adcb; @overlay2: #939ab7; @overlay1: #8087a2; @overlay0: #6e738d; @surface2: #5b6078; @surface1: #494d64; @surface0: #363a4f; @base: #24273a; @mantle: #1e2030; @crust: #181926; }; + @mocha: { @rosewater: #f5e0dc; @flamingo: #f2cdcd; @pink: #f5c2e7; @mauve: #cba6f7; @red: #f38ba8; @maroon: #eba0ac; @peach: #fab387; @yellow: #f9e2af; @green: #a6e3a1; @teal: #94e2d5; @sky: #89dceb; @sapphire: #74c7ec; @blue: #89b4fa; @lavender: #b4befe; @text: #cdd6f4; @subtext1: #bac2de; @subtext0: #a6adc8; @overlay2: #9399b2; @overlay1: #7f849c; @overlay0: #6c7086; @surface2: #585b70; @surface1: #45475a; @surface0: #313244; @base: #1e1e2e; @mantle: #181825; @crust: #11111b; }; +} + +// vim:ft=less diff --git a/styles/keybr.com/preview.webp b/styles/keybr.com/preview.webp new file mode 100644 index 0000000000..8feebb2a7b --- /dev/null +++ b/styles/keybr.com/preview.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:770296305124f09673a9c2dfd54fcdd5f83057d8b26ef5b3a5a105a797f691d0 +size 110206