This commit is contained in:
Casey Wittrock 2025-10-20 09:26:47 -05:00
parent d76ee19be7
commit 26609eb46c
11 changed files with 251 additions and 70 deletions

View file

@ -1,13 +1,20 @@
frappe.pages["custom_ui"].on_page_load = async (wrapper) => { frappe.pages["custom_ui"].on_page_load = async (wrapper) => {
$(wrapper).html('<div id="custom-ui-app"></div>'); $(wrapper).html('<div id="custom-ui-app"></div>');
console.log("App root div created"); console.log("App root div created");
const script = document.createElement("script");
manifest = await fetch("/assets/custom_ui/dist/.vite/manifest.json").then((res) => res.json()); manifest = await fetch("/assets/custom_ui/dist/.vite/manifest.json").then((res) => res.json());
console.log("Fetched manifest:", manifest); console.log("Fetched manifest:", manifest);
const script = document.createElement("script");
script.src = "/assets/custom_ui/dist/" + manifest["src/main.js"]["file"]; script.src = "/assets/custom_ui/dist/" + manifest["src/main.js"]["file"];
script.type = "module"; script.type = "module";
document.body.appendChild(script); document.body.appendChild(script);
console.log("Appended script:", script.src);
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "/assets/custom_ui/dist/" + manifest["src/main.js"]["css"][0];
document.head.appendChild(link);
console.log("Custom UI stylesheet loaded:", link.href);
console.log("Custom UI script loaded:", script.src); console.log("Custom UI script loaded:", script.src);
}; };

View file

@ -7,7 +7,7 @@
<title>frontend</title> <title>frontend</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="custom-ui-app"></div>
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.js"></script>
</body> </body>
</html> </html>

View file

@ -10,7 +10,9 @@
"dependencies": { "dependencies": {
"axios": "^1.12.2", "axios": "^1.12.2",
"frappe-ui": "^0.1.205", "frappe-ui": "^0.1.205",
"vue": "^3.5.22" "pinia": "^3.0.3",
"vue": "^3.5.22",
"vue-router": "^4.6.3"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^6.0.1",
@ -1880,8 +1882,31 @@
"version": "6.6.4", "version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/@vue/devtools-kit": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz",
"integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==",
"license": "MIT", "license": "MIT",
"peer": true "dependencies": {
"@vue/devtools-shared": "^7.7.7",
"birpc": "^2.3.0",
"hookable": "^5.5.3",
"mitt": "^3.0.1",
"perfect-debounce": "^1.0.0",
"speakingurl": "^14.0.1",
"superjson": "^2.2.2"
}
},
"node_modules/@vue/devtools-shared": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz",
"integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==",
"license": "MIT",
"dependencies": {
"rfdc": "^1.4.1"
}
}, },
"node_modules/@vue/reactivity": { "node_modules/@vue/reactivity": {
"version": "3.5.22", "version": "3.5.22",
@ -2149,6 +2174,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/birpc": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.6.1.tgz",
"integrity": "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/bl": { "node_modules/bl": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@ -2324,6 +2358,21 @@
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/copy-anything": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"license": "MIT",
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/core-js": { "node_modules/core-js": {
"version": "3.46.0", "version": "3.46.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz",
@ -2919,6 +2968,12 @@
"node": ">=12.0.0" "node": ">=12.0.0"
} }
}, },
"node_modules/hookable": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
"license": "MIT"
},
"node_modules/idb-keyval": { "node_modules/idb-keyval": {
"version": "6.2.2", "version": "6.2.2",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz",
@ -3023,6 +3078,18 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-what": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
"license": "MIT",
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "9.0.1", "version": "9.0.1",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
@ -3196,6 +3263,12 @@
"mini-svg-data-uri": "cli.js" "mini-svg-data-uri": "cli.js"
} }
}, },
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"license": "MIT"
},
"node_modules/mlly": { "node_modules/mlly": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
@ -3320,6 +3393,12 @@
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/perfect-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
"license": "MIT"
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -3338,6 +3417,36 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pinia": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz",
"integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^7.7.2"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.4.4",
"vue": "^2.7.0 || ^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/@vue/devtools-api": {
"version": "7.7.7",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.7.tgz",
"integrity": "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg==",
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^7.7.7"
}
},
"node_modules/pkg-types": { "node_modules/pkg-types": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
@ -3785,6 +3894,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"license": "MIT"
},
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.52.5", "version": "4.52.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
@ -3902,6 +4017,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/speakingurl": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/string_decoder": { "node_modules/string_decoder": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -3935,6 +4059,18 @@
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
} }
}, },
"node_modules/superjson": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
"integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
"license": "MIT",
"dependencies": {
"copy-anything": "^3.0.2"
},
"engines": {
"node": ">=16"
}
},
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -4357,7 +4493,6 @@
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.3.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.3.tgz",
"integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==", "integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@vue/devtools-api": "^6.6.4" "@vue/devtools-api": "^6.6.4"
}, },

