Skip to content

Commit

Permalink
use modules properly and clean up index file
Browse files Browse the repository at this point in the history
- move page theming to new file
- move tab data to new file
- rename some tab data fields to make more sense
- move method injection to new file
- clean up language variable names and code
- optimize route adding using flatMap
- remove and rename some unused/unneeded variables
- remove some more global components for speed
- add proper plurals for addon review page (and fix annoying console error)
  • Loading branch information
3vorp committed Dec 4, 2024
1 parent aaa7d91 commit e6958a6
Show file tree
Hide file tree
Showing 27 changed files with 509 additions and 561 deletions.
2 changes: 2 additions & 0 deletions components/fullscreen-modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
</template>

<script>
import { updatePageStyles } from "@helpers/colors.js";
export default {
name: "fullscreen-modal",
props: {
Expand Down
48 changes: 48 additions & 0 deletions helpers/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/** @type {Record<string, Record<string, string>>} */
const colors = (await import("https://cdn.jsdelivr.net/npm/vuetify@2.6.4/lib/util/colors.min.js"))
.default;

/** @param {string} color */
const colorToHex = (color) => {
const colorArr = color.trim().split(" ");

try {
colorArr[0] = colorArr[0].replace(/-./g, (x) => x[1].toUpperCase());
if (colorArr.length > 1) colorArr[1] = colorArr[1].replace("-", "");
return colors[colorArr[0]][colorArr.length > 1 ? colorArr[1] : "base"];
} catch (error) {
return "inherit";
}
};

/** @param {import("vue").Vue} page */
export const updatePageStyles = (page) => {
if (!page.$el) return;
page.$el.id ||= page.name;

const pageId = page.$el.id;
const hex = colorToHex(page.pageColor);

page.pageStyles = `
<style>
html.theme--light,
html.theme--light .colored,
html.theme--light .colored *,
html.theme--light .v-menu__content,
html.theme--light .v-menu__content *,
html.theme--light #${pageId},
html.theme--light #${pageId} * {
scrollbar-color: ${hex} #ffffffbb !important;
}
html.theme--dark,
html.theme--dark .colored,
html.theme--dark .colored *,
html.theme--dark .v-menu__content,
html.theme--dark .v-menu__content *,
html.theme--dark #${pageId},
html.theme--dark #${pageId} * {
scrollbar-color: ${hex} #000000bb !important;
}
</style>`;
};
189 changes: 189 additions & 0 deletions helpers/tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import axios from "axios";

// pages used in sidebar
import DashboardPage from "../pages/dashboard/main.vue";
import ProfilePage from "../pages/profile/main.vue";
import ContributorStatsPage from "../pages/contribution-stats/main.vue";
import GalleryPage from "../pages/gallery/main.vue";
import AddonSubmissionsPage from "../pages/addon/addon-submissions.vue";
import NewAddonPage from "../pages/addon/new-addon-form.vue";
import EditAddonPage from "../pages/addon/edit-addon-form.vue";
import ReviewAddonsPage from "../pages/review/main.vue";
import ReviewTranslationsPage from "../pages/translation/main.vue";
import PostListPage from "../pages/post/post-grid.vue";
import EditPostPage from "../pages/post/edit-post.vue";
import NewPostPage from "../pages/post/new-post.vue";
import ContributionPage from "../pages/contribution/main.vue";
import UsersPage from "../pages/users/main.vue";
import TexturePage from "../pages/texture/main.vue";
import PackPage from "../pages/pack/main.vue";
import SettingsPage from "../pages/settings/main.vue";

/** @type {import("resources/types.d.ts").SidebarTab[]} */
export default [
{
label: "general",
subtabs: [
{
label: "dashboard",
icon: "mdi-view-dashboard",
public: true,
// no name for dashboard (default page)
routes: [{ path: "/dashboard", component: DashboardPage }],
},
{
label: "profile",
icon: "mdi-account",
routes: [{ path: "/profile", component: ProfilePage, name: "Profile" }],
},
{
label: "statistics",
icon: "mdi-chart-timeline-variant",
public: true,
routes: [
{ path: "/contribution-stats", component: ContributorStatsPage, name: "Statistics" },
],
},
{
label: "gallery",
icon: "mdi-image-multiple",
public: true,
routes: [
{
path: "/gallery",
redirect: "/gallery/java/faithful_32x/latest/all/",
},
{
path: "/gallery/:edition/:pack/:version/:tag/:search*",
component: GalleryPage,
name: "Gallery",
},
],
},
],
},
{
label: "addons",
subtabs: [
{
label: "submissions",
icon: "mdi-folder-multiple",
routes: [
{
path: "/addons/submissions",
component: AddonSubmissionsPage,
name: "Add-on Submissions",
},
],
},
{
label: "upload",
icon: "mdi-upload",
routes: [
{ path: "/addons/new", component: NewAddonPage, name: "New Add-on" },
{ path: "/addons/edit/:id", component: EditAddonPage, name: "Edit Add-on" },
],
},
],
},
{
label: "review",
roles: ["Administrator"],
subtabs: [
{
label: "addons",
icon: "mdi-puzzle",
badge: (app) =>
axios.get(`${app.apiURL}/addons/pending`, app.apiOptions).then((r) => r.data.length || 0),
routes: [{ path: "/review/addons", component: ReviewAddonsPage, name: "Add-on Review" }],
},
{
label: "translations",
icon: "mdi-translate",
routes: [
{
path: "/review/translations",
component: ReviewTranslationsPage,
name: "Translations",
beforeEnter() {
location.href = "https://translate.faithfulpack.net/";
},
},
],
},
],
},
{
label: "posts",
roles: ["Administrator"],
subtabs: [
{
label: "list",
icon: "mdi-format-list-bulleted-square",
routes: [
{
path: "/posts/list",
component: PostListPage,
name: "All posts",
},
],
},
{
label: "create",
icon: "mdi-post",
routes: [
{
path: "/posts/new",
component: NewPostPage,
name: "New post",
},
{
path: "/posts/edit/:id",
component: EditPostPage,
name: "Edit post",
},
],
},
],
},
{
label: "database",
roles: ["Developer", "Administrator"],
subtabs: [
{
label: "contributions",
icon: "mdi-file-multiple",
routes: [{ path: "/contributions", component: ContributionPage, name: "Contributions" }],
},
{
label: "users",
icon: "mdi-account-multiple",
routes: [
{ path: "/users", redirect: "/users/all" },
{ path: "/users/:role?/:name*", component: UsersPage, name: "Users" },
],
},
{
label: "textures",
icon: "mdi-texture",
routes: [
{ path: "/textures", redirect: "/textures/all" },
{ path: "/textures/:tag?/:name*", component: TexturePage, name: "Textures" },
],
},
{
label: "packs",
icon: "mdi-cube",
routes: [
{ path: "/packs", redirect: "/packs/all" },
{ path: "/packs/:tag?/", component: PackPage, name: "Packs" },
],
},
{
label: "settings",
icon: "mdi-cog",
routes: [{ path: "/settings", component: SettingsPage, name: "Settings" }],
},
],
},
];
51 changes: 51 additions & 0 deletions helpers/utilityMethods.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Object.isObject = (item) => item && typeof item === "object" && !Array.isArray(item);

Object.merge = (target, ...sources) => {
if (!sources.length) return target;
const source = sources.shift();

if (Object.isObject(target) && Object.isObject(source)) {
for (const key in source) {
if (Object.isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
Object.merge(target[key], source[key]);
} else Object.assign(target, { [key]: source[key] });
}
}

return Object.merge(target, ...sources);
};

Object.equals = (x, y) => {
// primitives
if (x === y) return true;

// if one is an object and one is an array they can't be equal
if (!(Object.isObject(x) && Object.isObject(y)) && !(Array.isArray(x) && Array.isArray(y)))
return false;

// objects have to be same length
if (Object.keys(x).length != Object.keys(y).length) return false;

// if any property doesn't exist or isn't deep equal itself it can't be the same
if (Object.values(x).some((prop) => !y.hasOwnProperty(prop) || !Object.equals(x[prop], y[prop])))
return false;

return true;
};

String.prototype.toTitleCase = function () {
return this.split(/-|_| /g)
.map((word) => word[0].toUpperCase() + word.slice(1))
.join(" ");
};

String.urlRegex = new RegExp(
"^(https?:\\/\\/)?" + // protocol
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
"((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
"(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*" + // port and path
"(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
"(\\#[-a-z\\d_]*)?$", // fragment locator
"i",
);
Loading

0 comments on commit e6958a6

Please sign in to comment.