Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
48771f9
fix: ignore result dir
Kasper24 Aug 3, 2025
2590e23
refactor: standardize import paths and export patterns
Kasper24 Aug 3, 2025
94b7fa7
refactor: major refactor of settings, theme generation, and TRPC stru…
Kasper24 Aug 5, 2025
32fac2b
refactor: Implement debounced autosave for inputs
Kasper24 Aug 5, 2025
bee3a76
chore: update nix package npm deps hash
Kasper24 Aug 5, 2025
fa9ebbe
chore: update packges for node-canvas
Kasper24 Aug 5, 2025
0471306
refactor: implement debouncing for the slider componenet
Kasper24 Aug 5, 2025
2de4bf0
refactor: export SettingsSchema and reuse in base16 theme generation
Kasper24 Aug 5, 2025
898ebbf
fix: always show configuration screen when config is missing or empty
Kasper24 Aug 5, 2025
73bb766
fix: update configuration keys for wallpaper sources in library tabs
Kasper24 Aug 5, 2025
bfed3b9
feat: convert theme object to chroma colors before rendering templates
Kasper24 Aug 5, 2025
c031787
refactor: replace slider value display with editable number input
Kasper24 Aug 5, 2025
d7c0b13
refactor: improve type safety for wallpaper grid and API types
Kasper24 Aug 5, 2025
bbde5af
refactor(settings): extract common logic into `useSettings` hook
Kasper24 Aug 5, 2025
114ee8c
chore(ci): rename type check script to `ts:check` for consistency
Kasper24 Aug 5, 2025
846c7b4
chore: update nix npm deps hash
Kasper24 Aug 5, 2025
54853bc
refactor(trpc): restructure routes into index-based folders and updat…
Kasper24 Aug 5, 2025
dff0a88
fix: check `lastWallpaperCmd.command` instead of object
Kasper24 Aug 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,12 @@ jobs:

- name: Lint (ESLint)
run: npm run lint:check
continue-on-error: true

- name: Type check
run: npm run lint:types
continue-on-error: true
run: npm run ts:check

- name: Format check (Prettier)
run: npm run format:check
continue-on-error: true

- name: Package
run: npm run package
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,6 @@ out/
/playwright-report/
/blob-report/
/playwright/.cache/

# Nix
result/
3 changes: 2 additions & 1 deletion forge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ const config: ForgeConfig = {
fs.readFileSync(path.resolve(buildPath, "package.json")).toString()
);
packageJson.dependencies = {
"electron-store": "^10.1.0",
canvas: "^3.1.2",
conf: "^14.0.0",
keytar: "^7.9.0",
};
fs.writeFileSync(path.resolve(buildPath, "package.json"), JSON.stringify(packageJson));
Expand Down
61 changes: 40 additions & 21 deletions package-lock.json

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

13 changes: 9 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "walltone",
"productName": "Walltone",
"productName": "walltone",
"version": " 0.0.1",
"description": "Theme Manager",
"main": ".vite/build/main.js",
Expand All @@ -15,9 +15,9 @@
"scripts": {
"lint-staged": "lint-staged",
"prepare": "husky",
"lint:types": "tsc --noEmit",
"lint:check": "eslint --max-warnings=0",
"lint:fix": "eslint --fix",
"ts:check": "tsc --noEmit",
"format:check": "prettier --check \"**/*.{ts,tsx,js,css,yaml}\"",
"format:write": "prettier --write \"**/*.{ts,tsx,js,css,yaml}\"",
"start": "electron-forge start",
Expand Down Expand Up @@ -85,10 +85,11 @@
"@tailwindcss/vite": "^4.1.11",
"@tanstack/react-query": "^5.84.1",
"@uiw/react-color": "^2.7.3",
"canvas": "^3.1.2",
"chroma.ts": "^1.0.10",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"electron-store": "^10.1.0",
"conf": "^14.0.0",
"electron-trpc-experimental": "^1.0.0-alpha.0",
"keytar": "^7.9.0",
"lucide-react": "^0.536.0",
Expand All @@ -101,7 +102,11 @@
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.6",
"use-debounce": "^10.0.3",
"use-debounce": "^10.0.5",
"uuid": "^11.1.0",
"zod": "^4.0.14"
},
"overrides": {
"@trpc/server": "11.4.4"
}
}
6 changes: 4 additions & 2 deletions packaging/arch/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ pkgdesc="Wallpaper and theme management application"
arch=("x86_64")
url="https://github.com/kasper24/walltone"
license=("GPL3")
depends=("nss" "libsecret" "swaybg" "mpvpaper" "linux-wallpaperengine" "cage" "grim" "wayland-utils")
depends=("nss" "libsecret" "cairo" "pango" "libjpeg-turbo"
"giflib" "libsvgtiny" "swaybg" "mpvpaper"
"linux-wallpaperengine" "cage" "grim" "wayland-utils")
makedepends=("npm" "nodejs" "git")
source=("$pkgname::git+$url.git#branch=dev")
source=("$pkgname::git+$url.git")
sha256sums=("SKIP")