View file

@ -11,7 +11,9 @@
"dependencies": { "dependencies": {
"axios": "^1.12.2", "axios": "^1.12.2",
"frappe-ui": "^0.1.205", "frappe-ui": "^0.1.205",
"vue": "^3.5.22" "pinia": "^3.0.3",
"vue": "^3.5.22",
"vue-router": "^4.6.3"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^6.0.1", "@vitejs/plugin-vue": "^6.0.1",

View file

@ -1,14 +1,16 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from "vue";
import SideBar from "./SideBar.vue";
defineProps({ defineProps({
msg: String, msg: String,
}) });
const count = ref(0) const count = ref(0);
</script> </script>
<template> <template>
<SideBar />
<h1>{{ msg }}</h1> <h1>{{ msg }}</h1>
<div class="card"> <div class="card">
@ -19,17 +21,10 @@ const count = ref(0)
</p> </p>
</div> </div>
<p> <p></p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p> <p>
Learn more about IDE Support for Vue in the Learn more about IDE Support for Vue in the
<a <a href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support" target="_blank"
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a >Vue Docs Scaling up Guide</a
>. >.
</p> </p>

View file

@ -0,0 +1,15 @@
<script setup>
import { ref } from "vue";
const isOpen = ref(true);
const selectedItem = ref("home");
const onDisclosure = () => {
isOpen = !isOpen;
};
</script>
<template>
<div class="snw-side-bar">
<button @click="onDisclosure">{{ isOpen ? "Close" : "Open" }}</button>
</div>
</template>

View file

View file

@ -0,0 +1,11 @@
import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../components/pages/Home.vue";
const routes = [{ path: "/", component: Home }];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;

View file

@ -0,0 +1,16 @@
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({
username: "",
roles: [],
}),
actions: {
check_permission(role) {
if (this.roles.includes(role)) {
return true;
}
return false;
},
},
});

View file

@ -13,15 +13,6 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
h1 { h1 {
font-size: 3.2em; font-size: 3.2em;
line-height: 1.1; line-height: 1.1;
@ -50,10 +41,11 @@ button:focus-visible {
padding: 2em; padding: 2em;
} }
#app { #custom-ui-app {
max-width: 1280px; max-width: 1280px;
margin: 0 auto; margin: 0 auto;
padding: 2rem; padding: 2rem;
/* border: 1px solid #444; */
text-align: center; text-align: center;
} }

View file

@ -2,20 +2,28 @@ import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue";
import { resolve } from "path"; import { resolve } from "path";
// https://vite.dev/config/ export default defineConfig(({ command }) => {
export default defineConfig({ const isDev = command === "serve"; // 'serve' = npm run dev
return {
plugins: [vue()], plugins: [vue()],
base: isDev ? "/" : "/assets/custom_ui/dist/",
build: { build: {
outDir: resolve(__dirname, "../custom_ui/public/dist"), outDir: isDev
? resolve(__dirname, "dist-dev") // optional, Vite dev server serves in memory
: resolve(__dirname, "../custom_ui/public/dist"),
emptyOutDir: true, emptyOutDir: true,
manifest: true, manifest: true,
rollupOptions: { rollupOptions: {
input: resolve(__dirname, "src/main.js"), input: resolve(__dirname, "src/main.js"),
}, },
}, },
server: { server: {
port: 5173, port: 5173,
strictPort: true, strictPort: true,
}, },
base: "/assets/custom_ui/dist/", };
}); });