Skip to content

Commit 88e2795

Browse files
uncentersgoudham
andauthoredSep 8, 2024··
feat: add support for apple color list / .clr files (#87)
* feat: add support for apple color list / .clr files * style: format with swift-format * refactor: minor changes * refactor: simplify `hexToRGBA` * fix: use `red` not `calibratedRed` parameter for NSColor * refactor: clean up arg handling * ci(release-please): use macos runner, setup swift * fix: import Buffer type * fix: require `COMPILE_APPLE_COLOR_LIST=1` * ci(test): switch to macos & build everything * ci: upload palettes as artifact * Update .github/workflows/test.yml Co-authored-by: uncenter <47499684+uncenter@users.noreply.github.com> --------- Co-authored-by: sgoudham <sgoudham@gmail.com> Co-authored-by: Hammy <58985301+sgoudham@users.noreply.github.com>
1 parent 628a04a commit 88e2795

File tree

9 files changed

+135
-10
lines changed

9 files changed

+135
-10
lines changed
 

‎.github/workflows/release-please.yml

+7-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
tag_name: ${{ steps.release.outputs.tag_name }}
3131

3232
release:
33-
runs-on: ubuntu-latest
33+
runs-on: macos-latest
3434
needs: release-please
3535
if: ${{ needs.release-please.outputs.release_created || github.event.inputs.force_release }}
3636
steps:
@@ -43,8 +43,14 @@ jobs:
4343
node-version: "lts/*"
4444
registry-url: "https://registry.npmjs.org"
4545

46+
- uses: swift-actions/setup-swift@v2
47+
with:
48+
swift-version: "5"
49+
4650
- name: Build
4751
run: deno task build
52+
env:
53+
COMPILE_APPLE_COLOR_LIST: 1
4854

4955
- name: Publish NPM package
5056
working-directory: dist/npm

‎.github/workflows/test.yml

+15-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ on:
88
jobs:
99
main:
1010
name: Lint and test
11-
runs-on: ubuntu-latest
11+
runs-on: macos-latest
1212

1313
steps:
1414
- uses: actions/checkout@v4
1515

1616
- uses: nekowinston/setup-deno@v1
1717

18+
- uses: swift-actions/setup-swift@v2
19+
with:
20+
swift-version: "5"
21+
1822
- uses: actions/setup-node@v4
1923
with:
2024
node-version: "lts/*"
@@ -28,5 +32,13 @@ jobs:
2832
- name: Test
2933
run: deno test --doc
3034

31-
- name: Test Deno dnt
32-
run: deno task build:npm
35+
- name: Build
36+
run: deno task build
37+
env:
38+
COMPILE_APPLE_COLOR_LIST: 1
39+
40+
- name: Upload Built Palette Formats
41+
uses: actions/upload-artifact@v4
42+
with:
43+
name: "Catppuccin Palette Formats"
44+
path: dist/palettes

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Please use the respective files in [the latest GitHub Release](https://github.co
9595
| Adobe Suite, Affinity Suite, Sip | `ase/` |
9696
| Aseprite, Gimp, Inkscape, Krita | `gimp/` |
9797
| Procreate | `procreate/` |
98+
| Apple Color List (.clr) | `clr/` |
9899

99100
&nbsp;
100101

‎deno.lock

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎scripts/build_palettes.ts

+29-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { join } from "std/path/mod.ts";
44
import { flavors } from "@catppuccin/palette";
55
import {
66
generateAse,
7+
generateClrJson,
78
generateGimp,
89
generatePng,
910
generateProcreate,
@@ -14,14 +15,14 @@ const ROOT = new URL("../dist/palettes", import.meta.url).pathname;
1415
await emptyDir(ROOT);
1516

1617
await Promise.all(
17-
["ase", "gimp", "procreate", "png", "sip"].map((folder) =>
18+
["ase", "gimp", "procreate", "png", "sip", "clr"].map((folder) =>
1819
ensureDir(join(ROOT, folder))
1920
),
2021
);
2122

2223
Promise.all(
23-
Object.entries(flavors).flatMap(async ([name, { colors }]) => {
24-
const fname = name.charAt(0).toUpperCase() + name.slice(1);
24+
Object.entries(flavors).flatMap(async ([identifier, { name, colors }]) => {
25+
const fname = identifier.charAt(0).toUpperCase() + identifier.slice(1);
2526

2627
await Deno.writeFile(
2728
join(ROOT, `ase/${fname}.ase`),
@@ -43,5 +44,30 @@ Promise.all(
4344
join(ROOT, `sip/${fname}.palette`),
4445
generateSip(fname, colors),
4546
);
47+
48+
if (Deno.env.get("COMPILE_APPLE_COLOR_LIST") === "1") {
49+
const clrJson = join(ROOT, `clr/${fname}.json`);
50+
await Deno.writeTextFile(
51+
clrJson,
52+
generateClrJson(fname, colors),
53+
);
54+
55+
const cmd = new Deno.Command("swift", {
56+
args: [
57+
join(import.meta.dirname!, "./builders/palettes/json-to-clr.swift"),
58+
clrJson,
59+
join(ROOT, `clr/${name}.clr`),
60+
],
61+
});
62+
const { code, stderr, stdout } = await cmd.output();
63+
const td = new TextDecoder();
64+
if (code === 0) {
65+
console.log(td.decode(stdout).trim());
66+
} else {
67+
throw new Error(td.decode(stderr));
68+
}
69+
70+
await Deno.remove(clrJson);
71+
}
4672
}),
4773
).then(() => Deno.exit(0));

‎scripts/builders/mod.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { generateGimp } from "./palettes/gimp.ts";
77
export { generatePng } from "./palettes/png.ts";
88
export { generateProcreate } from "./palettes/procreate.ts";
99
export { generateSip } from "./palettes/sip.ts";
10+
export { generateClrJson } from "./palettes/clr.ts";

‎scripts/builders/palettes/clr.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { CatppuccinColors } from "@catppuccin/palette";
2+
3+
export const generateClrJson = (
4+
_name: string,
5+
palette: CatppuccinColors,
6+
): string => {
7+
const data: Record<string, { hex: string; order: number }> = Object
8+
.fromEntries(
9+
Object.entries(palette).map(([_, { name, hex, order }]) => {
10+
return [name, { hex, order }];
11+
}),
12+
);
13+
14+
return JSON.stringify(data);
15+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import AppKit
2+
import Foundation
3+
4+
struct ColorProperties: Decodable {
5+
let hex: String
6+
let order: Int
7+
}
8+
9+
typealias ColorList = [String: ColorProperties]
10+
11+
func hexToRGBA(_ color: String) -> (r: CGFloat, g: CGFloat, b: CGFloat) {
12+
var hexColor = String(color.dropFirst())
13+
14+
let r = CGFloat(Int(hexColor.prefix(2), radix: 16) ?? 0) / 255
15+
let g = CGFloat(Int(hexColor.dropFirst(2).prefix(2), radix: 16) ?? 0) / 255
16+
let b = CGFloat(Int(hexColor.dropFirst(4).prefix(2), radix: 16) ?? 0) / 255
17+
return (r, g, b)
18+
}
19+
20+
func convertJSONToCLR(inputFilePath: String, outputFilePath: String) {
21+
let url = URL(fileURLWithPath: inputFilePath)
22+
guard let data = try? Data(contentsOf: url),
23+
let colorList = try? JSONDecoder().decode(ColorList.self, from: data)
24+
else {
25+
print("Failed to read or parse JSON file.")
26+
return
27+
}
28+
29+
let sortedColors = colorList.sorted { (lhs, rhs) -> Bool in
30+
return lhs.value.order < rhs.value.order
31+
}
32+
33+
let paletteName = url.deletingPathExtension().lastPathComponent
34+
let nsColorList = NSColorList(name: paletteName)
35+
36+
for (name, properties) in sortedColors {
37+
let hex = properties.hex
38+
let color = hexToRGBA(hex)
39+
nsColorList.setColor(
40+
NSColor(red: color.r, green: color.g, blue: color.b, alpha: 1), forKey: name)
41+
}
42+
43+
let clrFilePath = URL(fileURLWithPath: outputFilePath)
44+
do {
45+
try nsColorList.write(to: clrFilePath)
46+
print("Successfully saved palette to \(outputFilePath).")
47+
} catch {
48+
print("Failed to save color palette: \(error)")
49+
}
50+
}
51+
52+
if CommandLine.argc != 3 {
53+
print("\(CommandLine.arguments[0]): Not enough arguments provided (expected input and output filenames)")
54+
exit(1)
55+
}
56+
57+
convertJSONToCLR(inputFilePath: CommandLine.arguments[1], outputFilePath: CommandLine.arguments[2])

‎types/procreate-swatches.d.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import type { Buffer } from "node:buffer";
2+
13
type ColorSpace = "rgb" | "hsl" | "hsv" | "hwb" | "xyz" | "lab" | "lch";
24
type Colors = [number[], ColorSpace][];
35

46
export function readSwatchesFile(
57
data: string | Uint8Array | ArrayBuffer | Blob,
6-
colorSpace?: ColorSpace
8+
colorSpace?: ColorSpace,
79
): Promise<{
810
name: string;
911
colors: Colors;
@@ -21,11 +23,11 @@ type SwatchReturnType = {
2123
};
2224

2325
export function createSwatchesFile<
24-
F extends keyof SwatchReturnType | undefined = undefined
26+
F extends keyof SwatchReturnType | undefined = undefined,
2527
>(
2628
name: string,
2729
colors: Colors,
28-
format?: F
30+
format?: F,
2931
): Promise<F extends keyof SwatchReturnType ? SwatchReturnType[F] : Uint8Array>;
3032

3133
interface ProcreateSwatchesError extends Error {

0 commit comments

Comments
 (0)
Please sign in to comment.