pkgver() {
Expand Down
18 changes: 17 additions & 1 deletion packaging/nix/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
fetchurl,
buildNpmPackage,
libsecret,
pixman,
cairo,
pango,
libjpeg,
libpng,
librsvg,
giflib,
pkg-config,
makeWrapper,
electron-bin,
Expand Down Expand Up @@ -39,7 +46,7 @@ buildNpmPackage rec {

src = ../../.;

npmDepsHash = "sha256-vs5gcGG7jHKu7qs80JFXX1PTr5alMSqjpCclU4+WJYc=";
npmDepsHash = "sha256-VlDOLuyr1qE2zTlXYdzBI1VsAzZMVDfODWyUTaNJCKA";

dontNpmBuild = true;
makeCacheWritable = true;
Expand All @@ -59,6 +66,15 @@ buildNpmPackage rec {

buildInputs = [
libsecret

# Node-Canvas dependencies
pixman
cairo
pango
libjpeg
libpng
librsvg
giflib
];

nativeBuildInputs = [
Expand Down
1 change: 0 additions & 1 deletion result

This file was deleted.

6 changes: 4 additions & 2 deletions src/electron/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { app, BrowserWindow, globalShortcut } from "electron";
import { createIPCHandler } from "electron-trpc-experimental/main";
import { appRouter } from "@electron/main/trpc/routes/base.js";
import { appRouter, caller } from "@electron/main/trpc/routes/index.js";
import { registerProtocols } from "./setup/protocols.js";
import { createTray } from "./setup/tray.js";
import { createWindow } from "./setup/window.js";

let isQuitting = false;

const initializeApp = () => {
const initializeApp = async () => {
const mainWindow = createWindow();
createTray(mainWindow);

createIPCHandler({ router: appRouter, windows: [mainWindow] });

await caller.wallpaper.restoreOnStart();

mainWindow.once("ready-to-show", () => {
mainWindow.show();
});
Expand Down
19 changes: 18 additions & 1 deletion src/electron/main/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { spawn } from "child_process";
import { TRPCError } from "@trpc/server";

const execute = ({
command,
Expand Down Expand Up @@ -72,4 +73,20 @@ const santize = (str: string) => {
return str.replace(/[^a-z0-9-]/gi, "").toLowerCase();
};

export { execute, killProcess, santize };
const renderString = async (content: string, context: Record<string, unknown>) => {
return content.replace(/\$\{([\s\S]+?)\}/g, (_, expr) => {
try {
const fn = new Function(...Object.keys(context), `return (${expr})`);
return fn(...Object.values(context));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Failed to evaluate: ${expr}: ${errorMessage}`,
cause: error,
});
}
});
};

export { execute, killProcess, santize, renderString };
1 change: 1 addition & 0 deletions src/electron/main/setup/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const createWindow = () => {
allowRunningInsecureContent: false,
nodeIntegration: false,
nodeIntegrationInSubFrames: false,
nodeIntegrationInWorker: true,
webSecurity: true,
preload: path.join(import.meta.dirname, "preload.js"),
},
Expand Down
12 changes: 12 additions & 0 deletions src/electron/main/trpc/routes/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { router } from "@electron/main/trpc/index.js";
import { pexelsRouter } from "./pexels/index.js";
import { unsplashRouter } from "./unsplash/index.js";
import { wallhavenRouter } from "./wallhaven/index.js";
import { wallpaperEngineRouter } from "./wallpaper-engine/index.js";

export const apiRouter = router({
pexels: pexelsRouter,
unsplash: unsplashRouter,
wallhaven: wallhavenRouter,
wallpaperEngine: wallpaperEngineRouter,
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { publicProcedure, router } from "@electron/main/trpc/index.js";
import { type DownloadableWallpaper } from "@electron/main/trpc/routes/theme.js";
import { type ApiWallpaper } from "@electron/main/trpc/routes/wallpaper/index.js";

interface PexelsPhoto {
id: number;
Expand Down Expand Up @@ -67,16 +67,17 @@ interface PexelsSearchResponse<T> {
next_page?: string;
}

const transformPhotos = (photos: PexelsPhoto[]): DownloadableWallpaper[] => {
const transformPhotos = (photos: PexelsPhoto[]): ApiWallpaper[] => {
return photos.map((photo) => ({
type: "api",
id: photo.id.toString(),
name: photo.alt || `Photo by ${photo.photographer}`,
previewPath: photo.src.large,
downloadUrl: photo.src.original,
}));
};

const transformVideos = (videos: PexelsVideo[]): DownloadableWallpaper[] => {
const transformVideos = (videos: PexelsVideo[]): ApiWallpaper[] => {
return videos.map((video) => {
// Get the highest quality video file
const bestVideo = video.video_files.reduce((prev, current) => {
Expand All @@ -86,6 +87,7 @@ const transformVideos = (videos: PexelsVideo[]): DownloadableWallpaper[] => {
});

return {
type: "api",
id: video.id.toString(),
name: `Video by ${video.user.name}`,
previewPath: video.image,
Expand Down Expand Up @@ -152,7 +154,7 @@ export const pexelsRouter = router({
const data: PexelsSearchResponse<PexelsPhoto | PexelsVideo> = await response.json();
const numberOfPages = Math.ceil(data.total_results / (input.perPage || 30));

let transformedData: DownloadableWallpaper[] = [];
let transformedData: ApiWallpaper[] = [];
if (input.type === "photos" && data.photos) {
transformedData = transformPhotos(data.photos as PexelsPhoto[]);
} else if (input.type === "videos" && data.videos) {
Expand All @@ -164,7 +166,7 @@ export const pexelsRouter = router({
currentPage: data.page,
prevPage: data.page > 1 ? data.page - 1 : null,
nextPage: data.page < numberOfPages ? data.page + 1 : null,
total: data.total_results,
totalItems: data.total_results,
totalPages: numberOfPages,
};
} catch (error) {
Expand Down
Loading
Loading