diff --git a/.gitignore b/.gitignore index 7f7e93c..cdc4bfc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules/ package-lock.json config.json -dist/ \ No newline at end of file +dist/ +*.sqlite \ No newline at end of file diff --git a/package.json b/package.json index ab9532c..75d7cae 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "tailwind": "npx tailwindcss -i ./src/client/public/css/main.css -o ./src/client/public/css/tailwind.css", - "build": "./build.sh", + "build": "./scripts/build.sh", "dev": "nodemon -r tsconfig-paths/register ./src/app.ts", "start": "node dist/app.js" }, @@ -28,10 +28,12 @@ "express": "^4.21.2", "express-session": "^1.18.1", "jquery": "^3.7.1", + "knex": "^3.1.0", "ncp": "^2.0.0", "passport": "^0.7.0", "passport-discord": "^0.1.4", "preline": "^2.7.0", + "sqlite3": "^5.1.7", "tsconfig-paths": "^4.2.0" }, "devDependencies": { diff --git a/build.sh b/scripts/build.sh similarity index 76% rename from build.sh rename to scripts/build.sh index a7c02e7..e733993 100755 --- a/build.sh +++ b/scripts/build.sh @@ -1,5 +1,7 @@ +cd "$(dirname "$0")/../" + echo "Erasing previous dist folder" -rm -r ./dist +rm -rf ./dist echo "Compiling tailwind css ..." npx tailwindcss -i ./src/client/public/css/main.css -o ./src/client/public/css/tailwind.css @@ -7,6 +9,9 @@ npx tailwindcss -i ./src/client/public/css/main.css -o ./src/client/public/css/t echo "Compiling typescript ..." npx tsc --project ./tsconfig.json +echo "Copying client files" +cp -r src/client dist/client + echo "Building typescript path aliases ..." npx tsc-alias -p ./tsconfig.json diff --git a/scripts/migrate.sh b/scripts/migrate.sh new file mode 100755 index 0000000..b9a17a7 --- /dev/null +++ b/scripts/migrate.sh @@ -0,0 +1,2 @@ +cd "$(dirname "$0")/../" +npx knex migrate:latest --knexfile ./src/knexfile.ts \ No newline at end of file diff --git a/scripts/seeds.sh b/scripts/seeds.sh new file mode 100755 index 0000000..8a05ff6 --- /dev/null +++ b/scripts/seeds.sh @@ -0,0 +1,2 @@ +cd "$(dirname "$0")/../" +npx knex seed:run --knexfile ./src/knexfile.ts \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 8b78ed6..773d396 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,3 +1,4 @@ +import path from "path"; import express from "express"; import engine from "ejs-mate"; import passport from "passport"; @@ -7,28 +8,29 @@ import dotenv from "dotenv"; dotenv.config(); import "@bot/bot"; -import { setupPassport } from "@server/controllers/auth"; +import { setupPassport } from "@server/controllers/auth.web.controller"; import { attachUser } from "@server/middleware/attachUser"; import { flashMiddleware } from "@server/middleware/flash"; import { ensureAuthenticated } from "@server/middleware/authenticated"; // import routers & middleware import { attachGuilds } from "@server/middleware/attachGuilds"; -import { router as homeRouter } from "@server/routes/home"; -import { router as guildRouter } from "@server/routes/guild"; -import { router as authRouter } from "@server/routes/auth"; +import homeWebRouter from "@server/routes/home.web.routes"; +import guildApiRouter from "@server/routes/guild.api.routes"; +import guildWebRouter from "@server/routes/guild.web.routes"; +import authWebRouter from "@server/routes/auth.web.routes"; const app = express(); app.engine("ejs", engine); -app.set("views", "./src/client/views"); +app.set("views", path.resolve(__dirname, "client/views")); app.set("view engine", "ejs"); // Public files, including 3rd party resources (foreign) -app.use("/static", express.static("./src/client/public")); -app.use("/static/foreign/preline.js", express.static("./node_modules/preline/dist/preline.js")); -app.use("/static/foreign/jquery.js", express.static("./node_modules/jquery/dist/jquery.min.js")); -app.use("/static/foreign/dataTables.js", express.static("./node_modules/datatables.net-dt/js/dataTables.dataTables.min.js")); +app.use("/static", express.static(path.resolve(__dirname, "client/public"))); +app.use("/static/foreign/preline.js", express.static(path.resolve(__dirname, "../node_modules/preline/dist/preline.js"))); +app.use("/static/foreign/jquery.js", express.static(path.resolve(__dirname, "../node_modules/jquery/dist/jquery.min.js"))); +app.use("/static/foreign/dataTables.js", express.static(path.resolve(__dirname, "../node_modules/datatables.net/js/dataTables.min.js"))); // User authentication & sessions app.use(session({ @@ -45,9 +47,9 @@ app.use(flash()); app.use(flashMiddleware); // register routers & middleware -app.use("/auth", authRouter); -app.use("/guild", ensureAuthenticated, attachUser, attachGuilds, guildRouter); -app.use("/", ensureAuthenticated, attachUser, attachGuilds, homeRouter); +app.use("/auth", authWebRouter); +app.use("/guild", ensureAuthenticated, attachUser, attachGuilds, guildWebRouter, guildApiRouter); +app.use("/", ensureAuthenticated, attachUser, attachGuilds, homeWebRouter); const PORT = process.env.PORT || 3000; diff --git a/src/bot/bot.ts b/src/bot/bot.ts index 25f2f33..4352bf9 100644 --- a/src/bot/bot.ts +++ b/src/bot/bot.ts @@ -14,7 +14,7 @@ client.on("ready", () => { throw Error("Client is null"); } - client.user.setActivity("Set Activity", { type: ActivityType.Watching }); + client.user.setActivity("new sources", { type: ActivityType.Watching }); console.log(`Discord Bot '${client.user.displayName}' is online!`) }); diff --git a/src/client/public/css/tailwind.css b/src/client/public/css/tailwind.css index 8c6455a..30bcad2 100644 --- a/src/client/public/css/tailwind.css +++ b/src/client/public/css/tailwind.css @@ -918,6 +918,10 @@ select { margin-inline-start: auto !important; } +.-me-0\.5 { + margin-inline-end: -0.125rem; +} + .-mt-px { margin-top: -1px; } @@ -1151,10 +1155,6 @@ select { width: 18rem; } -.w-\[100rem\] { - width: 100rem; -} - .w-\[260px\] { width: 260px; } @@ -1543,6 +1543,11 @@ select { background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); } +.bg-yellow-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 249 195 / var(--tw-bg-opacity, 1)); +} + .bg-opacity-50 { --tw-bg-opacity: 0.5; } @@ -1872,6 +1877,11 @@ select { color: rgb(255 255 255 / var(--tw-text-opacity, 1)); } +.text-yellow-800 { + --tw-text-opacity: 1; + color: rgb(133 77 14 / var(--tw-text-opacity, 1)); +} + .opacity-0 { opacity: 0; } @@ -2562,6 +2572,26 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te display: block; } +.dt-ordering-asc .hs-datatable-ordering-asc\:text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity, 1)); +} + +.dt-ordering-asc.hs-datatable-ordering-asc\:text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity, 1)); +} + +.dt-ordering-desc .hs-datatable-ordering-desc\:text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity, 1)); +} + +.dt-ordering-desc.hs-datatable-ordering-desc\:text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity, 1)); +} + .complete .hs-file-upload-complete\:bg-green-600 { --tw-bg-opacity: 1; background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1)); @@ -2830,6 +2860,10 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te background-color: rgb(20 184 166 / 0.1); } +.dark\:bg-yellow-500\/10:where(.dark, .dark *) { + background-color: rgb(234 179 8 / 0.1); +} + .dark\:bg-opacity-80:where(.dark, .dark *) { --tw-bg-opacity: 0.8; } @@ -2900,6 +2934,11 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te color: rgb(255 255 255 / 0.6); } +.dark\:text-yellow-500:where(.dark, .dark *) { + --tw-text-opacity: 1; + color: rgb(234 179 8 / var(--tw-text-opacity, 1)); +} + .dark\:placeholder-neutral-500:where(.dark, .dark *)::-moz-placeholder { --tw-placeholder-opacity: 1; color: rgb(115 115 115 / var(--tw-placeholder-opacity, 1)); @@ -2994,6 +3033,26 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te --tw-ring-offset-color: #1f2937; } +.dt-ordering-asc .dark\:hs-datatable-ordering-asc\:text-blue-500:where(.dark, .dark *) { + --tw-text-opacity: 1; + color: rgb(59 130 246 / var(--tw-text-opacity, 1)); +} + +.dt-ordering-asc.dark\:hs-datatable-ordering-asc\:text-blue-500:where(.dark, .dark *) { + --tw-text-opacity: 1; + color: rgb(59 130 246 / var(--tw-text-opacity, 1)); +} + +.dt-ordering-desc .dark\:hs-datatable-ordering-desc\:text-blue-500:where(.dark, .dark *) { + --tw-text-opacity: 1; + color: rgb(59 130 246 / var(--tw-text-opacity, 1)); +} + +.dt-ordering-desc.dark\:hs-datatable-ordering-desc\:text-blue-500:where(.dark, .dark *) { + --tw-text-opacity: 1; + color: rgb(59 130 246 / var(--tw-text-opacity, 1)); +} + .\[\&\:\:-webkit-scrollbar-thumb\]\:rounded-full::-webkit-scrollbar-thumb { border-radius: 9999px; } diff --git a/src/client/public/js/guild/subscriptions.js b/src/client/public/js/guild/subscriptions.js new file mode 100644 index 0000000..fcea348 --- /dev/null +++ b/src/client/public/js/guild/subscriptions.js @@ -0,0 +1,18 @@ + +// Filter by status +(function () { + const radioButtons = document.querySelectorAll('input[type="radio"][name="filter"]'); + const { dataTable } = new HSDataTable('#table'); + + dataTable.search.fixed('status', function (searchStr, data, index) { + const status = data[2].trim().toLowerCase(); // Adjust index based on your dataset + + if (radioButtons[0].checked && status === 'active') return true; + if (radioButtons[1].checked && status === 'inactive') return true; + return false; + }); + + radioButtons.forEach(radio => { + radio.addEventListener('change', () => dataTable.draw()); + }); +})(); diff --git a/src/client/views/guild/guildHeader.ejs b/src/client/views/guild/guildHeader.ejs index 2b46de8..9421840 100644 --- a/src/client/views/guild/guildHeader.ejs +++ b/src/client/views/guild/guildHeader.ejs @@ -1,5 +1,5 @@