diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..bd2257d
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,12 @@
+{
+ "plugins": ["prettier-plugin-svelte"],
+ "overrides": [
+ {
+ "files": "*.svelte",
+ "options": {
+ "parser": "svelte",
+ "svelteIndentScriptAndStyle": true
+ }
+ }
+ ]
+}
diff --git a/jsconfig.json b/jsconfig.json
index 04a3e53..09de4c3 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -26,6 +26,12 @@
],
"@static/*": [
"./static/*"
+ ],
+ "@ts/*": [
+ "./src/ts/*"
+ ],
+ "@stores": [
+ "./src/ts/store.ts"
]
}
}
diff --git a/package-lock.json b/package-lock.json
index cf45851..9c10e63 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@lucide/svelte": "^0.487.0",
"@tailwindcss/vite": "^4.1.3",
"lucide-svelte": "^0.475.0",
+ "pocketbase": "^0.26.2",
"svelte-katex": "^0.1.2",
"svelte-media-queries": "^1.6.2",
"theme-change": "^2.5.0"
@@ -23,6 +24,8 @@
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"daisyui": "^5.0.12",
+ "prettier": "^3.6.2",
+ "prettier-plugin-svelte": "^3.4.0",
"sass": "^1.77.4",
"svelte": "^5.25.7",
"svelte-check": "^3.8.6",
@@ -3137,6 +3140,12 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pocketbase": {
+ "version": "0.26.2",
+ "resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.26.2.tgz",
+ "integrity": "sha512-WA8EOBc3QnSJh8rJ3iYoi9DmmPOMFIgVfAmIGux7wwruUEIzXgvrO4u0W2htfQjGIcyezJkdZOy5Xmh7SxAftw==",
+ "license": "MIT"
+ },
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@@ -3183,6 +3192,33 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
+ "node_modules/prettier": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
+ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-plugin-svelte": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz",
+ "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "prettier": "^3.0.0",
+ "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
+ }
+ },
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
diff --git a/package.json b/package.json
index 8c78502..e77804c 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,8 @@
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"daisyui": "^5.0.12",
+ "prettier": "^3.6.2",
+ "prettier-plugin-svelte": "^3.4.0",
"sass": "^1.77.4",
"svelte": "^5.25.7",
"svelte-check": "^3.8.6",
@@ -31,6 +33,7 @@
"@lucide/svelte": "^0.487.0",
"@tailwindcss/vite": "^4.1.3",
"lucide-svelte": "^0.475.0",
+ "pocketbase": "^0.26.2",
"svelte-katex": "^0.1.2",
"svelte-media-queries": "^1.6.2",
"theme-change": "^2.5.0"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d4195cc..c560233 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,9 @@ importers:
lucide-svelte:
specifier: ^0.475.0
version: 0.475.0(svelte@5.25.7)
+ pocketbase:
+ specifier: ^0.26.2
+ version: 0.26.2
svelte-katex:
specifier: ^0.1.2
version: 0.1.2
@@ -1150,6 +1153,9 @@ packages:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
+ pocketbase@0.26.2:
+ resolution: {integrity: sha512-WA8EOBc3QnSJh8rJ3iYoi9DmmPOMFIgVfAmIGux7wwruUEIzXgvrO4u0W2htfQjGIcyezJkdZOy5Xmh7SxAftw==}
+
postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
@@ -2281,6 +2287,8 @@ snapshots:
picomatch@4.0.2: {}
+ pocketbase@0.26.2: {}
+
postcss-selector-parser@6.0.10:
dependencies:
cssesc: 3.0.0
diff --git a/src/pages/shop/_shop_main.svelte b/src/pages/shop/_shop_main.svelte
index 1eb0724..af49449 100644
--- a/src/pages/shop/_shop_main.svelte
+++ b/src/pages/shop/_shop_main.svelte
@@ -1,14 +1,29 @@
-
+
-
- {#each { length: 5 } as _, i}
-
- {/each}
+
+ {#if allItems != undefined}
+ {#each allItems as item, i}
+
+ {/each}
+ {:else}
+
+ {/if}
diff --git a/src/pages/shop/comps/ShopItemCard.svelte b/src/pages/shop/comps/ShopItemCard.svelte
index a3049e3..8d06766 100644
--- a/src/pages/shop/comps/ShopItemCard.svelte
+++ b/src/pages/shop/comps/ShopItemCard.svelte
@@ -1,14 +1,22 @@
-
-
-

+
-
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 5621849..d9a3352 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -26,7 +26,7 @@
afterNavigate(() => {
const params = new URLSearchParams(window.location.search);
hideOnPrint = params.get("hideOnPrint") === "1";
- console.log(hideOnPrint);
+ // console.log(hideOnPrint);
});
import { onMount } from "svelte";
@@ -105,7 +105,8 @@
Zhen CVZhen CV
Games
@@ -142,7 +143,11 @@
href="https://botalex.itch.io/"
target="_blank">Games
-
Zhen's CV
+
Zhen's CV
diff --git a/src/ts/Helper.ts b/src/ts/Helper.ts
new file mode 100644
index 0000000..c248011
--- /dev/null
+++ b/src/ts/Helper.ts
@@ -0,0 +1,57 @@
+import { PUBLIC_URL_BASE } from "$env/static/public";
+
+// Absolute vibe coded. Idk if it works or not. Not important anyways
+// Assumes PUBLIC_URL_BASE is something like "https://deprived.dev"
+const ABSOLUTE_RE = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//;
+
+function withTrailingSlash(s: string): string {
+ return s.replace(/\/+$/, "") + "/";
+}
+
+export function ParseAssetUrl(url: string, base?: string): string {
+ // Handle empty/undefined url: if a base is given, return the base itself
+ if (!url) {
+ const origin =
+ (typeof PUBLIC_URL_BASE !== "undefined" && PUBLIC_URL_BASE) || "";
+ if (!base) return ""; // no filename, no base → nothing to resolve
+
+ try {
+ // Make base absolute
+ const absoluteBase = ABSOLUTE_RE.test(base)
+ ? withTrailingSlash(base)
+ : new URL(withTrailingSlash(base), withTrailingSlash(origin)).href;
+
+ return absoluteBase; // e.g. "https://deprived.dev/assets/shop/preview-images/"
+ } catch {
+ return "";
+ }
+ }
+
+ // Already absolute
+ if (ABSOLUTE_RE.test(url)) {
+ try {
+ return new URL(url).href;
+ } catch {
+ return url;
+ }
+ }
+
+ const origin =
+ (typeof PUBLIC_URL_BASE !== "undefined" && PUBLIC_URL_BASE) || "";
+ let absoluteBase = "";
+
+ try {
+ if (base) {
+ absoluteBase = ABSOLUTE_RE.test(base)
+ ? withTrailingSlash(base)
+ : new URL(withTrailingSlash(base), withTrailingSlash(origin)).href;
+ } else {
+ if (!origin) return url;
+ absoluteBase = withTrailingSlash(origin);
+ }
+
+ return new URL(url, absoluteBase).href;
+ } catch {
+ return url;
+ }
+}
diff --git a/src/ts/api/api.ts b/src/ts/api/api.ts
new file mode 100644
index 0000000..963c5a4
--- /dev/null
+++ b/src/ts/api/api.ts
@@ -0,0 +1,18 @@
+// This files is meant for interaction with pocketbase. I might split this into multiple files later
+// It is meant to be called from stores.ts
+
+import PocketBase from "pocketbase";
+import { ShopItem } from "./classes/ShopItem";
+import { PUBLIC_POCKET_URL, PUBLIC_ASSETS_URL_BASE } from "$env/static/public";
+
+export let pb = new PocketBase(PUBLIC_POCKET_URL);
+
+console.log(PUBLIC_POCKET_URL);
+
+export class ApiService {
+ // read function name
+ static async GetAllShopItems(): Promise
{
+ const list = await pb.collection("shopItems").getList(1, 50, {});
+ return list.items.map((rec: any) => ShopItem.fromJSON(rec));
+ }
+}
diff --git a/src/ts/api/classes/ShopItem.ts b/src/ts/api/classes/ShopItem.ts
new file mode 100644
index 0000000..459ffc4
--- /dev/null
+++ b/src/ts/api/classes/ShopItem.ts
@@ -0,0 +1,46 @@
+import { PUBLIC_POCKET_URL, PUBLIC_URL_BASE } from "$env/static/public";
+import { ParseAssetUrl } from "@src/ts/Helper";
+
+export class ShopItem {
+ item_name: string;
+ preview_image: string;
+ page_url: string; // the url used for the item
+ images_root: string; // might not be optimal to include this, in the same class, but should be fine, for now at least
+ category: string[];
+ sold_quantity: number;
+ stock: number;
+ unlisted: boolean;
+
+ constructor(
+ item_name: string,
+ preview_image: string,
+ redirect: string,
+ images_root: string,
+ category: string[],
+ sold_quantity: number,
+ stock: number,
+ unlisted: boolean,
+ ) {
+ this.item_name = item_name;
+ this.preview_image = preview_image;
+ this.page_url = redirect;
+ this.images_root = images_root;
+ this.category = category;
+ this.sold_quantity = sold_quantity;
+ this.stock = stock;
+ this.unlisted = unlisted;
+ }
+
+ static fromJSON(json: any): ShopItem {
+ return new ShopItem(
+ json.item_name,
+ ParseAssetUrl(json.preview_image, "/assets/shop/preview-images"),
+ json.page_url,
+ ParseAssetUrl(json.images_root, "/assets/shop/" + json.item_name + "/"), // Please use better paths
+ json.category,
+ json.sold_quantity,
+ json.stock,
+ json.unlisted,
+ );
+ }
+}
diff --git a/src/ts/store.ts b/src/ts/store.ts
index 2061bcf..5519f84 100644
--- a/src/ts/store.ts
+++ b/src/ts/store.ts
@@ -1,2 +1,3 @@
-import PocketBase from "pocketbase";
-export let pb = new PocketBase("https://pocket.deprived.dev");
+import { ApiService } from "./api/api";
+
+export let api = ApiService;
diff --git a/vite.config.js b/vite.config.js
index 456f4d1..a90f8dd 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -24,7 +24,9 @@ export default defineConfig({
"@src": path.resolve("./src"),
"@static": path.resolve("./static"),
"@pages": path.resolve("./src/pages"),
+ "@ts": path.resolve("./src/ts"),
"@shop": path.resolve("./src/pages/shop"),
+ "@stores": path.resolve("./src/ts/store.ts"),
},
},
server: {