diff --git a/oa/front/audio.html b/oa/front/audio.html
new file mode 100644
index 0000000..07b5f23
--- /dev/null
+++ b/oa/front/audio.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+ Music Player
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/oa/front/card.html b/oa/front/card.html
new file mode 100644
index 0000000..58a05b2
--- /dev/null
+++ b/oa/front/card.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Card
+
+
+
+
+
+ slot a
+
+
+
+
+
+
diff --git a/oa/front/favicon.ico b/oa/front/favicon.ico
new file mode 100644
index 0000000..e26bc40
Binary files /dev/null and b/oa/front/favicon.ico differ
diff --git a/oa/front/index.html b/oa/front/index.html
new file mode 100644
index 0000000..6e89a6b
--- /dev/null
+++ b/oa/front/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+ Index
+
+
+
+
+
+
+
+
+
+
+
diff --git a/oa/front/layout/default.html b/oa/front/layout/default.html
new file mode 100644
index 0000000..3b9a9b1
--- /dev/null
+++ b/oa/front/layout/default.html
@@ -0,0 +1,12 @@
+
+
+ Default
+
+
+
+
+
+
+
diff --git a/oa/front/router.html b/oa/front/router.html
new file mode 100644
index 0000000..969d7a5
--- /dev/null
+++ b/oa/front/router.html
@@ -0,0 +1,6 @@
+
+ >
+
+
+
diff --git a/oa/front/tailwind.config.js b/oa/front/tailwind.config.js
new file mode 100644
index 0000000..16b1323
--- /dev/null
+++ b/oa/front/tailwind.config.js
@@ -0,0 +1,28 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: [
+ "./components/**/*.{js,vue,ts}",
+ "./layouts/**/*.vue",
+ "./pages/**/*.vue",
+ "./plugins/**/*.{js,ts}",
+ "./app.vue",
+ "./error.vue",
+ "*.html",
+ ],
+ theme: {
+ extend: {
+ colors: {
+ vprimary: '#2196f3',
+ vsecondary: '#ecc94b',
+ vaccents: '#ff9800',
+ verror: '#f44336',
+ vwaring: '#ff5722',
+ vinfo: '#ffc107',
+ vsuccess: '#53de58',
+ vignore: '#d1d5db',
+ }
+ },
+ },
+ plugins: [],
+}
+
diff --git a/oa/front/v.js b/oa/front/v.js
new file mode 100644
index 0000000..c2f26c8
--- /dev/null
+++ b/oa/front/v.js
@@ -0,0 +1,158 @@
+/*
+ * v.js
+ * Copyright (C) 2024 veypi
+ *
+ * Distributed under terms of the GPL license.
+ */
+
+(function () {
+ 'use strict';
+
+ const config = { childList: true, subtree: true };
+
+ const callback = function (mutationsList, observer) {
+ for (let mutation of mutationsList) {
+ if (mutation.type === 'childList') {
+ // console.log(mutation)
+ // console.log('A child node has been added or removed.');
+ }
+ }
+ };
+
+ const observer = new MutationObserver(callback);
+
+ var cacheUrl = {}
+ var pendingRequests = {};
+
+ async function fetchFileWithCache(url) {
+ if (cacheUrl[url]) {
+ return Promise.resolve(cacheUrl[url]);
+ }
+ if (pendingRequests[url]) {
+ return pendingRequests[url];
+ }
+ const promise = fetch(url)
+ .then(response => {
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ return response.text();
+ })
+ .then(txt => {
+ cacheUrl[url] = txt;
+ return txt;
+ })
+ .catch(error => {
+ console.error('Error fetching the file:', error);
+ delete pendingRequests[url];
+ throw error;
+ })
+ .finally(() => {
+ delete pendingRequests[url];
+ });
+ pendingRequests[url] = promise;
+ return promise;
+ }
+
+
+ function extractBodyAndScript(htmlString) {
+ const bodyMatch = htmlString.match(/]*>([\s\S]*)<\/body>/i);
+ const bodyContent = bodyMatch ? bodyMatch[1] : '';
+
+ let scriptMatches = htmlString.match(/