diff --git a/eslint.config.js b/eslint.config.js
index a0ec258..5f2f610 100755
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,6 +1,5 @@
import globals from "globals";
-import tseslint from "@typescript-eslint/eslint-plugin";
-import tsParser from "@typescript-eslint/parser";
+import pluginVue from "eslint-plugin-vue";
export default [
{
@@ -12,32 +11,22 @@ export default [
"build/**",
],
},
+ ...pluginVue.configs["flat/essential"],
{
- files: ["**/*.{ts,tsx}"],
languageOptions: {
- parser: tsParser,
- parserOptions: {
- ecmaVersion: "latest",
- sourceType: "module",
- ecmaFeatures: {
- jsx: true,
- },
- },
globals: {
...globals.browser,
...globals.node,
+ Alpine: "readonly",
+ $: "readonly",
+ jQuery: "readonly",
},
},
- plugins: {
- "@typescript-eslint": tseslint,
- },
rules: {
"no-console": "warn",
"no-debugger": "warn",
- "@typescript-eslint/no-unused-vars": [
- "warn",
- { argsIgnorePattern: "^_" },
- ],
+ "vue/multi-word-component-names": "off",
+ "vue/no-v-html": "off",
},
},
];
diff --git a/package.json b/package.json
index 7634b12..88e28ef 100755
--- a/package.json
+++ b/package.json
@@ -8,17 +8,16 @@
"build:atom": "vite build --config resources/themes/atom/vite.config.js && php artisan optimize:clear && php artisan optimize && chown -R www-data:www-data public/build",
"build:dusk": "vite build --config resources/themes/dusk/vite.config.js && php artisan optimize:clear && php artisan optimize && chown -R www-data:www-data public/build",
"build:all": "vite build --config resources/themes/atom/vite.config.js && vite build --config resources/themes/dusk/vite.config.js && php artisan optimize:clear && php artisan optimize && chown -R www-data:www-data public/build",
- "typecheck": "tsc --noEmit",
"preview": "vite preview",
- "format": "prettier \"resources/**/*.{js,ts,tsx,vue,blade}\" --ignore-unknown --write",
- "format:check": "prettier \"resources/**/*.{js,ts,tsx,vue,blade.php}\" --check",
- "lint": "eslint \"resources/js/\" --ext .ts,.tsx",
- "lint:fix": "eslint \"resources/js/\" --ext .ts,.tsx --fix",
+ "format": "prettier \"resources/**/*.{js,ts,vue,blade}\" --ignore-unknown --write",
+ "format:check": "prettier \"resources/**/*.{js,ts,vue,blade.php}\" --check",
+ "lint": "eslint resources/js/",
+ "lint:fix": "eslint resources/js/ --fix",
"lint:css": "stylelint \"resources/**/*.css\"",
"lint:css:fix": "stylelint \"resources/**/*.css\" --fix",
"lint:all": "yarn lint && yarn lint:css",
"lint:fix:all": "yarn lint:fix && yarn lint:fix:css",
- "check": "yarn typecheck && yarn lint:all && yarn format:check",
+ "check": "yarn lint:all && yarn format:check",
"check:php": "php -l app/ && php -l routes/ && php -l database/ && php -l resources/",
"check:security": "composer audit && npm audit",
"check:deps": "npm outdated --long --json || true",
@@ -34,17 +33,12 @@
"@tailwindcss/forms": "0.5.11",
"@tailwindcss/postcss": "4.3.0",
"@tailwindcss/typography": "0.5.19",
- "@types/lodash": "^4.17.24",
- "@types/react": "^19.2.17",
- "@types/react-dom": "^19.2.3",
- "@typescript-eslint/eslint-plugin": "^8.61.1",
- "@typescript-eslint/parser": "^8.61.1",
"alpinejs": "3.15.12",
"autoprefixer": "10.5.0",
"axios": "^1.17.0",
"esbuild": "^0.28.0",
"eslint": "^10.4.1",
- "globals": "^17.6.0",
+ "eslint-plugin-vue": "10.9.2",
"laravel-vite-plugin": "^3.1.0",
"lodash": "^4.18.1",
"postcss": "8.5.15",
@@ -55,7 +49,6 @@
"stylelint-config-standard": "^40.0.0",
"tailwindcss": "4.3.0",
"turbolinks": "5.2.0",
- "typescript": "^6.0.3",
"vite": "^8.0.16"
},
"dependencies": {
diff --git a/public/build/manifest.json b/public/build/manifest.json
index 7bc56e7..f7d8067 100644
--- a/public/build/manifest.json
+++ b/public/build/manifest.json
@@ -1,26 +1,15 @@
{
- "_axios-BEkq_c61.js": {
- "file": "assets/axios-BEkq_c61.js",
+ "_axios-Bb9VWCvi.js": {
+ "file": "assets/axios-Bb9VWCvi.js",
"name": "axios",
"imports": [
- "_chunk-b3L32Ng1.js"
+ "_chunk-QTnfLwEv.js"
]
},
- "_chunk-b3L32Ng1.js": {
- "file": "assets/chunk-b3L32Ng1.js",
+ "_chunk-QTnfLwEv.js": {
+ "file": "assets/chunk-QTnfLwEv.js",
"name": "chunk"
},
- "_swiper-Cjlszzo3.js": {
- "file": "assets/swiper-Cjlszzo3.js",
- "name": "swiper",
- "css": [
- "assets/swiper-CrMA9oas.css"
- ]
- },
- "_swiper-CrMA9oas.css": {
- "file": "assets/swiper-CrMA9oas.css",
- "src": "_swiper-CrMA9oas.css"
- },
"public/assets/images/background-dark.jpg": {
"file": "assets/background-dark-BfkMu3-0.jpg",
"src": "public/assets/images/background-dark.jpg"
@@ -29,18 +18,6 @@
"file": "assets/background-light-CP7oKwVT.jpg",
"src": "public/assets/images/background-light.jpg"
},
- "public/assets/images/dusk/background_image.png": {
- "file": "assets/background_image-BH7pVpv1.png",
- "src": "public/assets/images/dusk/background_image.png"
- },
- "public/assets/images/dusk/leaderboard_circle_image.png": {
- "file": "assets/leaderboard_circle_image-BYkDVX69.png",
- "src": "public/assets/images/dusk/leaderboard_circle_image.png"
- },
- "public/assets/images/dusk/store_icon.png": {
- "file": "assets/store_icon-B52tsSKO.png",
- "src": "public/assets/images/dusk/store_icon.png"
- },
"public/assets/images/icons/article.gif": {
"file": "assets/article-CYhGsSKA.gif",
"src": "public/assets/images/icons/article.gif"
@@ -134,7 +111,7 @@
"src": "public/assets/images/profile/profile-bg.png"
},
"resources/css/global.css": {
- "file": "assets/global-CwMfkl9f.css",
+ "file": "assets/global-DmKtm1TC.css",
"name": "global",
"names": [
"global.css"
@@ -169,27 +146,27 @@
"assets/community-Do_t1zw9.png"
]
},
- "resources/js/global.ts": {
- "file": "assets/global-B6tm4RcQ.js",
+ "resources/js/global.js": {
+ "file": "assets/global-r22-sRCc.js",
"name": "global",
- "src": "resources/js/global.ts",
+ "src": "resources/js/global.js",
"isEntry": true,
"imports": [
- "_chunk-b3L32Ng1.js",
- "_axios-BEkq_c61.js"
+ "_chunk-QTnfLwEv.js",
+ "_axios-Bb9VWCvi.js"
]
},
- "resources/js/ssr.tsx": {
- "file": "assets/ssr-GVDc-G73.js",
+ "resources/js/ssr.jsx": {
+ "file": "assets/ssr-DdmZbD73.js",
"name": "ssr",
- "src": "resources/js/ssr.tsx",
+ "src": "resources/js/ssr.jsx",
"isEntry": true,
"imports": [
- "_chunk-b3L32Ng1.js"
+ "_chunk-QTnfLwEv.js"
]
},
"resources/themes/atom/css/app.css": {
- "file": "assets/app-BPKvU7LK.css",
+ "file": "assets/app-DtTGSxkD.css",
"name": "app",
"names": [
"app.css"
@@ -224,56 +201,17 @@
"assets/community-Do_t1zw9.png"
]
},
- "resources/themes/atom/js/app.ts": {
- "file": "assets/app-evCrhLY1.js",
+ "resources/themes/atom/js/app.js": {
+ "file": "assets/app-CAkt-7PZ.js",
"name": "app",
- "src": "resources/themes/atom/js/app.ts",
+ "src": "resources/themes/atom/js/app.js",
"isEntry": true,
"imports": [
- "_chunk-b3L32Ng1.js",
- "_swiper-Cjlszzo3.js",
- "_axios-BEkq_c61.js"
- ]
- },
- "resources/themes/dusk/css/app.css": {
- "file": "assets/app-CHSILL1f.css",
- "name": "app",
- "names": [
- "app.css"
- ],
- "src": "resources/themes/dusk/css/app.css",
- "isEntry": true,
- "assets": [
- "assets/background_image-BH7pVpv1.png",
- "assets/feeds-BtHcJdHX.png",
- "assets/chat-r5H1PnTg.png",
- "assets/article-CYhGsSKA.gif",
- "assets/lighthouse-BON6qnQ0.png",
- "assets/store_icon-B52tsSKO.png",
- "assets/catalog-D-956oDx.png",
- "assets/inventory-BlHYLNGT.png",
- "assets/due-chat-CeO4yxLu.png",
- "assets/friends-BxpcKlvz.png",
- "assets/credits-Dpg5Nmby.png",
- "assets/duckets-CaGJI1Oy.png",
- "assets/diamonds-BtfqKoQu.png",
- "assets/trophy-gold-bbKmpkii.png",
- "assets/trophy-silver-bGfHJkQ_.png",
- "assets/trophy-bronze-CgV5j1MU.png",
- "assets/leaderboard_circle_image-BYkDVX69.png"
- ]
- },
- "resources/themes/dusk/js/app.ts": {
- "file": "assets/app-DKy1JARZ.js",
- "name": "app",
- "src": "resources/themes/dusk/js/app.ts",
- "isEntry": true,
- "imports": [
- "_swiper-Cjlszzo3.js",
- "_axios-BEkq_c61.js"
+ "_chunk-QTnfLwEv.js",
+ "_axios-Bb9VWCvi.js"
],
"css": [
- "assets/app-DU8Y3NnC.css"
+ "assets/app-CeYfhhVD.css"
]
}
}
\ No newline at end of file
diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js
new file mode 100755
index 0000000..34478d4
--- /dev/null
+++ b/resources/js/bootstrap.js
@@ -0,0 +1,34 @@
+import _ from "lodash";
+window._ = _;
+
+/**
+ * We'll load the axios HTTP library which allows us to easily issue requests
+ * to our Laravel back-end. This library automatically handles sending the
+ * CSRF token as a header based on the value of the "XSRF" token cookie.
+ */
+
+import axios from "axios";
+window.axios = axios;
+
+window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
+
+/**
+ * Echo exposes an expressive API for subscribing to channels and listening
+ * for events that are broadcast by Laravel. Echo and event broadcasting
+ * allows your team to easily build robust real-time web applications.
+ */
+
+// import Echo from 'laravel-echo';
+
+// import Pusher from 'pusher-js';
+// window.Pusher = Pusher;
+
+// window.Echo = new Echo({
+// broadcaster: 'pusher',
+// key: import.meta.env.VITE_PUSHER_APP_KEY,
+// wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
+// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
+// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
+// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
+// enabledTransports: ['ws', 'wss'],
+// });
diff --git a/resources/js/bootstrap.ts b/resources/js/bootstrap.ts
deleted file mode 100755
index 11434e8..0000000
--- a/resources/js/bootstrap.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import _ from "lodash";
-import axios from "axios";
-
-window._ = _;
-window.axios = axios;
-window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
diff --git a/resources/js/global.ts b/resources/js/global.js
similarity index 100%
rename from resources/js/global.ts
rename to resources/js/global.js
diff --git a/resources/js/pages/Home.jsx b/resources/js/pages/Home.jsx
new file mode 100755
index 0000000..e0bf985
--- /dev/null
+++ b/resources/js/pages/Home.jsx
@@ -0,0 +1,31 @@
+import { Head } from '@inertiajs/react'
+
+export default function Home({ auth, hotelName }) {
+ return (
+ <>
+
+
+
+
+ Welkom bij {hotelName}
+
+
+ Dit is een Inertia.js pagina — zelfde layout, zelfde Tailwind, zelfde stijlen.
+
+
+
+
+ >
+ )
+}
diff --git a/resources/js/pages/Home.tsx b/resources/js/pages/Home.tsx
deleted file mode 100755
index 34ce8c2..0000000
--- a/resources/js/pages/Home.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Head } from "@inertiajs/react";
-
-interface HomeProps {
- auth: Record;
- hotelName: string;
-}
-
-export default function Home({ hotelName }: HomeProps) {
- return (
- <>
-
-
-
-
- Welkom bij {hotelName}
-
-
- Dit is een Inertia.js pagina — zelfde layout, zelfde Tailwind,
- zelfde stijlen.
-
-
-
-
- >
- );
-}
diff --git a/resources/js/pages/Index.jsx b/resources/js/pages/Index.jsx
new file mode 100755
index 0000000..4d3a3fa
--- /dev/null
+++ b/resources/js/pages/Index.jsx
@@ -0,0 +1,119 @@
+import { Head, usePage } from '@inertiajs/react'
+
+export default function Index({ articles, photos }) {
+ const { avatarImager } = usePage().props
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
Laatste nieuws
+
Blijf op de hoogte van het laatste hotel nieuws.
+
+
+
+
+
+
+
+ {photos.length > 0 && (
+
+
+
+
+
+
Laatste foto's
+
Bekijk de mooiste momenten vastgelegd door gebruikers.
+
+
+
+
+
+
+ )}
+
+ >
+ )
+}
diff --git a/resources/js/pages/Index.tsx b/resources/js/pages/Index.tsx
deleted file mode 100755
index d361847..0000000
--- a/resources/js/pages/Index.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-import { Head, usePage } from "@inertiajs/react";
-
-interface User {
- look: string;
- username: string;
-}
-
-interface Article {
- id: number;
- slug: string;
- title: string;
- image: string;
- user?: User;
-}
-
-interface Photo {
- id: number;
- url: string;
- user?: User;
-}
-
-interface IndexProps {
- articles: Article[];
- photos: Photo[];
-}
-
-interface SharedProps extends Record {
- avatarImager: string;
-}
-
-export default function Index({ articles, photos }: IndexProps) {
- const { avatarImager } = usePage().props;
-
- return (
- <>
-
-
-
-
-
-
-
-
-
- Laatste nieuws
-
-
- Blijf op de hoogte van het laatste hotel nieuws.
-
-
-
-
-
-
-
-
- {photos.length > 0 && (
-
-
-
-
-
-
- Laatste foto's
-
-
- Bekijk de mooiste momenten vastgelegd door gebruikers.
-
-
-
-
-
-
-
- )}
-
- >
- );
-}
diff --git a/resources/js/ssr.jsx b/resources/js/ssr.jsx
new file mode 100755
index 0000000..49ff5b1
--- /dev/null
+++ b/resources/js/ssr.jsx
@@ -0,0 +1,12 @@
+import { createInertiaApp } from '@inertiajs/react'
+import { createRoot } from 'react-dom/client'
+
+createInertiaApp({
+ resolve: name => {
+ const pages = import.meta.glob('./pages/**/*.jsx', { eager: true })
+ return pages[`./pages/${name}.jsx`]
+ },
+ setup({ el, App, props }) {
+ createRoot(el).render()
+ },
+})
diff --git a/resources/js/ssr.tsx b/resources/js/ssr.tsx
deleted file mode 100755
index 9ceb0fc..0000000
--- a/resources/js/ssr.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { createInertiaApp } from "@inertiajs/react";
-import { createRoot } from "react-dom/client";
-import type { ComponentType } from "react";
-
-createInertiaApp({
- resolve: (name: string) => {
- const pages = import.meta.glob<{ default: ComponentType }>(
- "./pages/**/*.tsx",
- { eager: true },
- );
- return pages[`./pages/${name}.tsx`];
- },
- setup({ el, App, props }) {
- createRoot(el).render();
- },
-});
diff --git a/resources/js/types.d.ts b/resources/js/types.d.ts
deleted file mode 100644
index d1c49a9..0000000
--- a/resources/js/types.d.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-declare module "alpinejs" {
- interface Alpine {
- data(name: string, callback: (...args: unknown[]) => Record): void;
- plugin(plugin: unknown): void;
- start(): void;
- }
- const Alpine: Alpine;
- export default Alpine;
-}
-
-declare module "@alpinejs/focus" {
- const focus: unknown;
- export default focus;
-}
-
-declare module "turbolinks" {
- interface TurbolinksStatic {
- start(): void;
- }
- const Turbolinks: TurbolinksStatic;
- export default Turbolinks;
-}
-
-interface Window {
- _: import("lodash").default;
- axios: import("axios").AxiosStatic;
- App: {
- defaultReactions: string[];
- isAuthenticated: boolean;
- };
-}
diff --git a/resources/themes/atom/js/app.js b/resources/themes/atom/js/app.js
new file mode 100755
index 0000000..46cd354
--- /dev/null
+++ b/resources/themes/atom/js/app.js
@@ -0,0 +1,25 @@
+import "./bootstrap";
+import "./external/flowbite";
+
+import "swiper/css";
+import "swiper/css/pagination";
+
+import Alpine from "alpinejs";
+import Focus from "@alpinejs/focus";
+
+import ArticleReactions from "./components/ArticleReactions.js";
+
+import ThemeSwitcher from "./components/ThemeSwitcher.js";
+import AtomSliders from "./components/AtomSliders.js";
+
+ThemeSwitcher.init();
+ArticleReactions.init();
+AtomSliders.init();
+Alpine.plugin(Focus);
+Alpine.start();
+
+console.log(
+ "%cAtom CMS%c\n\nAtom CMS is a CMS for made for the community to enjoy. You can join our wonderful community at https://discord.gg/rX3aShUHdg\n\n",
+ "color: #14619c; -webkit-text-stroke: 2px black; font-size: 32px; font-weight: bold;",
+ "",
+);
diff --git a/resources/themes/atom/js/app.ts b/resources/themes/atom/js/app.ts
deleted file mode 100755
index 4101c2f..0000000
--- a/resources/themes/atom/js/app.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import "./bootstrap";
-import "./external/flowbite";
-
-import "swiper/css";
-import "swiper/css/pagination";
-
-import Alpine from "alpinejs";
-import Focus from "@alpinejs/focus";
-
-import ArticleReactions from "./components/ArticleReactions";
-import ThemeSwitcher from "./components/ThemeSwitcher";
-import AtomSliders from "./components/AtomSliders";
-
-ThemeSwitcher.init();
-ArticleReactions.init();
-AtomSliders.init();
-Alpine.plugin(Focus);
-Alpine.start();
diff --git a/resources/themes/atom/js/bootstrap.js b/resources/themes/atom/js/bootstrap.js
new file mode 100755
index 0000000..25ba4f6
--- /dev/null
+++ b/resources/themes/atom/js/bootstrap.js
@@ -0,0 +1,34 @@
+/**
+ * We'll load the axios HTTP library which allows us to easily issue requests
+ * to our Laravel back-end. This library automatically handles sending the
+ * CSRF token as a header based on the value of the "XSRF" token cookie.
+ */
+
+import axios from "axios";
+import Turbolinks from "turbolinks";
+
+window.axios = axios;
+window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
+
+Turbolinks.start();
+
+/**
+ * Echo exposes an expressive API for subscribing to channels and listening
+ * for events that are broadcast by Laravel. Echo and event broadcasting
+ * allows your team to easily build robust real-time web applications.
+ */
+
+// import Echo from 'laravel-echo';
+
+// import Pusher from 'pusher-js';
+// window.Pusher = Pusher;
+
+// window.Echo = new Echo({
+// broadcaster: 'pusher',
+// key: import.meta.env.VITE_PUSHER_APP_KEY,
+// wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_CLUSTER}.pusher.com`,
+// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
+// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
+// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
+// enabledTransports: ['ws', 'wss'],
+// });
diff --git a/resources/themes/atom/js/bootstrap.ts b/resources/themes/atom/js/bootstrap.ts
deleted file mode 100755
index 88f04f2..0000000
--- a/resources/themes/atom/js/bootstrap.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import axios from "axios";
-import Turbolinks from "turbolinks";
-
-window.axios = axios;
-window.axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
-
-Turbolinks.start();
diff --git a/resources/themes/atom/js/components/ArticleReactions.js b/resources/themes/atom/js/components/ArticleReactions.js
new file mode 100755
index 0000000..9163877
--- /dev/null
+++ b/resources/themes/atom/js/components/ArticleReactions.js
@@ -0,0 +1,131 @@
+import Alpine from "alpinejs";
+
+const ArticleReactions = {
+ init() {
+ document.addEventListener("alpine:init", () => this.startComponent());
+ },
+
+ startComponent() {
+ Alpine.data(
+ "reactions",
+ (myReactions = [], articleReactions = [], url = "") => ({
+ url,
+ myReactions,
+ articleReactions,
+ allReactions: [],
+ isAuthenticated: false,
+
+ init() {
+ this.treatArticleReactions();
+ this.allReactions = window.App.defaultReactions;
+ this.isAuthenticated = window.App.isAuthenticated;
+
+ this.dispatchFlowbiteEvent();
+ },
+
+ treatArticleReactions() {
+ let articleReactions = this.articleReactions;
+
+ this.articleReactions = [];
+
+ Object.entries(articleReactions).forEach((reactionData) => {
+ let reactionName = reactionData[0],
+ reactions = Object.values(reactionData[1]);
+
+ this.articleReactions.push({
+ id: this.generateVirtualReactionId(reactionName),
+ name: reactionName,
+ count: reactions.length,
+ users: reactions.map((reaction) => reaction.user?.username ?? ""),
+ });
+ });
+ },
+
+ toggleReaction(reaction) {
+ if (!this.url.length || !this.isAuthenticated) return;
+
+ axios.post(this.url, { reaction }).then((response) => {
+ if (!response.data.success) return;
+
+ if (!response.data.added) {
+ this.removeReaction(reaction, response.data.username);
+ return;
+ }
+
+ this.addReaction(reaction, response.data.username);
+ });
+ },
+
+ addReaction(name, username) {
+ this.myReactions.push(name);
+
+ let existingReaction = this.getReactionDataFromName(name);
+
+ if (existingReaction) {
+ existingReaction.count++;
+ existingReaction.users.push(username);
+ return;
+ }
+
+ this.articleReactions.push({
+ id: this.generateVirtualReactionId(name),
+ name,
+ count: 1,
+ users: [username],
+ });
+
+ this.dispatchFlowbiteEvent();
+ },
+
+ removeReaction(name, username) {
+ this.myReactions.splice(this.myReactions.indexOf(name), 1);
+
+ let reactionData = this.getReactionDataFromName(name);
+
+ if (reactionData.count > 1) {
+ reactionData.count--;
+ reactionData.users.splice(reactionData.users.indexOf(username), 1);
+ return;
+ }
+
+ this.$nextTick(() => {
+ this.articleReactions.splice(
+ this.articleReactions.indexOf(reactionData),
+ 1,
+ );
+ });
+ },
+
+ generateVirtualReactionId(name) {
+ return name + Math.floor(Math.random() * 1000);
+ },
+
+ canAddReactionFromModal(name) {
+ return !this.userHasReaction(name) && !this.articleHasReaction(name);
+ },
+
+ userHasReaction(reaction) {
+ return this.myReactions.includes(reaction.name);
+ },
+
+ articleHasReaction(name) {
+ return typeof this.getReactionDataFromName(name) !== "undefined";
+ },
+
+ getReactionDataFromName(name) {
+ return this.articleReactions.find(
+ (reaction) => reaction.name === name,
+ );
+ },
+
+ dispatchFlowbiteEvent() {
+ this.$nextTick(() =>
+ document.dispatchEvent(new CustomEvent("reactions:loaded")),
+ );
+ },
+ }),
+ );
+ },
+};
+
+export { ArticleReactions as default };
diff --git a/resources/themes/atom/js/components/ArticleReactions.ts b/resources/themes/atom/js/components/ArticleReactions.ts
deleted file mode 100755
index 7ba0723..0000000
--- a/resources/themes/atom/js/components/ArticleReactions.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import Alpine from "alpinejs";
-
-interface ReactionData {
- id: string;
- name: string;
- count: number;
- users: string[];
-}
-
-interface ReactionComponent extends Record {
- url: string;
- myReactions: string[];
- articleReactions: ReactionData[];
- allReactions: string[];
- isAuthenticated: boolean;
- init(): void;
- treatArticleReactions(rawReactions: Record): void;
- toggleReaction(reaction: string): void;
- addReaction(name: string, username: string): void;
- removeReaction(name: string, username: string): void;
- generateVirtualReactionId(name: string): string;
- canAddReactionFromModal(name: string): boolean;
- userHasReaction(reaction: ReactionData | string): boolean;
- articleHasReaction(name: string): boolean;
- getReactionDataFromName(name: string): ReactionData | undefined;
- dispatchFlowbiteEvent(): void;
- $nextTick: (callback: () => void) => void;
-}
-
-const ArticleReactions = {
- init() {
- document.addEventListener("alpine:init", () => this.startComponent());
- },
-
- startComponent() {
- Alpine.data("reactions", (...args: unknown[]) => {
- const [myReactions = [], , url = ""] = args as [string[], Record, string];
- const rawArticleReactions = args[1] as Record | undefined;
-
- return {
- url,
- myReactions: myReactions as string[],
- articleReactions: [] as ReactionData[],
- allReactions: [] as string[],
- isAuthenticated: false,
-
- init(this: ReactionComponent) {
- if (rawArticleReactions) {
- this.treatArticleReactions(rawArticleReactions);
- }
- this.allReactions = window.App.defaultReactions;
- this.isAuthenticated = window.App.isAuthenticated;
- this.dispatchFlowbiteEvent();
- },
-
- treatArticleReactions(this: ReactionComponent, raw: Record) {
- const transformed: ReactionData[] = [];
-
- Object.entries(raw).forEach(([name, reactions]) => {
- const values = Object.values(reactions);
- transformed.push({
- id: this.generateVirtualReactionId(name),
- name,
- count: values.length,
- users: values.map((r) => r.user?.username ?? ""),
- });
- });
-
- this.articleReactions = transformed;
- },
-
- toggleReaction(this: ReactionComponent, reaction: string) {
- if (!this.url.length || !this.isAuthenticated) return;
-
- window.axios
- .post(this.url, { reaction })
- .then((response: { data: { success: boolean; added: boolean; username: string } }) => {
- if (!response.data.success) return;
- if (!response.data.added) {
- this.removeReaction(reaction, response.data.username);
- return;
- }
- this.addReaction(reaction, response.data.username);
- });
- },
-
- addReaction(this: ReactionComponent, name: string, username: string) {
- this.myReactions.push(name);
- const existing = this.getReactionDataFromName(name);
- if (existing) {
- existing.count++;
- existing.users.push(username);
- return;
- }
- this.articleReactions.push({
- id: this.generateVirtualReactionId(name),
- name,
- count: 1,
- users: [username],
- });
- this.dispatchFlowbiteEvent();
- },
-
- removeReaction(this: ReactionComponent, name: string, username: string) {
- this.myReactions.splice(this.myReactions.indexOf(name), 1);
- const data = this.getReactionDataFromName(name);
- if (!data) return;
- if (data.count > 1) {
- data.count--;
- data.users.splice(data.users.indexOf(username), 1);
- return;
- }
- this.$nextTick(() => {
- this.articleReactions.splice(this.articleReactions.indexOf(data), 1);
- });
- },
-
- generateVirtualReactionId(this: ReactionComponent, name: string): string {
- return name + Math.floor(Math.random() * 1000);
- },
-
- canAddReactionFromModal(this: ReactionComponent, name: string): boolean {
- return !this.userHasReaction(name) && !this.articleHasReaction(name);
- },
-
- userHasReaction(this: ReactionComponent, reaction: ReactionData | string): boolean {
- const name = typeof reaction === "string" ? reaction : reaction.name;
- return this.myReactions.includes(name);
- },
-
- articleHasReaction(this: ReactionComponent, name: string): boolean {
- return typeof this.getReactionDataFromName(name) !== "undefined";
- },
-
- getReactionDataFromName(this: ReactionComponent, name: string): ReactionData | undefined {
- return this.articleReactions.find((r) => r.name === name);
- },
-
- dispatchFlowbiteEvent(this: ReactionComponent) {
- this.$nextTick(() => document.dispatchEvent(new CustomEvent("reactions:loaded")));
- },
- } as ReactionComponent;
- });
- },
-};
-
-export { ArticleReactions as default };
diff --git a/resources/themes/atom/js/components/AtomSliders.ts b/resources/themes/atom/js/components/AtomSliders.js
similarity index 83%
rename from resources/themes/atom/js/components/AtomSliders.ts
rename to resources/themes/atom/js/components/AtomSliders.js
index be5a2de..afbf1fc 100755
--- a/resources/themes/atom/js/components/AtomSliders.ts
+++ b/resources/themes/atom/js/components/AtomSliders.js
@@ -1,11 +1,6 @@
import Swiper from "swiper";
-interface AtomSlidersStore {
- init(): void;
- initArticleSlider(): void;
-}
-
-const AtomSliders: AtomSlidersStore = {
+const AtomSliders = {
init() {
document.addEventListener("turbolinks:load", () => {
this.initArticleSlider();
diff --git a/resources/themes/atom/js/components/ThemeSwitcher.ts b/resources/themes/atom/js/components/ThemeSwitcher.js
similarity index 71%
rename from resources/themes/atom/js/components/ThemeSwitcher.ts
rename to resources/themes/atom/js/components/ThemeSwitcher.js
index 4b4acaa..21683b9 100755
--- a/resources/themes/atom/js/components/ThemeSwitcher.ts
+++ b/resources/themes/atom/js/components/ThemeSwitcher.js
@@ -1,19 +1,10 @@
-type Theme = "light" | "dark";
-
-interface ThemeSwitcherStore {
- currentTheme: Theme;
- init(): void;
- initButton(): void;
- toggleTheme(): void;
-}
-
-const ThemeSwitcher: ThemeSwitcherStore = {
+const ThemeSwitcher = {
currentTheme: "light",
init() {
if (
localStorage.theme === "dark" ||
- (typeof window.matchMedia !== "undefined" &&
+ (typeof window.matchMedia != "undefined" &&
window.matchMedia("(prefers-color-scheme: dark)").matches &&
localStorage.theme !== "light")
) {
@@ -24,7 +15,7 @@ const ThemeSwitcher: ThemeSwitcherStore = {
},
initButton() {
- const themeSwitcher = document.getElementById("theme-switcher");
+ let themeSwitcher = document.getElementById("theme-switcher");
themeSwitcher?.addEventListener("click", () => this.toggleTheme());
},
diff --git a/resources/themes/atom/views/client/nitro.blade.php b/resources/themes/atom/views/client/nitro.blade.php
index 5d2a66e..bc3d232 100755
--- a/resources/themes/atom/views/client/nitro.blade.php
+++ b/resources/themes/atom/views/client/nitro.blade.php
@@ -9,7 +9,7 @@
- @vite(['resources/themes/' . setting('theme') . '/css/app.css', 'resources/themes/' . setting('theme') . '/js/app.ts'], 'build')
+ @vite(['resources/themes/' . setting('theme') . '/css/app.css', 'resources/themes/' . setting('theme') . '/js/app.js'], 'build')