diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index dd9784e..bde4de9 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,35 +1,9 @@
-
-
## What kind of change does this PR introduce?
-## What is the current behavior?
-
-
-
-## What is the new behavior?
-
-
-
-## What steps did you take to test this? This is required before I can merge, make sure to test the flow you've updated.
-
-1. Step A
-2. Step B
-3. Step C
-
## Checklist
-
-
-
-
- [ ] Documentation
- [ ] Testing
- [ ] Ready to be merged
@@ -37,5 +11,4 @@ merge of your pull request!
- [ ] Added myself to contributors table
-
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 05fdb0c..4d60583 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,71 +1,93 @@
name: build
on:
- push:
- paths-ignore:
- - "**.md"
- - "**.bbcode"
- - LICENSE
- branches: [main, dev]
- pull_request:
- paths-ignore:
- - "**.md"
- - "**.bbcode"
- - LICENSE
- branches: [main]
+ push:
+ paths-ignore:
+ - "**.md"
+ - "**.bbcode"
+ - LICENSE
+ branches: [main, dev]
+ pull_request:
+ paths-ignore:
+ - "**.md"
+ - "**.bbcode"
+ - LICENSE
+ branches: [main]
jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Install build dependencies (apt)
- run: sudo apt install -y libx11-dev libxcursor-dev libpng-dev
- continue-on-error: false
- - name: Get yarn cache directory path
- id: yarn-cache-dir-path
- run: echo "::set-output name=dir::$(yarn cache dir)"
- - name: Caching yarn packages
- uses: actions/cache@v2
- id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
- with:
- path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
- key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-yarn-
- - name: Set Up NodeJS 12.x
- uses: actions/setup-node@v1
- with:
- node-version: "12.x"
- - name: Caching pip packages
- uses: actions/cache@v2
- id: pip-cache # use this to check for `cache-hit` (`steps.pip-cache.outputs.cache-hit != 'true'`)
- with:
- path: ~/.cache/pip
- key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
- restore-keys: |
- ${{ runner.os }}-pip-
- - name: Set up Python 3.8
- uses: actions/setup-python@v2
- with:
- python-version: "3.8"
- - name: Generating `macOSBigSur` Cursor Theme
- run: make
- continue-on-error: false
- - name: Compressing UNIX theme
- run: tar -cvzf macOSBigSur.tar.gz themes/macOSBigSur
- - name: Uploading `bitmaps` artifact
- uses: actions/upload-artifact@v2
- with:
- name: bitmaps
- path: bitmaps/*
- - name: Uploading `macOSBigSur` UNIX Theme artifact
- uses: actions/upload-artifact@v2
- with:
- name: macOSBigSur
- path: macOSBigSur.tar.gz
- - name: Uploading `macOSBigSur` Windows Theme artifact
- uses: actions/upload-artifact@v2
- with:
- name: macOSBigSur_Windows
- path: themes/macOSBigSur_Windows/*
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install build dependencies (apt)
+ run: sudo apt install -y libx11-dev libxcursor-dev libpng-dev
+ continue-on-error: false
+ - name: Get yarn cache directory path
+ id: yarn-cache-dir-path
+ run: echo "::set-output name=dir::$(yarn cache dir)"
+ - name: Caching yarn packages
+ uses: actions/cache@v2
+ id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+ with:
+ path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+ key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-yarn-
+
+ - name: Set Up NodeJS 12.x
+ uses: actions/setup-node@v1
+ with:
+ node-version: "12.x"
+
+ - name: Caching pip packages
+ uses: actions/cache@v2
+ id: pip-cache # use this to check for `cache-hit` (`steps.pip-cache.outputs.cache-hit != 'true'`)
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: "3.8"
+
+ - name: Generating `macOSBigSur` Cursor Theme
+ run: make
+ continue-on-error: false
+
+ - name: Compressing UNIX theme
+ run: |
+ tar -cvzf macOSBigSur.tar.gz themes/macOSBigSur
+ tar -cvzf macOSBigSur-White.tar.gz themes/macOSBigSur-White
+
+ - name: Uploading `bitmaps` artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: bitmaps
+ path: bitmaps/*
+
+ - name: Uploading `macOSBigSur` UNIX Theme artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: macOSBigSur
+ path: macOSBigSur.tar.gz
+
+ - name: Uploading `macOSBigSur-White` UNIX Theme artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: macOSBigSur-White
+ path: macOSBigSur-White.tar.gz
+
+ - name: Uploading `macOSBigSur` Windows Theme artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: macOSBigSur-Windows
+ path: themes/macOSBigSur-Windows/*
+
+ - name: Uploading `macOSBigSur-White` Windows Theme artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: macOSBigSur-White-Windows
+ path: themes/macOSBigSur-White-Windows/*
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 082ba51..8e3385a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased]
+## [v1.2.0] - 25 Aug 2021
+
+### Added
+
+- Dark branding
+- Multiple config supports inside bitmapper
+- `macOSBigSur-White` CI added inside `build.yml`
+
+### Changed
+
+- Drop shadow removed from `plus.svg`
+- Key colors added inside `.svg` files
+- `builder/src` configured as dynamic comment and theme-name
+- `builder/Makefile` updated
+- `Makefile` with macOSBigSur-White cursor theme
+- `PULL_REQUEST_TEMPLATE.md` template updated
+
## [v1.1.6] - 13 Aug 2021
### Added
@@ -212,7 +229,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Logo and badges
- CI/CD Pipelines
-[unreleased]: https://github.com/ful1e5/apple_cursor/compare/v1.1.6...main
+[unreleased]: https://github.com/ful1e5/apple_cursor/compare/v1.2.0...main
+[v1.2.0]: https://github.com/ful1e5/apple_cursor/compare/v1.1.6...v1.2.0
[v1.1.6]: https://github.com/ful1e5/apple_cursor/compare/v1.1.5...v1.1.6
[v1.1.5]: https://github.com/ful1e5/apple_cursor/compare/v1.1.4...v1.1.5
[v1.1.4]: https://github.com/ful1e5/apple_cursor/compare/v1.1.3...v1.1.4
diff --git a/Makefile b/Makefile
index 0690cd3..47a0293 100644
--- a/Makefile
+++ b/Makefile
@@ -19,8 +19,7 @@ windows: clean render bitmaps
# Installation
-theme := macOSBigSur
-src := ./themes/$(theme)
+src := ./themes/
local := ~/.icons
local_dest := $(local)/$(theme)
@@ -31,35 +30,42 @@ root_dest := $(root)/$(theme)
.ONESHELL:
SHELL:=/bin/bash
+
install: $(src)
@if [[ $EUID -ne 0 ]]; then
- @echo "> Installing '$(theme)' cursors inside $(local)/..."
+ @echo "> Installing 'macOSBigSur' cursors inside $(local)/..."
@mkdir -p $(local)
- @cp -r $(src) $(local_dest) && echo "> Installed!"
+ @cp -r ./themes/macOSBigSur $(local_dest)
+ @cp -r ./themes/macOSBigSur-White $(local_dest) && echo "> Installed!"
@else
- @echo "> Installing '$(theme)' cursors inside $(root)/..."
+ @echo "> Installing 'macOSBigSur' cursors inside $(root)/..."
@mkdir -p $(root)
- @sudo cp -r $(src) $(root_dest) && echo "> Installed!"
+ @sudo cp -r ./themes/macOSBigSur $(root_dest)
+ @sudo cp -r ./themes/macOSBigSur-White $(root_dest) && echo "> Installed!"
@fi
uninstall:
@if [[ $EUID -ne 0 ]]; then
- @echo "> Removing '$(local_dest)'..."
- @rm -rf $(local_dest)
+ @echo "> Removing 'macOSBigSur' from '$(local)'..."
+ @rm -rf $(local)/macOSBigSur
+ @rm -rf $(local)/macOSBigSur-White
@else
- @echo "> Removing '$(root_dest)'..."
- @sudo rm -rf $(root_dest)
+ @echo "> Removing 'macOSBigSur' from '$(root)'..."
+ @rm -rf $(root)/macOSBigSur
+ @rm -rf $(root)/macOSBigSur-White
@fi
reinstall: uninstall install
+# generates binaries
BIN_DIR = ../bin
+THEMES = White
prepare: bitmaps themes
- # Bitmaps
@rm -rf bin && mkdir bin
@cd bitmaps && zip -r $(BIN_DIR)/bitmaps.zip * && cd ..
- # Themes
@cd themes
@tar -czvf $(BIN_DIR)/macOSBigSur.tar.gz macOSBigSur
- @zip -r $(BIN_DIR)/macOSBigSur_Windows.zip macOSBigSur_Windows
+ @zip -r $(BIN_DIR)/macOSBigSur-Windows.zip macOSBigSur-Windows
+ @$(foreach theme,$(THEMES), tar -czvf $(BIN_DIR)/macOSBigSur-$(theme).tar.gz macOSBigSur-$(theme);)
+ @$(foreach theme,$(THEMES), zip -r $(BIN_DIR)/macOSBigSur-$(theme)-Windows.zip macOSBigSur-$(theme)-Windows;)
@cd ..
diff --git a/README.md b/README.md
index 8ad37da..48d1c36 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
@@ -134,11 +134,16 @@ sudo mv macOSBigSur /usr/share/icons/
-
+
macOSBigSur Cursors 🍎
+
+
+
+ macOSBigSur White Cursors 🍎
+
# Dependencies
diff --git a/bitmapper/package.json b/bitmapper/package.json
index 2c441b4..b97ffa0 100644
--- a/bitmapper/package.json
+++ b/bitmapper/package.json
@@ -1,6 +1,6 @@
{
"name": "apple_cursor_bitmapper",
- "version": "1.1.6",
+ "version": "1.2.0",
"main": "index.js",
"scripts": {
"render": "yarn ts-node src/index.ts"
diff --git a/bitmapper/src/config.ts b/bitmapper/src/config.ts
index 6ab4744..aa654b1 100644
--- a/bitmapper/src/config.ts
+++ b/bitmapper/src/config.ts
@@ -1,23 +1,28 @@
-import path from "path";
-import { readdirSync, existsSync } from "fs";
+import { Colors } from "./core/types";
-// Directory resolve
-const projectRoot = path.resolve(__dirname, "../../");
-
-const outDir = path.resolve(projectRoot, "bitmaps");
-const staticSvgDir = path.resolve(projectRoot, "svg", "static");
-const animatedSvgDir = path.resolve(projectRoot, "svg", "animated");
-
-// Generate a svg list
-if (!existsSync(staticSvgDir) || !existsSync(animatedSvgDir)) {
- throw new Error("svg directory not found");
+interface Config {
+ themeName: string;
+ color: Colors;
}
-const staticCursors = readdirSync(staticSvgDir).map((f) =>
- path.resolve(staticSvgDir, f)
-);
-const animatedCursors = readdirSync(animatedSvgDir).map((f) =>
- path.resolve(animatedSvgDir, f)
-);
+const black = "#000000";
+const white = "#FFFFFF";
-export { staticCursors, animatedCursors, outDir };
+const config: Config[] = [
+ {
+ themeName: "macOSBigSur",
+ color: {
+ base: black,
+ outline: white,
+ },
+ },
+ {
+ themeName: "macOSBigSur-White",
+ color: {
+ base: white,
+ outline: black,
+ },
+ },
+];
+
+export { config };
diff --git a/bitmapper/src/core/BitmapsGenerator.ts b/bitmapper/src/core/BitmapsGenerator.ts
new file mode 100644
index 0000000..c9017a0
--- /dev/null
+++ b/bitmapper/src/core/BitmapsGenerator.ts
@@ -0,0 +1,155 @@
+import fs from "fs";
+import path from "path";
+
+import puppeteer, { Browser, ElementHandle, Page } from "puppeteer";
+
+import { frameNumber } from "./util/frameNumber";
+import { matchImages } from "./util/matchImages";
+import { toHTML } from "./util/toHTML";
+
+class BitmapsGenerator {
+ /**
+ * Generate Png files from svg code.
+ * @param themeName Give name, So all bitmaps files are organized in one directory.
+ * @param bitmapsDir `absolute` or `relative` path, Where `.png` files will store.
+ */
+ constructor(private bitmapsDir: string) {
+ this.bitmapsDir = path.resolve(bitmapsDir);
+ this.createDir(this.bitmapsDir);
+ }
+
+ /**
+ * Create directory if it doesn't exists.
+ * @param dirPath directory `absolute` path.
+ */
+ private createDir(dirPath: string) {
+ if (!fs.existsSync(dirPath)) {
+ fs.mkdirSync(dirPath, { recursive: true });
+ }
+ }
+
+ /**
+ * Prepare headless browser.
+ */
+ public async getBrowser(): Promise {
+ return await puppeteer.launch({
+ ignoreDefaultArgs: ["--no-sandbox"],
+ headless: true,
+ });
+ }
+
+ private async getSvgElement(
+ page: Page,
+ content: string
+ ): Promise> {
+ if (!content) {
+ throw new Error(`${content} File Read error`);
+ }
+
+ const html = toHTML(content);
+ await page.setContent(html, { timeout: 0 });
+
+ const svg = await page.$("#container svg");
+
+ if (!svg) {
+ throw new Error("svg element not found!");
+ }
+ return svg;
+ }
+
+ public async generateStatic(browser: Browser, content: string, key: string) {
+ const page = await browser.newPage();
+ const svg = await this.getSvgElement(page, content);
+
+ const out = path.resolve(this.bitmapsDir, `${key}.png`);
+
+ await svg.screenshot({ omitBackground: true, path: out });
+ await page.close();
+ }
+
+ private async screenshot(
+ element: ElementHandle
+ ): Promise {
+ const buffer = await element.screenshot({
+ encoding: "binary",
+ omitBackground: true,
+ });
+
+ if (!buffer) {
+ throw new Error("SVG element screenshot not working");
+ }
+ return buffer;
+ }
+
+ private async stopAnimation(page: Page) {
+ const client = await page.target().createCDPSession();
+ await client.send("Animation.setPlaybackRate", {
+ playbackRate: 0,
+ });
+ }
+
+ private async resumeAnimation(page: Page, playbackRate: number) {
+ const client = await page.target().createCDPSession();
+ await client.send("Animation.setPlaybackRate", {
+ playbackRate,
+ });
+ }
+
+ private async saveFrameImage(key: string, frame: Buffer | string) {
+ const out_path = path.resolve(this.bitmapsDir, key);
+ fs.writeFileSync(out_path, frame);
+ }
+
+ public async generateAnimated(
+ browser: Browser,
+ content: string,
+ key: string,
+ options?: {
+ playbackRate?: number;
+ diff?: number;
+ frameLimit?: number;
+ framePadding?: number;
+ }
+ ) {
+ const opt = Object.assign(
+ { playbackRate: 0.1, diff: 0, frameLimit: 300, framePadding: 4 },
+ options
+ );
+
+ const page = await browser.newPage();
+ const svg = await this.getSvgElement(page, content);
+ await this.stopAnimation(page);
+
+ let index = 1;
+ let breakRendering = false;
+ let prevImg: Buffer | string;
+
+ // Rendering frames till `imgN` matched to `imgN-1` (When Animation is done)
+ while (!breakRendering) {
+ if (index > opt.frameLimit) {
+ throw new Error("Reached the frame limit.");
+ }
+
+ await this.resumeAnimation(page, opt.playbackRate);
+ const img: string | Buffer = await this.screenshot(svg);
+ await this.stopAnimation(page);
+
+ if (index > 1) {
+ // @ts-ignore
+ const diff = matchImages(prevImg, img);
+ if (diff <= opt.diff) {
+ breakRendering = !breakRendering;
+ }
+ }
+ const number = frameNumber(index, opt.framePadding);
+ const frame = `${key}-${number}.png`;
+
+ this.saveFrameImage(frame, img);
+
+ prevImg = img;
+ ++index;
+ }
+ await page.close();
+ }
+}
+export { BitmapsGenerator };
diff --git a/bitmapper/src/core/SVGHandler/SvgDirectoryParser.ts b/bitmapper/src/core/SVGHandler/SvgDirectoryParser.ts
new file mode 100644
index 0000000..516c69b
--- /dev/null
+++ b/bitmapper/src/core/SVGHandler/SvgDirectoryParser.ts
@@ -0,0 +1,77 @@
+import fs from "fs";
+import path from "path";
+
+interface Svg {
+ key: string;
+ content: string;
+}
+
+class SvgDirectoryParser {
+ /**
+ * Manage and Parse SVG file path in `absolute` fashion.
+ * This Parser look svg files as below fashion:
+ * `
+ * <@svgDir>/static
+ * <@svgDir>/animated
+ * `
+ * @param svgDir is relative/absolute path, Where `SVG` files are stored.
+ */
+ semiAnimated: boolean = false;
+ constructor(private svgDir: string) {
+ if (!fs.existsSync(this.svgDir)) {
+ throw new Error(`SVG files not found in ${this.svgDir}`);
+ }
+ }
+
+ private readData(f: string): Svg {
+ const content = fs.readFileSync(f, "utf-8");
+ const key = path.basename(f, ".svg");
+ return { content, key };
+ }
+
+ /**
+ * Return absolute paths array of SVG files data located inside '@svgDir/static'
+ */
+ public getStatic(): Svg[] {
+ const staticDir = path.resolve(this.svgDir, "static");
+
+ if (!fs.existsSync(staticDir)) {
+ console.log(`${this.svgDir} contains semi-animated .svg files`);
+ this.semiAnimated = true;
+ return [];
+ } else {
+ const svgs = fs
+ .readdirSync(staticDir)
+ .map((f) => this.readData(path.resolve(staticDir, f)));
+
+ if (svgs.length == 0) {
+ throw new Error("Static Cursors directory is empty");
+ }
+ return svgs;
+ }
+ }
+ /**
+ * Return absolute paths array of SVG files data located inside '@svgDir/animated'
+ */
+ public getAnimated(): Svg[] {
+ const animatedDir = path.resolve(this.svgDir, "animated");
+
+ if (!fs.existsSync(animatedDir)) {
+ throw new Error("Animated Cursors directory not found");
+ }
+
+ const svgs = fs
+ .readdirSync(animatedDir)
+ .map((f) => this.readData(path.resolve(animatedDir, f)));
+
+ if (svgs.length == 0 && this.semiAnimated) {
+ throw new Error(
+ `Can't parse svg directory ${this.svgDir} as semi-animated theme`
+ );
+ }
+
+ return svgs;
+ }
+}
+
+export { SvgDirectoryParser };
diff --git a/bitmapper/src/core/SVGHandler/colorSvg.ts b/bitmapper/src/core/SVGHandler/colorSvg.ts
new file mode 100644
index 0000000..49a0b50
--- /dev/null
+++ b/bitmapper/src/core/SVGHandler/colorSvg.ts
@@ -0,0 +1,52 @@
+import { Colors } from "../types";
+
+/**
+ * Default Key Colors for generating colored svg.
+ * base="#00FF00" (Green)
+ * outline="#0000FF" (Blue)
+ * watch.background="#FF0000" (Red)
+ * */
+const defaultKeyColors: Colors = {
+ base: "#00FF00",
+ outline: "#0000FF",
+ watch: {
+ background: "#FF0000",
+ },
+};
+
+/**
+ * Customize colors of svg code.
+ * @param {string} content SVG code.
+ * @param {Colors} colors Customize colors.
+ * @param {Colors} [keys] Colors Key, That was written SVG code.
+ * @returns {string} SVG code with colors.
+ */
+const colorSvg = (
+ content: string,
+ colors: Colors,
+ keys: Colors = defaultKeyColors
+): string => {
+ content = content
+ .replace(new RegExp(keys.base, "ig"), colors.base)
+ .replace(new RegExp(keys.outline, "ig"), colors.outline);
+
+ try {
+ // === trying to replace `watch` color ===
+
+ if (!colors.watch?.background) {
+ throw new Error("");
+ }
+ const { background: b } = colors.watch;
+ content = content.replace(new RegExp(keys.watch!.background, "ig"), b); // Watch Background
+ } catch (error) {
+ // === on error => replace `watch` color as `base` ===
+
+ content = content.replace(
+ new RegExp(keys.watch!.background, "ig"),
+ colors.base
+ );
+ }
+ return content;
+};
+
+export { colorSvg };
diff --git a/bitmapper/src/core/SVGHandler/index.ts b/bitmapper/src/core/SVGHandler/index.ts
new file mode 100644
index 0000000..308a433
--- /dev/null
+++ b/bitmapper/src/core/SVGHandler/index.ts
@@ -0,0 +1,4 @@
+import { colorSvg } from "./colorSvg";
+import { SvgDirectoryParser } from "./SvgDirectoryParser";
+
+export { colorSvg, SvgDirectoryParser };
diff --git a/bitmapper/src/core/index.ts b/bitmapper/src/core/index.ts
new file mode 100644
index 0000000..2fe958b
--- /dev/null
+++ b/bitmapper/src/core/index.ts
@@ -0,0 +1,4 @@
+import { BitmapsGenerator } from "./BitmapsGenerator";
+import * as SVGHandler from "./SVGHandler";
+
+export { BitmapsGenerator, SVGHandler };
diff --git a/bitmapper/src/core/types.ts b/bitmapper/src/core/types.ts
new file mode 100644
index 0000000..da9fb1c
--- /dev/null
+++ b/bitmapper/src/core/types.ts
@@ -0,0 +1,20 @@
+/**
+ * Hex Colors in string Format.
+ *
+ * `Example: `"#FFFFFF"
+ */
+type HexColor = string;
+
+/**
+ * @Colors expect `base`, `outline` & `watch-background` colors in **HexColor** Format.
+ * @default background is `base` color.
+ */
+type Colors = {
+ base: HexColor;
+ outline: HexColor;
+ watch?: {
+ background: HexColor;
+ };
+};
+
+export { Colors };
diff --git a/bitmapper/src/utils/frameNumber.ts b/bitmapper/src/core/util/frameNumber.ts
similarity index 100%
rename from bitmapper/src/utils/frameNumber.ts
rename to bitmapper/src/core/util/frameNumber.ts
diff --git a/bitmapper/src/utils/matchImages.ts b/bitmapper/src/core/util/matchImages.ts
similarity index 100%
rename from bitmapper/src/utils/matchImages.ts
rename to bitmapper/src/core/util/matchImages.ts
diff --git a/bitmapper/src/utils/toHTML.ts b/bitmapper/src/core/util/toHTML.ts
similarity index 100%
rename from bitmapper/src/utils/toHTML.ts
rename to bitmapper/src/core/util/toHTML.ts
diff --git a/bitmapper/src/index.ts b/bitmapper/src/index.ts
index 9cff291..7873c9e 100644
--- a/bitmapper/src/index.ts
+++ b/bitmapper/src/index.ts
@@ -1,127 +1,37 @@
-import fs from "fs";
import path from "path";
-import puppeteer, { ElementHandle, Page } from "puppeteer";
-import { animatedCursors, outDir, staticCursors } from "./config";
-import { frameNumber } from "./utils/frameNumber";
-import { matchImages } from "./utils/matchImages";
-import { toHTML } from "./utils/toHTML";
+import { BitmapsGenerator, SVGHandler } from "./core";
+import { config } from "./config";
-const getSVGElement = async (page: Page) => {
- const svg = await page.$("#container svg");
-
- if (!svg) {
- throw new Error("svg element not found!");
- }
- return svg;
-};
-
-const screenshot = async (element: ElementHandle): Promise => {
- return element.screenshot({
- omitBackground: true,
- encoding: "binary",
- });
-};
-
-const stopAnimation = async (page: Page) => {
- // @ts-ignore
- await page._client.send("Animation.setPlaybackRate", {
- playbackRate: 0,
- });
-};
-
-const resumeAnimation = async (page: Page, playbackRate: number = 0.1) => {
- // @ts-ignore
- await page._client.send("Animation.setPlaybackRate", {
- playbackRate,
- });
-};
-
-const saveFrameImage = (key: string, frame: Buffer) => {
- const out_path = path.resolve(outDir, key);
- fs.writeFileSync(out_path, frame, { encoding: "binary" });
-};
+const root = path.resolve(__dirname, "../../");
+const svgDir = path.resolve(root, "svg");
const main = async () => {
- const browser = await puppeteer.launch({
- ignoreDefaultArgs: ["--single-process", "--no-sandbox"],
- headless: true,
- });
+ for (const { themeName, color } of config) {
+ console.log("=>", themeName);
- if (!fs.existsSync(outDir)) {
- fs.mkdirSync(outDir);
- } else {
- throw new Error(`out directory '${outDir}' already exists.`);
- }
+ const bitmapsDir = path.resolve(root, "bitmaps", themeName);
+ const svg = new SVGHandler.SvgDirectoryParser(svgDir);
- for (const svgFilePath of staticCursors) {
- const svgData = fs.readFileSync(svgFilePath, "utf-8");
- if (!svgData) {
- throw new Error(`${svgFilePath} File Read error`);
+ const png = new BitmapsGenerator(bitmapsDir);
+ const browser = await png.getBrowser();
+
+ for (let { key, content } of svg.getStatic()) {
+ console.log(" -> Saving", key, "...");
+
+ content = SVGHandler.colorSvg(content, color);
+ await png.generateStatic(browser, content, key);
}
- const page = await browser.newPage();
- const html = toHTML(svgData);
+ for (let { key, content } of svg.getAnimated()) {
+ console.log(" -> Saving", key, "...");
- await page.setContent(html);
- const svg = await getSVGElement(page);
-
- const key = `${path.basename(svgFilePath, ".svg")}.png`;
- const out = path.join(outDir, key);
-
- console.log("Saving", key, "...");
- await svg.screenshot({ omitBackground: true, path: out });
- await page.close();
- }
-
- for (const svgFilePath of animatedCursors) {
- const svgData = fs.readFileSync(svgFilePath, "utf8");
- if (!svgData) {
- throw new Error(`${svgFilePath} File Read error`);
+ content = SVGHandler.colorSvg(content, color);
+ await png.generateAnimated(browser, content, key);
}
- const page = await browser.newPage();
- const html = toHTML(svgData);
-
- await page.setContent(html);
- const svg = await getSVGElement(page);
- await stopAnimation(page);
-
- let index = 1;
- const frameLimit = 300;
- let breakRendering = false;
- let prevImg: Buffer;
-
- // Rendering frames till `imgN` matched to `imgN-1` (When Animation is done)
- while (!breakRendering) {
- if (index > frameLimit) {
- throw new Error("Reached the frame limit.");
- }
-
- resumeAnimation(page);
- const img = await screenshot(svg);
- stopAnimation(page);
-
- if (index > 1) {
- // @ts-ignore
- const diff = matchImages(prevImg, img);
- if (diff <= 100) {
- breakRendering = !breakRendering;
- }
- }
- const frame = frameNumber(index, 3);
- const key = `${path.basename(svgFilePath, ".svg")}-${frame}.png`;
-
- console.log("Saving", key, "...");
- saveFrameImage(key, img);
-
- prevImg = img;
- ++index;
- }
-
- await page.close();
+ await browser.close();
}
- await browser.close();
};
main();
diff --git a/bitmapper/yarn.lock b/bitmapper/yarn.lock
index 88952c5..ba44ec5 100644
--- a/bitmapper/yarn.lock
+++ b/bitmapper/yarn.lock
@@ -15,14 +15,14 @@
defer-to-connect "^1.0.1"
"@types/node@*":
- version "14.14.37"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
- integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
+ version "16.7.1"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.1.tgz#c6b9198178da504dfca1fd0be9b2e1002f1586f0"
+ integrity sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A==
"@types/pixelmatch@^5.2.2":
- version "5.2.2"
- resolved "https://registry.yarnpkg.com/@types/pixelmatch/-/pixelmatch-5.2.2.tgz#3403238d4b920bf2255fb6cbf9a098bef796ce62"
- integrity sha512-ndpfW/H8+SAiI3wt+f8DlHGgB7OeBdgFgBJ6v/1l3SpJ0MCn9wtXFb4mUccMujN5S4DMmAh7MVy1O3WcXrHUKw==
+ version "5.2.4"
+ resolved "https://registry.yarnpkg.com/@types/pixelmatch/-/pixelmatch-5.2.4.tgz#ca145cc5ede1388c71c68edf2d1f5190e5ddd0f6"
+ integrity sha512-HDaSHIAv9kwpMN7zlmwfTv6gax0PiporJOipcrGsVNF3Ba+kryOZc0Pio5pn6NhisgWr7TaajlPEKTbTAypIBQ==
dependencies:
"@types/node" "*"
@@ -34,16 +34,16 @@
"@types/node" "*"
"@types/puppeteer@^5.4.2":
- version "5.4.3"
- resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-5.4.3.tgz#cdca84aa7751d77448d8a477dbfa0af1f11485f2"
- integrity sha512-3nE8YgR9DIsgttLW+eJf6mnXxq8Ge+27m5SU3knWmrlfl6+KOG0Bf9f7Ua7K+C4BnaTMAh3/UpySqdAYvrsvjg==
+ version "5.4.4"
+ resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-5.4.4.tgz#e92abeccc4f46207c3e1b38934a1246be080ccd0"
+ integrity sha512-3Nau+qi69CN55VwZb0ATtdUAlYlqOOQ3OfQfq0Hqgc4JMFXiQT/XInlwQ9g6LbicDslE6loIFsXFklGh5XmI6Q==
dependencies:
"@types/node" "*"
"@types/yauzl@^2.9.1":
- version "2.9.1"
- resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af"
- integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a"
+ integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==
dependencies:
"@types/node" "*"
@@ -81,10 +81,10 @@ ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
-anymatch@~3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
- integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+anymatch@~3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+ integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
@@ -95,9 +95,9 @@ arg@^4.1.0:
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-js@^1.3.1:
version "1.5.1"
@@ -153,9 +153,9 @@ buffer-crc32@~0.2.3:
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^5.2.1, buffer@^5.5.0:
version "5.7.1"
@@ -192,19 +192,19 @@ chalk@^3.0.0:
supports-color "^7.1.0"
chokidar@^3.2.2:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
- integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
+ integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
dependencies:
- anymatch "~3.1.1"
+ anymatch "~3.1.2"
braces "~3.0.2"
- glob-parent "~5.1.0"
+ glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
- readdirp "~3.5.0"
+ readdirp "~3.6.0"
optionalDependencies:
- fsevents "~2.3.1"
+ fsevents "~2.3.2"
chownr@^1.1.1:
version "1.1.4"
@@ -268,9 +268,9 @@ crypto-random-string@^2.0.0:
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
debug@4, debug@^4.1.0, debug@^4.1.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
- integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
+ integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
dependencies:
ms "2.1.2"
@@ -392,7 +392,7 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-fsevents@~2.3.1:
+fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
@@ -411,7 +411,7 @@ get-stream@^5.1.0:
dependencies:
pump "^3.0.0"
-glob-parent@~5.1.0:
+glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@@ -419,9 +419,9 @@ glob-parent@~5.1.0:
is-glob "^4.0.1"
glob@^7.1.3:
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
- integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ version "7.1.7"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -455,9 +455,9 @@ got@^9.6.0:
url-parse-lax "^3.0.0"
graceful-fs@^4.1.2:
- version "4.2.6"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
- integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
+ version "4.2.8"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
+ integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
has-flag@^3.0.0:
version "3.0.0"
@@ -695,9 +695,9 @@ node-fetch@^2.6.1:
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
nodemon@^2.0.7:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.7.tgz#6f030a0a0ebe3ea1ba2a38f71bf9bab4841ced32"
- integrity sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.12.tgz#5dae4e162b617b91f1873b3bfea215dd71e144d5"
+ integrity sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA==
dependencies:
chokidar "^3.2.2"
debug "^3.2.6"
@@ -784,9 +784,9 @@ pend@~1.2.0:
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
picomatch@^2.0.4, picomatch@^2.2.1:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
- integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
+ integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
pixelmatch@^5.2.1:
version "5.2.1"
@@ -884,10 +884,10 @@ readable-stream@^3.1.1, readable-stream@^3.4.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
-readdirp@~3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
- integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
@@ -1092,9 +1092,9 @@ typedarray-to-buffer@^3.1.5:
is-typedarray "^1.0.0"
typescript@^4.1.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
- integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
+ version "4.3.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
+ integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
unbzip2-stream@^1.3.3:
version "1.4.3"
@@ -1172,9 +1172,15 @@ write-file-atomic@^3.0.0:
typedarray-to-buffer "^3.1.5"
ws@^7.2.3:
+<<<<<<< HEAD
version "7.4.6"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
+=======
+ version "7.5.3"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
+ integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
+>>>>>>> dev
xdg-basedir@^4.0.0:
version "4.0.0"
diff --git a/builder/Makefile b/builder/Makefile
index d3dfe66..f595eb1 100644
--- a/builder/Makefile
+++ b/builder/Makefile
@@ -4,18 +4,25 @@ all: setup build
.ONESHELL:
SHELL:=/bin/bash
+bitmaps_dir = "../bitmaps"
+
X_SIZES ?=22 24 28 32 40 48 56 64 72 80 88 96
WIN_CANVAS_SIZE ?= 32
WIN_SIZE ?= 24
+THEMES = White
+
setup:
@python3 -m pip install clickgen --user
build: setup build.py
- @python3 build.py --xsizes $(X_SIZES) --win-size $(WIN_SIZE) --win-canvas-size $(WIN_CANVAS_SIZE)
+ @python3 build.py -p "$(bitmaps_dir)/macOSBigSur" --xsizes $(X_SIZES) --win-size $(WIN_SIZE) --win-canvas-size $(WIN_CANVAS_SIZE)
+ @$(foreach theme,$(THEMES), python3 build.py -p "$(bitmaps_dir)/macOSBigSur-$(theme)" --xsizes $(X_SIZES) --win-size $(WIN_SIZE) --win-canvas-size $(WIN_CANVAS_SIZE);)
build_unix: setup build.py
- @python3 build.py unix --xsizes $(X_SIZES)
+ @python3 build.py unix -p "$(bitmaps_dir)/macOSBigSur" --xsizes $(X_SIZES)
+ @$(foreach theme,$(THEMES), python3 build.py unix -p "$(bitmaps_dir)/macOSBigSur-$(theme)" --xsizes $(X_SIZES);)
build_windows: setup build.py
- @python3 build.py windows --win-size $(WIN_SIZE) --win-canvas-size $(WIN_CANVAS_SIZE)
+ @python3 build.py windows -p "$(bitmaps_dir)/macOSBigSur" --win-size $(WIN_SIZE) --win-canvas-size $(WIN_CANVAS_SIZE)
+ @$(foreach theme,$(THEMES), python3 build.py windows -p "$(bitmaps_dir)/macOSBigSur-$(theme)" --win-size $(WIN_SIZE) --win-canvas-size $(WIN_CANVAS_SIZE);)
diff --git a/builder/build.py b/builder/build.py
index d6ae0e3..f843558 100644
--- a/builder/build.py
+++ b/builder/build.py
@@ -5,13 +5,14 @@ import argparse
from pathlib import Path
from src.configure import get_config
-from src.generator import build, wbuild, xbuild
+from src.generator import Info, build, wbuild, xbuild
parser = argparse.ArgumentParser(
prog="apple_builder",
description="'macOSBigSur' cursor build python script.",
)
+
# Positional Args.
parser.add_argument(
"platform",
@@ -95,9 +96,10 @@ parser.add_argument(
args = parser.parse_args()
bitmaps_dir = Path(args.png_dir)
+name = bitmaps_dir.stem
-x_out_dir = Path(args.out_dir) / "macOSBigSur"
-win_out_dir = Path(args.out_dir) / "macOSBigSur_Windows"
+x_out_dir = Path(args.out_dir) / name
+win_out_dir = Path(args.out_dir) / f"{name}-Windows"
# Windows Canvas & Cursor sizes
win_size: int = args.win_size
@@ -105,17 +107,20 @@ win_canvas_size: int = args.win_canvas_size
if win_canvas_size < win_size:
win_canvas_size = win_size
+print(f"Getting '{name}' bitmaps ready for build...")
config = get_config(
bitmaps_dir,
x_sizes=args.xsizes,
- win_canvas_size=win_canvas_size,
- win_size=win_size,
+ win_canvas_size=args.win_canvas_size,
+ win_size=args.win_size,
)
+info = Info(name=name, comment=f"{name} Cursors")
+
if args.platform == "unix":
- xbuild(config, x_out_dir)
+ xbuild(config, x_out_dir, info)
elif args.platform == "windows":
- wbuild(config, win_out_dir)
+ wbuild(config, win_out_dir, info)
else:
- build(config, x_out_dir, win_out_dir)
+ build(config, x_out_dir, win_out_dir, info)
diff --git a/builder/src/configure.py b/builder/src/configure.py
index 51e9faf..56fab02 100644
--- a/builder/src/configure.py
+++ b/builder/src/configure.py
@@ -4,7 +4,6 @@
from typing import Any, Dict, Tuple, TypeVar
from clickgen.util import PNGProvider
-
from .constants import WIN_CURSORS_CFG, WIN_DELAY, X_CURSORS_CFG, X_DELAY
X = TypeVar("X")
@@ -15,7 +14,7 @@ def to_tuple(x: X) -> Tuple[X, X]:
def get_config(bitmaps_dir, **kwargs) -> Dict[str, Any]:
- """Return configuration of `GoogleDot` pointers.
+ """Return configuration of `macOSBigSur` pointers.
:param bitmaps_dir: Path to .png file's directory.
:type bitmaps_dir: ``str`` or ``pathlib.Path``
diff --git a/builder/src/constants.py b/builder/src/constants.py
index 47f6d6d..6dabf36 100644
--- a/builder/src/constants.py
+++ b/builder/src/constants.py
@@ -4,8 +4,6 @@
from typing import Dict
# Info
-THEME_NAME = "macOSBigSur"
-COMMENT = "macOS Big Sur Pointers"
AUTHOR = "Kaiz Khatri"
URL = "https://github.com/ful1e5/apple_cursor"
diff --git a/builder/src/generator.py b/builder/src/generator.py
index 19af6e9..772073b 100644
--- a/builder/src/generator.py
+++ b/builder/src/generator.py
@@ -1,31 +1,42 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-"""This module provides build methods for ``macOSBigSur``."""
-
from pathlib import Path
-from typing import Any, Dict
+from typing import Any, Dict, NamedTuple
from clickgen.builders import WindowsCursor, XCursor
from clickgen.core import CursorAlias
from clickgen.packagers import WindowsPackager, XPackager
-
-from .constants import AUTHOR, COMMENT, THEME_NAME, URL
+from .constants import AUTHOR, URL
from .symlinks import add_missing_xcursor
-def xbuild(config: Dict[str, Dict[str, Any]], x_out_dir: Path) -> None:
+class Info(NamedTuple):
+ """Theme basic information.
+
+ :param name: Theme title.
+ :type name: ``str``
+
+ :param comment: quick information about theme.
+ :type comment: ``str``
+ """
+
+ name: str
+ comment: str
+
+
+def xbuild(config: Dict[str, Dict[str, Any]], x_out_dir: Path, info: Info) -> None:
"""Build `macOSBigSur` cursor theme for only `X11`(UNIX) platform.
:param config: `macOSBigSur` configuration.
- :type config: Dict
+ :type config: ``Dict``
:param x_out_dir: Path to the output directory,\
Where the `X11` cursor theme package will generate.\
It also creates a directory if not exists.
- :type x_out_dir: Path
+ :type x_out_dir: ``pathlib.Path``
- :param info: Content theme name & comment
+ :param info: Content theme name & comment.
:type info: Info
"""
@@ -37,21 +48,21 @@ def xbuild(config: Dict[str, Dict[str, Any]], x_out_dir: Path) -> None:
XCursor.create(x_cfg, x_out_dir)
add_missing_xcursor(x_out_dir / "cursors")
- XPackager(x_out_dir, THEME_NAME, COMMENT)
+ XPackager(x_out_dir, info.name, info.comment)
-def wbuild(config: Dict[str, Dict[str, Any]], win_out_dir: Path) -> None:
+def wbuild(config: Dict[str, Dict[str, Any]], win_out_dir: Path, info: Info) -> None:
"""Build `macOSBigSur` cursor theme for only `Windows` platforms.
:param config: `macOSBigSur` configuration.
- :type config: Dict
+ :type config: ``Dict``
:param win_out_dir: Path to the output directory,\
Where the `Windows` cursor theme package will generate.\
It also creates a directory if not exists.
- :type win_out_dir: Path
+ :type win_out_dir: ``pathlib.Path``
- :param info: Content theme name & comment
+ :param info: Content theme name & comment.
:type info: Info
"""
@@ -70,28 +81,28 @@ def wbuild(config: Dict[str, Dict[str, Any]], win_out_dir: Path) -> None:
print(f"Building '{win_cfg.stem}' Windows Cursor...")
WindowsCursor.create(win_cfg, win_out_dir)
- WindowsPackager(win_out_dir, THEME_NAME, COMMENT, AUTHOR, URL)
+ WindowsPackager(win_out_dir, info.name, info.comment, AUTHOR, URL)
def build(
- config: Dict[str, Dict[str, Any]], x_out_dir: Path, win_out_dir: Path
+ config: Dict[str, Dict[str, Any]], x_out_dir: Path, win_out_dir: Path, info: Info
) -> None:
"""Build `macOSBigSur` cursor theme for `X11` & `Windows` platforms.
:param config: `macOSBigSur` configuration.
- :type config: Dict
+ :type config: ``Dict``
:param x_out_dir: Path to the output directory,\
Where the `X11` cursor theme package will generate.\
It also creates a directory if not exists.
- :type x_out_dir: Path
+ :type x_out_dir: ``pathlib.Path``
:param win_out_dir: Path to the output directory,\
Where the `Windows` cursor theme package will generate.\
It also creates a directory if not exists.
- :type win_out_dir: Path
+ :type win_out_dir: ``pathlib.Path``
- :param info: Content theme name & comment
+ :param info: Content theme name & comment.
:type info: Info
"""
@@ -115,6 +126,6 @@ def build(
WindowsCursor.create(win_cfg, win_out_dir)
add_missing_xcursor(x_out_dir / "cursors")
- XPackager(x_out_dir, THEME_NAME, COMMENT)
+ XPackager(x_out_dir, info.name, info.comment)
- WindowsPackager(win_out_dir, THEME_NAME, COMMENT, AUTHOR, URL)
+ WindowsPackager(win_out_dir, info.name, info.comment, AUTHOR, URL)
diff --git a/svg/animated/left_ptr_watch.svg b/svg/animated/left_ptr_watch.svg
index 22bdce0..fdf089a 100644
--- a/svg/animated/left_ptr_watch.svg
+++ b/svg/animated/left_ptr_watch.svg
@@ -9,9 +9,9 @@
-
+
-
+
diff --git a/svg/static/X_cursor.svg b/svg/static/X_cursor.svg
index 69386d0..315a2f4 100644
--- a/svg/static/X_cursor.svg
+++ b/svg/static/X_cursor.svg
@@ -1,13 +1,13 @@