+ return (
{windows?.map((window: WindowProps) => {
const { id, app, size, position, options, minimized, fullscreen } = window;
const index = sortedWindows.indexOf(window);
diff --git a/packages/core/src/constants/branding.const.ts b/packages/core/src/constants/branding.const.ts
new file mode 100644
index 0000000..320962e
--- /dev/null
+++ b/packages/core/src/constants/branding.const.ts
@@ -0,0 +1 @@
+export const NAME = "ProzillaOS";
\ No newline at end of file
diff --git a/packages/core/src/features/system/configs/app.tsx b/packages/core/src/features/apps/app.tsx
similarity index 96%
rename from packages/core/src/features/system/configs/app.tsx
rename to packages/core/src/features/apps/app.tsx
index 1f4c9f1..436fc8b 100644
--- a/packages/core/src/features/system/configs/app.tsx
+++ b/packages/core/src/features/apps/app.tsx
@@ -1,5 +1,5 @@
-import { Vector2 } from "../../math/vector2";
-import { WindowProps } from "../../../components/windows/WindowView";
+import { WindowProps } from "../../components";
+import { Vector2 } from "../";
import { FC } from "react";
const validIdRegex = /^[a-zA-Z0-9-]+$/;
diff --git a/packages/core/src/features/index.ts b/packages/core/src/features/index.ts
index 2ad8a1f..c0d2bf0 100644
--- a/packages/core/src/features/index.ts
+++ b/packages/core/src/features/index.ts
@@ -2,6 +2,7 @@ export * from "./system/configs";
export * from "./virtual-drive";
export * from "./_utils";
+export { App } from "./apps/app";
export { ModalsManager } from "./modals/modalsManager";
export { SettingsManager } from "./settings/settingsManager";
export { StorageManager } from "./storage/storageManager";
diff --git a/packages/core/src/features/system/configs/appsConfig.ts b/packages/core/src/features/system/configs/appsConfig.ts
index 48b0358..f990f81 100644
--- a/packages/core/src/features/system/configs/appsConfig.ts
+++ b/packages/core/src/features/system/configs/appsConfig.ts
@@ -1,4 +1,4 @@
-import { App } from ".";
+import { App } from "../../";
import { OptionalInterface } from "../../../types/utils";
export interface AppsConfigOptions {
diff --git a/packages/core/src/features/system/configs/index.ts b/packages/core/src/features/system/configs/index.ts
index 765b33b..a8ab39c 100644
--- a/packages/core/src/features/system/configs/index.ts
+++ b/packages/core/src/features/system/configs/index.ts
@@ -1,4 +1,3 @@
-export { App } from "./app";
export { AppsConfig } from "./appsConfig";
export { DesktopConfig } from "./desktopConfig";
export { MiscConfig } from "./miscConfig";
diff --git a/packages/core/src/features/system/systemManager.ts b/packages/core/src/features/system/systemManager.ts
index 1e3b623..eb1dcf0 100644
--- a/packages/core/src/features/system/systemManager.ts
+++ b/packages/core/src/features/system/systemManager.ts
@@ -1,4 +1,5 @@
import { formatRelativeTime } from "../_utils";
+import { Skin } from "@prozilla-os/skins";
import { VirtualDriveConfig } from "./configs";
import { AppsConfig } from "./configs/appsConfig";
import { DesktopConfig } from "./configs/desktopConfig";
@@ -11,6 +12,9 @@ import { WindowsConfig } from "./configs/windowsConfig";
export interface SystemManagerParams {
systemName: SystemManager["systemName"] | null;
tagLine: SystemManager["tagLine"] | null;
+
+ skin?: SystemManager["skin"];
+
desktopConfig: DesktopConfig;
appsConfig: AppsConfig;
miscConfig: MiscConfig;
@@ -26,6 +30,8 @@ export class SystemManager {
tagLine: string;
#startDate: Date;
+ skin?: Skin;
+
appsConfig: AppsConfig;
desktopConfig: DesktopConfig;
miscConfig: MiscConfig;
@@ -38,6 +44,7 @@ export class SystemManager {
constructor({
systemName,
tagLine,
+ skin,
desktopConfig,
appsConfig,
miscConfig,
@@ -50,6 +57,8 @@ export class SystemManager {
this.systemName = systemName ?? "ProzillaOS";
this.tagLine = tagLine ?? "Web-based Operating System";
+ this.skin = skin;
+
this.desktopConfig = desktopConfig;
this.appsConfig = appsConfig;
this.miscConfig = miscConfig;
@@ -59,6 +68,42 @@ export class SystemManager {
this.windowsConfig = windowsConfig;
this.virtualDriveConfig = virtualDriveConfig;
+ if (this.skin != null) {
+ const skin = this.skin;
+
+ if (skin.appIcons != null) {
+ const appIcons = skin.appIcons as { [key: string]: string };
+
+ this.appsConfig.apps.forEach((app) => {
+ if (Object.keys(appIcons).includes(app.id))
+ app.setIconUrl(appIcons[app.id]);
+ });
+ }
+
+ if (skin.wallpapers != null)
+ this.desktopConfig.wallpapers = this.desktopConfig.wallpapers.concat(skin.wallpapers);
+
+ if (skin.defaultWallpaper != null)
+ this.desktopConfig.defaultWallpaper = skin.defaultWallpaper;
+
+ if (skin.fileIcons != null) {
+ this.virtualDriveConfig.fileIcon = skin.fileIcons.generic;
+ this.virtualDriveConfig.infoFileIcon = skin.fileIcons.info ?? skin.fileIcons.generic;
+ this.virtualDriveConfig.textFileIcon = skin.fileIcons.text ?? skin.fileIcons.generic;
+ this.virtualDriveConfig.codeFileIcon = skin.fileIcons.code ?? skin.fileIcons.generic;
+ }
+
+ if (skin.folderIcons != null) {
+ this.virtualDriveConfig.folderIcon = skin.folderIcons.generic;
+ this.virtualDriveConfig.textFolderIcon = skin.folderIcons.text ?? skin.folderIcons.generic;
+ this.virtualDriveConfig.imagesFolderIcon = skin.folderIcons.images ?? skin.folderIcons.generic;
+ this.virtualDriveConfig.folderLinkIcon = skin.folderIcons.link ?? skin.folderIcons.generic;
+ }
+
+ if (skin.loadStyleSheet != null)
+ skin.loadStyleSheet();
+ }
+
this.#startDate = new Date();
}
diff --git a/packages/core/src/features/windows/windowsManager.ts b/packages/core/src/features/windows/windowsManager.ts
index 6262cb4..dfcd16f 100644
--- a/packages/core/src/features/windows/windowsManager.ts
+++ b/packages/core/src/features/windows/windowsManager.ts
@@ -1,5 +1,5 @@
import { randomRange } from "../_utils/math.utils";
-import { App } from "../system/configs/app";
+import { App } from "../";
import { Vector2 } from "../math/vector2";
import { SystemManager } from "../system/systemManager";
import { TrackingManager } from "../tracking/trackingManager";
diff --git a/packages/core/src/hooks/_utils/classNames.ts b/packages/core/src/hooks/_utils/classNames.ts
new file mode 100644
index 0000000..9ca2e3e
--- /dev/null
+++ b/packages/core/src/hooks/_utils/classNames.ts
@@ -0,0 +1,39 @@
+import { useMemo } from "react";
+import { NAME } from "../../constants/branding.const";
+
+/**
+ * Generates static class name using BEM notation
+ */
+export function useStaticClassName(block?: string, element?: string, modifier?: string) {
+ return useMemo(() => {
+ if (block == null)
+ return null;
+
+ let className = `${NAME}-${block}`;
+
+ if (element != null)
+ className += `_${element}`;
+ if (modifier != null)
+ className += `--${modifier}`;
+
+ return className;
+ }, [block, element, modifier]);
+}
+
+/**
+ * Combine clas names and an optional static class name
+ */
+export function useClassNames(classNames: (string | undefined)[], block?: string, element?: string, modifier?: string) {
+ const staticClassName = useStaticClassName(block, element, modifier);
+
+ return useMemo(() => {
+ const resultClassNames = [...classNames];
+
+ resultClassNames.filter((className) => className != null);
+
+ if (staticClassName != null)
+ resultClassNames.unshift(staticClassName);
+
+ return resultClassNames.join(" ");
+ }, [classNames, staticClassName]);
+}
\ No newline at end of file
diff --git a/packages/core/src/hooks/_utils/index.ts b/packages/core/src/hooks/_utils/index.ts
index a878e64..0460d7d 100644
--- a/packages/core/src/hooks/_utils/index.ts
+++ b/packages/core/src/hooks/_utils/index.ts
@@ -3,4 +3,5 @@ export { useKeyboardListener, useShortcuts } from "./keyboard";
export { useMouseListener } from "./mouse";
export { OutsideClickListener } from "./outsideClick";
export { useScreenBounds, useScreenDimensions } from "./screen";
-export { useScrollWithShadow } from "./scrollWithShadows";
\ No newline at end of file
+export { useScrollWithShadow } from "./scrollWithShadows";
+export { useClassNames, useStaticClassName } from "./classNames";
\ No newline at end of file
diff --git a/packages/core/src/hooks/apps/appFolder.ts b/packages/core/src/hooks/apps/appFolder.ts
index 305aeff..88aaf21 100644
--- a/packages/core/src/hooks/apps/appFolder.ts
+++ b/packages/core/src/hooks/apps/appFolder.ts
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
-import { App } from "../../features/system/configs/app";
+import { App } from "../../features/";
import { VirtualFolder } from "../../features/virtual-drive/folder";
import { useVirtualRoot } from "../virtual-drive/virtualRootContext";
diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts
index 97392d7..6faa96d 100644
--- a/packages/core/vite.config.ts
+++ b/packages/core/vite.config.ts
@@ -11,9 +11,11 @@ export default defineConfig({
libInjectCss(),
dts({
include: ["src"],
- outDir: "dist",
+ outDir: "./dist",
rollupTypes: true,
- strictOutput: true
+ strictOutput: true,
+ pathsToAliases: false,
+ bundledPackages: ["@prozilla-os/*"]
})
],
build: {
@@ -22,12 +24,12 @@ export default defineConfig({
formats: ["es"],
},
rollupOptions: {
- external: ["react", "react/jsx-runtime"],
+ external: ["react", "react/jsx-runtime", /@prozilla-os/],
output: {
assetFileNames: "assets/[name][extname]",
entryFileNames: "[name].js",
}
},
- sourcemap: true
- }
+ sourcemap: true,
+ },
});
\ No newline at end of file
diff --git a/packages/demo/package.json b/packages/demo/package.json
index 4442121..0c31df0 100644
--- a/packages/demo/package.json
+++ b/packages/demo/package.json
@@ -10,7 +10,7 @@
"type": "module",
"scripts": {
"start": "vite",
- "build": "tsc && vite build",
+ "build": "tsc --project tsconfig-build.json && vite build",
"preview": "vite preview --port 8080",
"stage": "vite-node scripts/stage",
"predeploy": "pnpm run build && pnpm run stage",
@@ -27,6 +27,7 @@
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@prozilla-os/logic-sim": "workspace:*",
+ "@prozilla-os/skins": "workspace:*",
"prozilla-os": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/packages/demo/public/assets/skins/mac/apps/file-explorer/file.svg b/packages/demo/public/assets/skins/mac/apps/file-explorer/file.svg
new file mode 100644
index 0000000..9df7cba
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/file-explorer/file.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/file-explorer/folder.svg b/packages/demo/public/assets/skins/mac/apps/file-explorer/folder.svg
new file mode 100644
index 0000000..357ce34
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/file-explorer/folder.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/ball-maze.svg b/packages/demo/public/assets/skins/mac/apps/icons/ball-maze.svg
new file mode 100644
index 0000000..41ad2e2
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/ball-maze.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/browser.svg b/packages/demo/public/assets/skins/mac/apps/icons/browser.svg
new file mode 100644
index 0000000..40c667f
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/browser.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/calculator.svg b/packages/demo/public/assets/skins/mac/apps/icons/calculator.svg
new file mode 100644
index 0000000..74e87ac
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/calculator.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/file-explorer.svg b/packages/demo/public/assets/skins/mac/apps/icons/file-explorer.svg
new file mode 100644
index 0000000..7999c09
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/file-explorer.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/media-viewer.svg b/packages/demo/public/assets/skins/mac/apps/icons/media-viewer.svg
new file mode 100644
index 0000000..2a91607
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/media-viewer.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/minesweeper.svg b/packages/demo/public/assets/skins/mac/apps/icons/minesweeper.svg
new file mode 100644
index 0000000..71e5296
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/minesweeper.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/settings.svg b/packages/demo/public/assets/skins/mac/apps/icons/settings.svg
new file mode 100644
index 0000000..b704c3e
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/settings.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/terminal.svg b/packages/demo/public/assets/skins/mac/apps/icons/terminal.svg
new file mode 100644
index 0000000..060287c
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/terminal.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/text-editor.svg b/packages/demo/public/assets/skins/mac/apps/icons/text-editor.svg
new file mode 100644
index 0000000..511eef5
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/text-editor.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/apps/icons/wordle.svg b/packages/demo/public/assets/skins/mac/apps/icons/wordle.svg
new file mode 100644
index 0000000..e869146
--- /dev/null
+++ b/packages/demo/public/assets/skins/mac/apps/icons/wordle.svg
@@ -0,0 +1,14 @@
+
diff --git a/packages/demo/public/assets/skins/mac/wallpapers/macos-monterey.jpg b/packages/demo/public/assets/skins/mac/wallpapers/macos-monterey.jpg
new file mode 100644
index 0000000..5e6ecd8
Binary files /dev/null and b/packages/demo/public/assets/skins/mac/wallpapers/macos-monterey.jpg differ
diff --git a/packages/demo/public/assets/skins/minimal/apps/file-explorer/file.svg b/packages/demo/public/assets/skins/minimal/apps/file-explorer/file.svg
new file mode 100644
index 0000000..935da21
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/file-explorer/file.svg
@@ -0,0 +1,10 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/file-explorer/folder.svg b/packages/demo/public/assets/skins/minimal/apps/file-explorer/folder.svg
new file mode 100644
index 0000000..d828a2f
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/file-explorer/folder.svg
@@ -0,0 +1,10 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/browser.svg b/packages/demo/public/assets/skins/minimal/apps/icons/browser.svg
new file mode 100644
index 0000000..e69fcf3
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/browser.svg
@@ -0,0 +1,10 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/calculator.svg b/packages/demo/public/assets/skins/minimal/apps/icons/calculator.svg
new file mode 100644
index 0000000..82e4aee
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/calculator.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/file-explorer.svg b/packages/demo/public/assets/skins/minimal/apps/icons/file-explorer.svg
new file mode 100644
index 0000000..aaa625e
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/file-explorer.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/media-viewer.svg b/packages/demo/public/assets/skins/minimal/apps/icons/media-viewer.svg
new file mode 100644
index 0000000..18d93aa
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/media-viewer.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/settings.svg b/packages/demo/public/assets/skins/minimal/apps/icons/settings.svg
new file mode 100644
index 0000000..b200562
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/settings.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/terminal.svg b/packages/demo/public/assets/skins/minimal/apps/icons/terminal.svg
new file mode 100644
index 0000000..e992c76
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/terminal.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/demo/public/assets/skins/minimal/apps/icons/text-editor.svg b/packages/demo/public/assets/skins/minimal/apps/icons/text-editor.svg
new file mode 100644
index 0000000..44bc4f3
--- /dev/null
+++ b/packages/demo/public/assets/skins/minimal/apps/icons/text-editor.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/demo/public/assets/skins/windows/apps/icons/file-explorer.webp b/packages/demo/public/assets/skins/windows/apps/icons/file-explorer.webp
new file mode 100644
index 0000000..661dca3
Binary files /dev/null and b/packages/demo/public/assets/skins/windows/apps/icons/file-explorer.webp differ
diff --git a/packages/demo/public/assets/skins/windows/wallpapers/windows-10.webp b/packages/demo/public/assets/skins/windows/wallpapers/windows-10.webp
new file mode 100644
index 0000000..6cc77b5
Binary files /dev/null and b/packages/demo/public/assets/skins/windows/wallpapers/windows-10.webp differ
diff --git a/packages/demo/src/Main.tsx b/packages/demo/src/Main.tsx
index 343c646..b7c4e7a 100644
--- a/packages/demo/src/Main.tsx
+++ b/packages/demo/src/Main.tsx
@@ -5,11 +5,13 @@ import { NAME, TAG_LINE } from "./config/branding.config";
import { appsConfig } from "./config/apps.config";
import { virtualDriveConfig } from "./config/virtualDrive.config";
import { ProzillaOS } from "prozilla-os";
+import { macOsSkin } from "@prozilla-os/skins";
export function Main(): ReactElement {
return
+
+
+
+
+
+
+
+
+
+
+
+
+## About
+
+`@prozilla-os/skins` is a React library that contains skins for ProzillaOS.
+
+## Installation
+
+```sh
+$ npm install @prozilla-os/skins
+$ yarn add @prozilla-os/skins
+$ pnpm add @prozilla-os/skins
+```
+
+## Links
+
+- [Website/demo][website]
+- [GitHub][github]
+- [npm][npm]
+- [Discord][discord]
+- [Ko-fi][ko-fi]
+
+[website]: https://os.prozilla.dev/
+[github]: https://github.com/prozilla-os/ProzillaOS/tree/main/packages/skins
+[npm]: https://www.npmjs.com/package/@prozilla-os/skins
+[discord]: https://discord.gg/JwbyQP4tdz
+[ko-fi]: https://ko-fi.com/prozilla
\ No newline at end of file
diff --git a/packages/skins/package.json b/packages/skins/package.json
new file mode 100644
index 0000000..59c97ff
--- /dev/null
+++ b/packages/skins/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@prozilla-os/skins",
+ "description": "A React library that contains skins for ProzillaOS.",
+ "version": "1.0.0",
+ "homepage": "https://os.prozilla.dev",
+ "author": {
+ "name": "Prozilla",
+ "email": "business@prozilla.dev",
+ "url": "https://prozilla.dev/"
+ },
+ "type": "module",
+ "main": "dist/main.js",
+ "types": "dist/main.d.ts",
+ "scripts": {
+ "build": "tsc && vite build"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/prozilla-os/ProzillaOS.git",
+ "directory": "packages/skins"
+ },
+ "license": "MIT",
+ "devDependencies": {
+ "@types/react": "^18.3.3",
+ "@vitejs/plugin-react-swc": "^3.7.0",
+ "glob": "^11.0.0",
+ "typescript": "^5.4.5",
+ "vite": "^5.3.1",
+ "vite-plugin-dts": "^3.9.1",
+ "vite-plugin-lib-inject-css": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ },
+ "files": [
+ "dist"
+ ],
+ "sideEffects": [
+ "**/*.css"
+ ],
+ "publishConfig": {
+ "registry": "https://registry.npmjs.org/",
+ "access": "public"
+ }
+}
diff --git a/packages/skins/src/core/index.ts b/packages/skins/src/core/index.ts
new file mode 100644
index 0000000..525e483
--- /dev/null
+++ b/packages/skins/src/core/index.ts
@@ -0,0 +1,3 @@
+export { Skin } from "./skin";
+export { macOsSkin } from "./skins/macOs";
+export { minimalSkin } from "./skins/minimal";
\ No newline at end of file
diff --git a/packages/skins/src/core/skin.ts b/packages/skins/src/core/skin.ts
new file mode 100644
index 0000000..145c9c4
--- /dev/null
+++ b/packages/skins/src/core/skin.ts
@@ -0,0 +1,40 @@
+interface SkinOptions {
+ appIcons?: { [key: string]: string };
+
+ wallpapers?: string[];
+ defaultWallpaper?: string;
+
+ fileIcons?: {
+ generic: string;
+ info?: string;
+ text?: string;
+ code?: string;
+ };
+
+ folderIcons?: {
+ generic: string;
+ images?: string;
+ text?: string;
+ link?: string;
+ };
+
+ loadStyleSheet?: () => void;
+}
+
+export class Skin {
+ appIcons: SkinOptions["appIcons"];
+ wallpapers: SkinOptions["wallpapers"];
+ defaultWallpaper: SkinOptions["defaultWallpaper"];
+ fileIcons: SkinOptions["fileIcons"];
+ folderIcons: SkinOptions["folderIcons"];
+ loadStyleSheet: SkinOptions["loadStyleSheet"];
+
+ constructor(options: SkinOptions) {
+ this.appIcons = options.appIcons;
+ this.wallpapers = options.wallpapers;
+ this.defaultWallpaper = options.defaultWallpaper;
+ this.fileIcons = options.fileIcons;
+ this.folderIcons = options.folderIcons;
+ this.loadStyleSheet = options.loadStyleSheet;
+ }
+}
\ No newline at end of file
diff --git a/packages/skins/src/core/skins/macOs.ts b/packages/skins/src/core/skins/macOs.ts
new file mode 100644
index 0000000..dbf9b42
--- /dev/null
+++ b/packages/skins/src/core/skins/macOs.ts
@@ -0,0 +1,29 @@
+import { Skin } from "../skin";
+
+export const macOsSkin = new Skin({
+ appIcons: {
+ "ball-maze": "/assets/skins/mac/apps/icons/ball-maze.svg",
+ "browser": "/assets/skins/mac/apps/icons/browser.svg",
+ "calculator": "/assets/skins/mac/apps/icons/calculator.svg",
+ "file-explorer": "/assets/skins/mac/apps/icons/file-explorer.svg",
+ "media-viewer": "/assets/skins/mac/apps/icons/media-viewer.svg",
+ "minesweeper": "/assets/skins/mac/apps/icons/minesweeper.svg",
+ "settings": "/assets/skins/mac/apps/icons/settings.svg",
+ "terminal": "/assets/skins/mac/apps/icons/terminal.svg",
+ "text-editor": "/assets/skins/mac/apps/icons/text-editor.svg",
+ "wordle": "/assets/skins/mac/apps/icons/wordle.svg",
+ },
+ wallpapers: [
+ "/assets/skins/mac/wallpapers/macos-monterey.jpg"
+ ],
+ defaultWallpaper: "/assets/skins/mac/wallpapers/macos-monterey.jpg",
+ fileIcons: {
+ generic: "/assets/skins/mac/apps/file-explorer/file.svg"
+ },
+ folderIcons: {
+ generic: "/assets/skins/mac/apps/file-explorer/folder.svg"
+ },
+ loadStyleSheet: () => {
+ import("../../styles/skins/macOs.css");
+ }
+});
\ No newline at end of file
diff --git a/packages/skins/src/core/skins/minimal.ts b/packages/skins/src/core/skins/minimal.ts
new file mode 100644
index 0000000..6aac0e4
--- /dev/null
+++ b/packages/skins/src/core/skins/minimal.ts
@@ -0,0 +1,26 @@
+import { Skin } from "../skin";
+
+export const minimalSkin = new Skin({
+ appIcons: {
+ "browser": "/assets/skins/minimal/apps/icons/browser.svg",
+ "calculator": "/assets/skins/minimal/apps/icons/calculator.svg",
+ "file-explorer": "/assets/skins/minimal/apps/icons/file-explorer.svg",
+ "media-viewer": "/assets/skins/minimal/apps/icons/media-viewer.svg",
+ "settings": "/assets/skins/minimal/apps/icons/settings.svg",
+ "terminal": "/assets/skins/minimal/apps/icons/terminal.svg",
+ "text-editor": "/assets/skins/minimal/apps/icons/text-editor.svg",
+ },
+ wallpapers: [
+ "/assets/wallpapers/abstract-wallpaper-mesh-gradient-cyan.png"
+ ],
+ defaultWallpaper: "/assets/wallpapers/abstract-wallpaper-mesh-gradient-cyan.png",
+ fileIcons: {
+ generic: "/assets/skins/minimal/apps/file-explorer/file.svg"
+ },
+ folderIcons: {
+ generic: "/assets/skins/minimal/apps/file-explorer/folder.svg"
+ },
+ loadStyleSheet: () => {
+ import("../../styles/skins/minimal.css");
+ }
+});
\ No newline at end of file
diff --git a/packages/skins/src/main.ts b/packages/skins/src/main.ts
new file mode 100644
index 0000000..d964fba
--- /dev/null
+++ b/packages/skins/src/main.ts
@@ -0,0 +1 @@
+export { Skin, macOsSkin, minimalSkin } from "./core";
\ No newline at end of file
diff --git a/packages/skins/src/styles/skins/macOs.css b/packages/skins/src/styles/skins/macOs.css
new file mode 100644
index 0000000..a250387
--- /dev/null
+++ b/packages/skins/src/styles/skins/macOs.css
@@ -0,0 +1,114 @@
+:root {
+ --util-menu-height: 2rem;
+ --taskbar-margin: 0.5rem;
+}
+
+.ProzillaOS-Taskbar {
+ --taskbar-opacity: 0.1;
+
+ height: 100%;
+ pointer-events: none;
+}
+
+.ProzillaOS-Taskbar::before, .ProzillaOS-Taskbar::after {
+ display: none;
+}
+
+.ProzillaOS-Taskbar_MenuIcons {
+ display: none;
+}
+
+.ProzillaOS-Taskbar_AppIcons {
+ position: absolute;
+ bottom: var(--taskbar-margin);
+ left: 50%;
+ width: auto;
+ height: auto;
+ min-height: var(--taskbar-height);
+ transform: translateX(-50%);
+ border-radius: var(--border-radius-1);
+ transition: height 200ms ease-out 100ms;
+ pointer-events: auto;
+}
+
+.ProzillaOS-Taskbar_AppIcons:has(.ProzillaOS-Taskbar_AppIcon:hover) {
+ animation: expand 200ms ease-out forwards;
+}
+
+@keyframes expand {
+ 0% {
+ height: var(--taskbar-height);
+ }
+ 100% {
+ height: calc(var(--taskbar-height) * 150%);
+ }
+}
+
+.ProzillaOS-Taskbar_AppIcons::after,
+.ProzillaOS-Taskbar_AppIcons::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ pointer-events: none;
+}
+
+.ProzillaOS-Taskbar_AppIcons::after {
+ opacity: var(--taskbar-opacity);
+ background-color: var(--foreground-color-0);
+ z-index: -2;
+}
+
+.ProzillaOS-Taskbar_AppIcons::before {
+ backdrop-filter: var(--taskbar-filter);
+ z-index: -3;
+}
+
+.ProzillaOS-Taskbar_AppIcons > div {
+ position: relative;
+ width: auto;
+ height: 100%;
+ align-items: flex-end;
+}
+
+.ProzillaOS-Taskbar_AppIcon {
+ --scale: var(--taskbar-height);
+ width: var(--scale);
+ height: var(--scale);
+ padding: 0.5rem;
+ transition: width 200ms ease-out, height 200ms ease-out, background-color 100ms ease-in-out !important;
+}
+
+.ProzillaOS-Taskbar_AppIcon svg {
+ transform: none !important;
+}
+
+.ProzillaOS-Taskbar_AppIcon:hover {
+ --scale: calc(var(--taskbar-height) * 1.5);
+}
+
+.ProzillaOS-Taskbar_UtilIcons {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: var(--util-menu-height);
+ background-color: var(--taskbar-color);
+ box-shadow: 0.1rem 0.1rem 0.2rem 0.1rem color-mix(in srgb, var(--svg-drop-shadow-color) 50%, transparent);
+ pointer-events: auto;
+}
+
+.ProzillaOS-Taskbar_UtilIcons button {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.ProzillaOS-Taskbar_UtilIcons button br {
+ display: none;
+}
+
+.ProzillaOS-Desktop .ProzillaOS-DirectoryList {
+ margin-top: var(--util-menu-height);
+}
\ No newline at end of file
diff --git a/packages/skins/src/styles/skins/minimal.css b/packages/skins/src/styles/skins/minimal.css
new file mode 100644
index 0000000..e69de29
diff --git a/packages/skins/src/types/vite-env.d.ts b/packages/skins/src/types/vite-env.d.ts
new file mode 100644
index 0000000..151aa68
--- /dev/null
+++ b/packages/skins/src/types/vite-env.d.ts
@@ -0,0 +1 @@
+///
\ No newline at end of file
diff --git a/packages/skins/tsconfig.json b/packages/skins/tsconfig.json
new file mode 100644
index 0000000..dc6269e
--- /dev/null
+++ b/packages/skins/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "../..",
+ "composite": true,
+ "outDir": "dist",
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "noEmit": false
+ },
+ "include": ["src", "vite.config.ts"],
+ "exclude": ["node_modules"]
+}
\ No newline at end of file
diff --git a/packages/skins/vite.config.ts b/packages/skins/vite.config.ts
new file mode 100644
index 0000000..1c25e42
--- /dev/null
+++ b/packages/skins/vite.config.ts
@@ -0,0 +1,60 @@
+import { defineConfig } from "vite";
+import { resolve } from "path";
+import react from "@vitejs/plugin-react-swc";
+import dts from "vite-plugin-dts";
+import { libInjectCss } from "vite-plugin-lib-inject-css";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ react(),
+ dts({
+ include: ["src"],
+ outDir: "./dist",
+ rollupTypes: true,
+ strictOutput: true
+ }),
+ libInjectCss(),
+ ],
+ build: {
+ lib: {
+ entry: resolve(__dirname, "src/main.ts"),
+ formats: ["es"],
+ },
+ rollupOptions: {
+ external: ["react", "react/jsx-runtime"],
+ output: {
+ assetFileNames: "assets/[name][extname]",
+ entryFileNames: "[name].js",
+ chunkFileNames: "[name]-[hash].js",
+ manualChunks: undefined
+ },
+ plugins: [{
+ name: "test",
+ resolveId (source) {
+ if (source.endsWith(".css")) {
+ return source;
+ }
+ return null;
+ },
+ renderDynamicImport(options) {
+ const { targetModuleId } = options;
+ if (targetModuleId?.endsWith(".css")) {
+ const matches = targetModuleId.match(/(?<=\/)[a-zA-Z-]+(?=\.css$)/);
+
+ if (matches == null)
+ return;
+
+ const name = matches[0];
+ return {
+ left: "import(/*",
+ right: `*/"./assets/${name}.css")`
+ };
+ }
+ return null;
+ },
+ }]
+ },
+ sourcemap: true,
+ },
+});
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5867b15..1dab79c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -383,6 +383,9 @@ importers:
'@fortawesome/react-fontawesome':
specifier: ^0.2.2
version: 0.2.2(@fortawesome/fontawesome-svg-core@6.5.2)(react@18.3.1)
+ '@prozilla-os/skins':
+ specifier: workspace:*
+ version: link:../skins
react:
specifier: ^18.3.1
version: 18.3.1
@@ -408,6 +411,9 @@ importers:
'@vitejs/plugin-react-swc':
specifier: ^3.7.0
version: 3.7.0(vite@5.3.1(@types/node@20.14.10)(less@4.2.0))
+ glob:
+ specifier: ^11.0.0
+ version: 11.0.0
typescript:
specifier: ^5.4.5
version: 5.4.5
@@ -435,6 +441,9 @@ importers:
'@prozilla-os/logic-sim':
specifier: workspace:*
version: link:../apps/logic-sim
+ '@prozilla-os/skins':
+ specifier: workspace:*
+ version: link:../skins
prozilla-os:
specifier: workspace:*
version: link:../prozilla-os
@@ -615,6 +624,34 @@ importers:
specifier: ^2.1.1
version: 2.1.1(vite@5.3.1(@types/node@20.14.10)(less@4.2.0))
+ packages/skins:
+ dependencies:
+ react:
+ specifier: ^18.3.1
+ version: 18.3.1
+ devDependencies:
+ '@types/react':
+ specifier: ^18.3.3
+ version: 18.3.3
+ '@vitejs/plugin-react-swc':
+ specifier: ^3.7.0
+ version: 3.7.0(vite@5.3.1(@types/node@20.14.10)(less@4.2.0))
+ glob:
+ specifier: ^11.0.0
+ version: 11.0.0
+ typescript:
+ specifier: ^5.4.5
+ version: 5.4.5
+ vite:
+ specifier: ^5.3.1
+ version: 5.3.1(@types/node@20.14.10)(less@4.2.0)
+ vite-plugin-dts:
+ specifier: ^3.9.1
+ version: 3.9.1(@types/node@20.14.10)(rollup@4.18.0)(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.10)(less@4.2.0))
+ vite-plugin-lib-inject-css:
+ specifier: ^2.1.1
+ version: 2.1.1(vite@5.3.1(@types/node@20.14.10)(less@4.2.0))
+
packages:
'@algolia/autocomplete-core@1.9.3':
@@ -2418,6 +2455,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ glob@11.0.0:
+ resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==}
+ engines: {node: 20 || >=22}
+ hasBin: true
+
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
@@ -2731,6 +2773,10 @@ packages:
resolution: {integrity: sha512-U23pQPDnmYybVkYjObcuYMk43VRlMLLqLI+RdZy8s8WV8WsxO9SnqSroKaluuvcNOdCAlauKszDwd+umbot5Mg==}
engines: {node: '>=18'}
+ jackspeak@4.0.1:
+ resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==}
+ engines: {node: 20 || >=22}
+
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
@@ -2853,6 +2899,10 @@ packages:
resolution: {integrity: sha512-9/8QXrtbGeMB6LxwQd4x1tIMnsmUxMvIH/qWGsccz6bt9Uln3S+sgAaqfQNhbGA8ufzs2fHuP/yqapGgP9Hh2g==}
engines: {node: '>=18'}
+ lru-cache@11.0.0:
+ resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==}
+ engines: {node: 20 || >=22}
+
lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
@@ -2922,6 +2972,10 @@ packages:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
+ minimatch@10.0.1:
+ resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
+ engines: {node: 20 || >=22}
+
minimatch@3.0.8:
resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==}
@@ -3099,6 +3153,10 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
+ path-scurry@2.0.0:
+ resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==}
+ engines: {node: 20 || >=22}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -6087,6 +6145,15 @@ snapshots:
package-json-from-dist: 1.0.0
path-scurry: 1.11.1
+ glob@11.0.0:
+ dependencies:
+ foreground-child: 3.2.1
+ jackspeak: 4.0.1
+ minimatch: 10.0.1
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.0
+ path-scurry: 2.0.0
+
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -6376,6 +6443,12 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
+ jackspeak@4.0.1:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
jju@1.4.0: {}
js-tokens@4.0.0: {}
@@ -6496,6 +6569,8 @@ snapshots:
lru-cache@10.3.1: {}
+ lru-cache@11.0.0: {}
+
lru-cache@4.1.5:
dependencies:
pseudomap: 1.0.2
@@ -6565,6 +6640,10 @@ snapshots:
min-indent@1.0.1: {}
+ minimatch@10.0.1:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@3.0.8:
dependencies:
brace-expansion: 1.1.11
@@ -6744,6 +6823,11 @@ snapshots:
lru-cache: 10.3.1
minipass: 7.1.2
+ path-scurry@2.0.0:
+ dependencies:
+ lru-cache: 11.0.0
+ minipass: 7.1.2
+
path-type@4.0.0: {}
pathe@1.1.2: {}
diff --git a/tsconfig.json b/tsconfig.json
index 64e1094..e02ad6e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,6 +17,7 @@
/* Emit */
"noEmit": true,
+ "noEmitOnError": true,
/* Interop Constraints */
"allowSyntheticDefaultImports": true,
@@ -29,8 +30,8 @@
/* Module resolution */
"baseUrl": "./",
"paths": {
- "prozilla-os": ["packages/prozilla-os/dist/main"],
- "@prozilla-os/*": ["packages/*/dist/main", "packages/*/src/main", "packages/apps/*/dist/main"],
+ "prozilla-os": ["packages/prozilla-os/dist/main", "packages/prozilla-os/src/main"],
+ "@prozilla-os/*": ["packages/*/dist/main", "packages/*/src/main", "packages/apps/*/dist/main", "packages/apps/*/src/main"],
}
},
"include": [