eslint, prettier, git hooks

This commit is contained in:
Jake Potrebic 2022-02-27 09:29:58 -08:00 committed by MiniDigger | Martin
parent 95b616048d
commit 33ac87664b
42 changed files with 1103 additions and 1354 deletions

View File

@ -15,9 +15,6 @@ ij_javascript_use_double_quotes = false
ij_sass_use_double_quotes = false
ij_html_quote_style = double
[**/locales/*.ts]
indent_size = 2
[*.java]
ij_java_insert_inner_class_imports = false
ij_java_use_fq_class_names = false

View File

@ -0,0 +1,8 @@
[*]
indent_size = 2
[{*.js, *.ts, *.vue}]
ij_javascript_use_double_quotes = true
ij_typescript_use_double_quotes = true
ij_javascript_enforce_trailing_comma = whenmultiline
ij_typescript_enforce_trailing_comma = whenmultiline

View File

@ -1,222 +0,0 @@
{
"globals": {
"acceptHMRUpdate": true,
"asyncComputed": true,
"autoResetRef": true,
"axios": true,
"biSyncRef": true,
"computed": true,
"computedInject": true,
"controlledComputed": true,
"controlledRef": true,
"createApp": true,
"createEventHook": true,
"createGlobalState": true,
"createPinia": true,
"createReactiveFn": true,
"createSharedComposable": true,
"createUnrefFn": true,
"customRef": true,
"debouncedRef": true,
"debouncedWatch": true,
"defineAsyncComponent": true,
"defineComponent": true,
"defineStore": true,
"eagerComputed": true,
"effectScope": true,
"EffectScope": true,
"extendRef": true,
"getActivePinia": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"ignorableWatch": true,
"inject": true,
"isDefined": true,
"isReadonly": true,
"isRef": true,
"makeDestructurable": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onClickOutside": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onKeyStroke": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onStartTyping": true,
"onUnmounted": true,
"onUpdated": true,
"pausableWatch": true,
"provide": true,
"reactify": true,
"reactifyObject": true,
"reactive": true,
"reactivePick": true,
"readonly": true,
"ref": true,
"refDefault": true,
"resolveComponent": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"storeToRefs": true,
"syncRef": true,
"templateRef": true,
"throttledRef": true,
"throttledWatch": true,
"toRaw": true,
"toReactive": true,
"toRef": true,
"toRefs": true,
"triggerRef": true,
"tryOnBeforeUnmount": true,
"tryOnMounted": true,
"tryOnScopeDispose": true,
"tryOnUnmounted": true,
"unref": true,
"unrefElement": true,
"until": true,
"useActiveElement": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
"useBase64": true,
"useBattery": true,
"useBreakpoints": true,
"useBroadcastChannel": true,
"useBrowserLocation": true,
"useClamp": true,
"useClipboard": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
"useCssModule": true,
"useCssVar": true,
"useCssVars": true,
"useCycleList": true,
"useDark": true,
"useDebounce": true,
"useDebouncedRefHistory": true,
"useDebounceFn": true,
"useDeviceMotion": true,
"useDeviceOrientation": true,
"useDevicePixelRatio": true,
"useDevicesList": true,
"useDisplayMedia": true,
"useDocumentVisibility": true,
"useDraggable": true,
"useElementBounding": true,
"useElementByPoint": true,
"useElementHover": true,
"useElementSize": true,
"useElementVisibility": true,
"useEventBus": true,
"useEventListener": true,
"useEventSource": true,
"useEyeDropper": true,
"useFavicon": true,
"useFetch": true,
"useFocus": true,
"useFocusWithin": true,
"useFps": true,
"useFullscreen": true,
"useGeolocation": true,
"useHead": true,
"useI18n": true,
"useIdle": true,
"useIntersectionObserver": true,
"useInterval": true,
"useIntervalFn": true,
"useKeyModifier": true,
"useLastChanged": true,
"useLocalStorage": true,
"useMagicKeys": true,
"useManualRefHistory": true,
"useMediaControls": true,
"useMediaQuery": true,
"useMemoize": true,
"useMemory": true,
"useMounted": true,
"useMouse": true,
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,
"useOnline": true,
"usePageLeave": true,
"useParallax": true,
"usePermission": true,
"usePointer": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
"useRoute": true,
"useRouter": true,
"useScreenSafeArea": true,
"useScriptTag": true,
"useScroll": true,
"useScrollLock": true,
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStorage": true,
"useStorageAsync": true,
"useStyleTag": true,
"useSwipe": true,
"useTemplateRefsList": true,
"useTextSelection": true,
"useThrottle": true,
"useThrottledRefHistory": true,
"useThrottleFn": true,
"useTimeAgo": true,
"useTimeout": true,
"useTimeoutFn": true,
"useTimestamp": true,
"useTitle": true,
"useToggle": true,
"useTransition": true,
"useUrlSearchParams": true,
"useUserMedia": true,
"useVibrate": true,
"useVirtualList": true,
"useVModel": true,
"useVModels": true,
"useWakeLock": true,
"useWebNotification": true,
"useWebSocket": true,
"useWebWorker": true,
"useWebWorkerFn": true,
"useWindowFocus": true,
"useWindowScroll": true,
"useWindowSize": true,
"watch": true,
"watchAtMost": true,
"watchEffect": true,
"watchOnce": true,
"watchWithFilter": true,
"whenever": true
}
}

91
frontend-new/.eslintrc.js Normal file
View File

@ -0,0 +1,91 @@
module.exports = {
root: true,
env: {
node: true,
browser: true,
"vue/setup-compiler-macros": true,
},
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
},
extends: [
"plugin:vue/vue3-recommended",
"eslint:recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"@vue/typescript/recommended",
"plugin:eslint-comments/recommended",
"prettier",
],
plugins: ["unicorn"],
settings: {
"import/resolver": {
node: {
extensions: [".js", ".ts", ".d.ts"],
},
alias: {
map: [["~", "./src/"]],
extensions: [".js", ".ts", ".d.ts", ".vue"],
},
},
"import/core-modules": ["windi.css", "virtual:generated-layouts", "virtual:generated-pages"],
},
rules: {
"eol-last": ["error", "always"],
"vue/multi-word-component-names": "off",
// TS
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off",
// unicorn
"unicorn/better-regex": "error",
"unicorn/empty-brace-spaces": "error",
"unicorn/escape-case": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-array-for-each": "error",
"unicorn/no-array-push-push": "error",
"unicorn/no-console-spaces": "error",
"unicorn/no-instanceof-array": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-unsafe-regex": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-array-flat": "error",
"unicorn/prefer-array-flat-map": "error",
"unicorn/prefer-array-index-of": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-at": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-default-parameters": "error",
"unicorn/prefer-dom-node-append": "error",
"unicorn/prefer-export-from": "error",
"unicorn/prefer-includes": "error",
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-set-has": "error",
"unicorn/prefer-spread": "error",
"unicorn/prefer-string-replace-all": "error",
"unicorn/prefer-switch": "error",
"unicorn/prefer-ternary": "error",
"unicorn/relative-url-style": "error",
"unicorn/throw-new-error": "error",
},
overrides: [
{
files: ".eslintrc.js",
rules: {
"unicorn/prefer-module": "off",
},
},
{
files: ["*.html"],
rules: {
"vue/comment-directive": "off",
},
},
],
};

6
frontend-new/.husky/pre-commit Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd frontend-new
pnpm lint-staged

View File

@ -2,4 +2,7 @@
/.cache/**
/dist/**
/tests/unit/coverage/**
**/.temp/**
**/.temp/**
pnpm-lock.yaml
.vscode/**
.idea/**

View File

@ -3,5 +3,6 @@
"semi": true,
"singleQuote": false,
"printWidth": 160,
"arrowParens": "always"
"arrowParens": "always",
"trailingComma": "es5"
}

View File

@ -1,78 +1,77 @@
{
"private": true,
"engines": {
"node": ">=16"
},
"scripts": {
"dev": "vite-ssr dev --port 3333",
"dev:spa": "vite --port 3333",
"build": "cross-env NODE_ENV=production vite-ssr build",
"preview": "vite-ssr --port 1337 --open",
"lint": "eslint --ext \".js,.vue,.ts,.json\" --ignore-path .gitignore --fix .",
"format": "prettier . --write"
},
"dependencies": {
"@headlessui/vue": "^1.5.0",
"@vueuse/core": "^7.5.5",
"@vueuse/head": "^0.7.5",
"@vueuse/integrations": "^7.5.5",
"axios": "^0.26.0",
"jwt-decode": "^3.1.2",
"nprogress": "^0.2.0",
"pinia": "^2.0.11",
"prism-theme-vars": "^0.2.2",
"qs": "^6.10.3",
"universal-cookie": "^4.0.4",
"vite-ssr": "^0.15.0",
"vue": "^3.2.31",
"vue-i18n": "^9.1.9",
"vue-router": "^4.0.12"
},
"devDependencies": {
"@antfu/eslint-config": "^0.16.1",
"@iconify/json": "^2.1.7",
"@intlify/vite-plugin-vue-i18n": "^3.3.0",
"@types/markdown-it-link-attributes": "^3.0.1",
"@types/nprogress": "^0.2.0",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.12.0",
"@vitejs/plugin-vue": "^2.2.0",
"@vue/compiler-sfc": "^3.2.31",
"@vue/server-renderer": "^3.2.31",
"cross-env": "^7.0.3",
"eslint": "^8.10.0",
"eslint-config-prettier": "^8.4.0",
"eslint-plugin-vue": "^8.5.0",
"markdown-it-link-attributes": "^4.0.0",
"markdown-it-prism": "^2.2.3",
"node-fetch": "^3.2.0",
"pnpm": "^6.32.1",
"prettier": "2.5.1",
"typescript": "^4.5.5",
"unplugin-auto-import": "^0.6.1",
"unplugin-icons": "^0.13.2",
"unplugin-vue-components": "^0.17.21",
"vite": "^2.7.13",
"vite-plugin-eslint": "^1.3.0",
"vite-plugin-md": "^0.11.8",
"vite-plugin-pages": "^0.20.2",
"vite-plugin-pwa": "^0.11.13",
"vite-plugin-vue-layouts": "^0.6.0",
"vite-plugin-windicss": "^1.7.1"
},
"//": "TODO steal from work",
"eslintConfig": {
"extends": [
"@antfu/eslint-config",
"prettier"
],
"env": {
"shared-node-browser": true
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"no-console": "off"
}
}
"private": true,
"engines": {
"node": ">=16"
},
"scripts": {
"dev": "vite-ssr dev --port 3333",
"dev:spa": "vite --port 3333",
"build": "cross-env NODE_ENV=production vite-ssr build",
"preview": "vite-ssr --port 1337 --open",
"lint:eslint": "eslint --ext \".js,.vue,.ts,.json,.html\" --ignore-path .gitignore --fix .",
"lint:prettier": "prettier -w .",
"prepare": "cd .. && husky install frontend-new/.husky"
},
"lint-staged": {
"*.{ts,js,vue,json,html}": [
"prettier -c",
"eslint"
]
},
"dependencies": {
"@headlessui/vue": "^1.5.0",
"@vueuse/core": "^7.5.5",
"@vueuse/head": "^0.7.5",
"@vueuse/integrations": "^7.5.5",
"axios": "^0.25.0",
"jwt-decode": "^3.1.2",
"nprogress": "^0.2.0",
"pinia": "^2.0.11",
"prism-theme-vars": "^0.2.2",
"qs": "^6.10.3",
"swagger-ui-dist": "^4.5.2",
"universal-cookie": "^4.0.4",
"vite-ssr": "^0.15.0",
"vue": "^3.2.29",
"vue-i18n": "^9.1.9",
"vue-router": "^4.0.12"
},
"devDependencies": {
"@iconify/json": "^2.0.33",
"@intlify/vite-plugin-vue-i18n": "^3.3.0",
"@types/markdown-it-link-attributes": "^3.0.1",
"@types/nprogress": "^0.2.0",
"@types/prettier": "^2.4.4",
"@types/qs": "^6.9.7",
"@vitejs/plugin-vue": "^2.1.0",
"@vue/compiler-sfc": "^3.2.29",
"@vue/eslint-config-typescript": "^10.0.0",
"@vue/server-renderer": "^3.2.29",
"cross-env": "^7.0.3",
"eslint": "^8.10.0",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-unicorn": "^41.0.0",
"eslint-plugin-vue": "^8.4.1",
"husky": "^7.0.4",
"lint-staged": "^12.3.4",
"markdown-it-link-attributes": "^4.0.0",
"markdown-it-prism": "^2.2.2",
"node-fetch": "^3.2.0",
"pnpm": "^6.29.1",
"prettier": "2.5.1",
"typescript": "^4.5.5",
"unplugin-auto-import": "^0.5.11",
"unplugin-icons": "^0.13.0",
"unplugin-vue-components": "^0.17.16",
"vite": "^2.7.13",
"vite-plugin-eslint": "^1.3.0",
"vite-plugin-md": "^0.11.7",
"vite-plugin-pages": "^0.20.1",
"vite-plugin-pwa": "^0.11.13",
"vite-plugin-vue-layouts": "^0.6.0",
"vite-plugin-windicss": "^1.6.3"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +1,70 @@
<script setup lang="ts">
import {useHead} from "@vueuse/head";
import {onMounted} from 'vue'
import { useRoute } from 'vue-router';
import {useSeo} from "~/composables/useSeo";
import {useThemeStore} from '~/store/theme'
import { useHead } from "@vueuse/head";
import { onMounted } from "vue";
import { useRoute } from "vue-router";
import { useSeo } from "~/composables/useSeo";
import { useThemeStore } from "~/store/theme";
const title = "Hangar New Test";
const description = "IDK WTF am doing";
useHead(useSeo(title, description, useRoute(), null));
const theme = useThemeStore()
const theme = useThemeStore();
onMounted(() => {
if (typeof window !== 'undefined') {
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
theme.enableDarkMode();
} else {
theme.disableDarkMode();
}
if (theme.darkMode) {
document.documentElement.classList.add('dark');
document.documentElement.classList.remove('light');
} else {
document.documentElement.classList.add('light');
document.documentElement.classList.remove('dark');
}
if (typeof window !== "undefined") {
if (localStorage.theme === "dark" || (!("theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
theme.enableDarkMode();
} else {
theme.disableDarkMode();
}
theme.$subscribe((mutation, state) => {
if (typeof window !== 'undefined') {
if (state.darkMode) {
localStorage.theme = 'dark';
document.documentElement.classList.add('dark');
document.documentElement.classList.remove('light');
} else {
localStorage.theme = 'light';
document.documentElement.classList.add('light');
document.documentElement.classList.remove('dark');
}
}
})
// For checking if on mobile or not
if(innerWidth <= theme.mobileBreakPoint && !theme.mobile){
theme.enableMobile();
}else if(innerWidth > theme.mobileBreakPoint && theme.mobile){
theme.disableMobile();
if (theme.darkMode) {
document.documentElement.classList.add("dark");
document.documentElement.classList.remove("light");
} else {
document.documentElement.classList.add("light");
document.documentElement.classList.remove("dark");
}
addEventListener('resize', () => {
if(innerWidth <= theme.mobileBreakPoint && !theme.mobile){
theme.enableMobile();
console.log(`Mobile: ${ theme.mobile}`)
}else if(innerWidth > theme.mobileBreakPoint && theme.mobile){
theme.disableMobile();
console.log(`Mobile: ${ theme.mobile}`)
}
})
})
}
theme.$subscribe((mutation, state) => {
if (typeof window !== "undefined") {
if (state.darkMode) {
localStorage.theme = "dark";
document.documentElement.classList.add("dark");
document.documentElement.classList.remove("light");
} else {
localStorage.theme = "light";
document.documentElement.classList.add("light");
document.documentElement.classList.remove("dark");
}
}
});
// For checking if on mobile or not
if (innerWidth <= theme.mobileBreakPoint && !theme.mobile) {
theme.enableMobile();
} else if (innerWidth > theme.mobileBreakPoint && theme.mobile) {
theme.disableMobile();
}
addEventListener("resize", () => {
if (innerWidth <= theme.mobileBreakPoint && !theme.mobile) {
theme.enableMobile();
console.log(`Mobile: ${theme.mobile}`);
} else if (innerWidth > theme.mobileBreakPoint && theme.mobile) {
theme.disableMobile();
console.log(`Mobile: ${theme.mobile}`);
}
});
});
</script>
<template>
<router-view v-slot="{ Component, route }">
<transition name="slide">
<component :is="Component" :key="route"/>
</transition>
</router-view>
<router-view v-slot="{ Component, route }">
<transition name="slide">
<component :is="Component" :key="route" />
</transition>
</router-view>
</template>

View File

@ -1,13 +1,13 @@
<script setup lang="ts">
import type {Announcement} from "hangar-api";
import { toRefs } from 'vue';
import type { Announcement } from "hangar-api";
import { toRefs } from "vue";
const props = defineProps<{ announcement: Announcement }>();
const {announcement} = toRefs(props);
const { announcement } = toRefs(props);
</script>
<template>
<div :style="'background-color:' + announcement.color" class="mb-2 p-2 text-center">
{{ announcement.text }}
</div>
<div :style="'background-color:' + announcement.color" class="mb-2 p-2 text-center">
{{ announcement.text }}
</div>
</template>

View File

@ -1,76 +1,61 @@
<script setup lang="ts"></script>
<template>
<footer
class="relative flex items-end mt-10 bg-gradient-to-r from-[#004ee9] to-[#367aff] px-8 pt-20 pb-2 text-[#f8faff] min-h-70">
<div class="footerContent w-screen">
<div
class="flex justify-center flex-col md:flex-row justify-center gap-y-6 md:gap-y-0 md:gap-x-6 max-w-1200px m-auto">
<div class="md:(w-1/3 min-w-1/3 max-w-1/3)">
<p class="text-xl font-bold text-center mb-2">About Hangar</p>
<p>Hangar is an NFT plugin repository, hosted in the blockchain. Every plugin is unique and owned
just by you. Can you use it on your server? No! You only own the receipt. And that's what makes
Hangar so eco-friendly.</p>
</div>
<div class="md:(w-1/3 min-w-1/3 max-w-1/3)">
<p class="text-xl font-bold text-center mb-2">Links</p>
<div class="flex flex-col items-center gap-y-3">
<router-link
:to="{ name: 'staff' }"
class="flex items-center justify-center rounded-md px-4 py-2 light:text-black background-body w-fit"
hover="text-primary-100"
>
Open Crypto Wallet
</router-link>
<router-link
:to="{ name: 'staff' }"
class="flex items-center justify-center rounded-md px-4 py-2 light:text-black background-body w-fit"
hover="text-primary-100"
>
Exchange Plugin NFTs
</router-link>
</div>
</div>
<div class="md:(w-1/3 min-w-1/3 max-w-1/3)">
<p class="text-xl font-bold text-center mb-2">More from Paper</p>
</div>
</div>
<div class="footerBar flex items-center justify-around mt-4 max-w-1200px m-auto">
<p>Copyright © <a href="https://papermc.io/">PaperMC</a> 2016 - 2022</p>
<div class="footerBarLinks flex">
<router-link
:to="{ name: 'staff' }"
class="flex items-center rounded-md px-6 py-2"
hover="text-primary-100 bg-primary-50"
>About Hangar
</router-link>
<router-link
:to="{ name: 'staff' }"
class="flex items-center rounded-md px-6 py-2"
hover="text-primary-100 bg-primary-50"
>Imprint
</router-link>
<router-link
:to="{ name: 'staff' }"
class="flex items-center rounded-md px-6 py-2"
hover="text-primary-100 bg-primary-50"
>Privacy Policy
</router-link>
</div>
</div>
<footer class="relative flex items-end mt-10 bg-gradient-to-r from-[#004ee9] to-[#367aff] px-8 pt-20 pb-2 text-[#f8faff] min-h-70">
<div class="footerContent w-screen">
<div class="flex justify-center flex-col md:flex-row justify-center gap-y-6 md:gap-y-0 md:gap-x-6 max-w-1200px m-auto">
<div class="md:(w-1/3 min-w-1/3 max-w-1/3)">
<p class="text-xl font-bold text-center mb-2">About Hangar</p>
<p>
Hangar is an NFT plugin repository, hosted in the blockchain. Every plugin is unique and owned just by you. Can you use it on your server? No! You
only own the receipt. And that's what makes Hangar so eco-friendly.
</p>
</div>
<div
class="footerShape absolute z-1 left-0 right-0 top-0 overflow-hidden pointer-events-none"
style="transform: scaleY(-1) scaleX(-1);">
<!--- <svg class="fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 218" preserveAspectRatio="none"><path d="M0 218h1200v-31.3l-40 4.4c-40 4.8-120 13.1-200 0-80-13.6-160-48.6-240-66.7-80-17.8-160-17.8-240-8.8-80 8.6-160 26.9-240 8.8-80-17.7-160-71.1-200-97.7L0 0v218z"></path></svg>
<div class="md:(w-1/3 min-w-1/3 max-w-1/3)">
<p class="text-xl font-bold text-center mb-2">Links</p>
<div class="flex flex-col items-center gap-y-3">
<router-link
:to="{ name: 'staff' }"
class="flex items-center justify-center rounded-md px-4 py-2 light:text-black background-body w-fit"
hover="text-primary-100"
>
Open Crypto Wallet
</router-link>
<router-link
:to="{ name: 'staff' }"
class="flex items-center justify-center rounded-md px-4 py-2 light:text-black background-body w-fit"
hover="text-primary-100"
>
Exchange Plugin NFTs
</router-link>
</div>
</div>
<div class="md:(w-1/3 min-w-1/3 max-w-1/3)">
<p class="text-xl font-bold text-center mb-2">More from Paper</p>
</div>
</div>
<div class="footerBar flex items-center justify-around mt-4 max-w-1200px m-auto">
<p>Copyright © <a href="https://papermc.io/">PaperMC</a> 2016 - 2022</p>
<div class="footerBarLinks flex">
<router-link :to="{ name: 'staff' }" class="flex items-center rounded-md px-6 py-2" hover="text-primary-100 bg-primary-50">About Hangar </router-link>
<router-link :to="{ name: 'staff' }" class="flex items-center rounded-md px-6 py-2" hover="text-primary-100 bg-primary-50">Imprint </router-link>
<router-link :to="{ name: 'staff' }" class="flex items-center rounded-md px-6 py-2" hover="text-primary-100 bg-primary-50"
>Privacy Policy
</router-link>
</div>
</div>
</div>
<div class="footerShape absolute z-1 left-0 right-0 top-0 overflow-hidden pointer-events-none" style="transform: scaleY(-1) scaleX(-1)">
<!--- <svg class="fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 218" preserveAspectRatio="none"><path d="M0 218h1200v-31.3l-40 4.4c-40 4.8-120 13.1-200 0-80-13.6-160-48.6-240-66.7-80-17.8-160-17.8-240-8.8-80 8.6-160 26.9-240 8.8-80-17.7-160-71.1-200-97.7L0 0v218z"></path></svg>
-->
<svg
class="fill-background-light-10 dark:fill-background-dark-80 h-240px min-w-full"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 218" preserveAspectRatio="none">
<path
d="M0 218h1200v-61.3l-40 0,961 V 0,480 C 268.5,456.5 537,433 857,433 C 1177,433 1548.5,456.5 1920,480 C 1920,480 1920,961 1920,961 Z"></path>
</svg>
</div>
</footer>
<svg
class="fill-background-light-10 dark:fill-background-dark-80 h-240px min-w-full"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1200 218"
preserveAspectRatio="none"
>
<path d="M0 218h1200v-61.3l-40 0,961 V 0,480 C 268.5,456.5 537,433 857,433 C 1177,433 1548.5,456.5 1920,480 C 1920,480 1920,961 1920,961 Z"></path>
</svg>
</div>
</footer>
</template>

View File

@ -1,212 +1,171 @@
<script setup lang="ts">
import type {Announcement as AnnouncementObject} from "hangar-api";
import {Popover, PopoverButton, PopoverPanel} from '@headlessui/vue'
import type {Ref} from 'vue';
import { useI18n } from 'vue-i18n';
import { ref } from 'vue';
import {useThemeStore} from '~/store/theme'
import {useAPI} from '~/store/api'
import Announcement from '~/components/Announcement.vue';
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/vue";
import type { Announcement as AnnouncementObject } from "hangar-api";
import type { Ref } from "vue";
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import Announcement from "~/components/Announcement.vue";
import { useAPI } from "~/store/api";
import { useThemeStore } from "~/store/theme";
const theme = useThemeStore()
const {t} = useI18n();
const theme = useThemeStore();
const { t } = useI18n();
const api = useAPI();
const empty: AnnouncementObject[] = [];
const announcements: Ref<AnnouncementObject[]> = ref(empty);
api.getAnnouncements().then((value) => {
if (value) {
const firstObject: AnnouncementObject | null = value[0];
if (firstObject) {
console.log(`Res: ${firstObject.text}`);
} else {
console.log("Res is undefined");
}
} else {
console.log("value is null");
}
api.getAnnouncements()
.then((value) => {
if (value) {
const firstObject: AnnouncementObject | null = value[0];
if (firstObject) {
console.log(`Res: ${firstObject.text}`)
} else {
console.log("Res is undefined")
}
} else {
console.log("value is null")
}
announcements.value = value;
});
announcements.value = value;
});
const navBarLinks = [
{link: 'index', label: 'Home'},
{link: 'staff', label: 'Team'},
{ link: "index", label: "Home" },
{ link: "staff", label: "Team" },
];
const loggedIn = false; // TODO
</script>
<template>
<template v-if="announcements">
<Announcement v-for="(announcement, idx) in announcements" :key="idx" :announcement="announcement"/>
</template>
<header class="background-header">
<div class="inner-header flex items-center max-w-1200px mx-auto justify-between h-65px w-[calc(100%-40px)]">
<div class="logo-and-nav flex items-center">
<Popover class="relative">
<PopoverButton v-slot="{ open }" class="flex mr-4">
<icon-mdi-menu
class="transition-transform text-[1.2em]"
:class="open
? 'transform rotate-90'
: ''"/>
</PopoverButton>
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="translate-y-1 opacity-0"
enter-to-class="translate-y-0 opacity-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="translate-y-0 opacity-100"
leave-to-class="translate-y-1 opacity-0"
>
<PopoverPanel
class="fixed md:absolute z-10 w-9/10 md:w-max background-header top-1/14 md:top-10 left-1/20 shadow1 rounded-md md:rounded-none md:rounded-bl-md md:rounded-r-md border-top-primary text-xs p-[20px]">
<p class="text-base font-semibold color-primary mb-4">Hangar</p>
<div class="grid grid-cols-2">
<router-link
:to="{ name: 'index' }"
class="flex items-center rounded-md px-6 py-2"
hover="text-primary-100 bg-primary-50"
>
<icon-mdi-home class="mr-3 text-[1.2em]"/>
Home
</router-link>
<router-link
:to="{ name: 'staff' }"
class="flex items-center rounded-md px-6 py-2"
hover="text-primary-100 bg-primary-50"
>
<icon-mdi-account-group class="mr-3 text-[1.2em]"/>
Team
</router-link>
</div>
<template v-if="announcements">
<Announcement v-for="(announcement, idx) in announcements" :key="idx" :announcement="announcement" />
</template>
<header class="background-header">
<div class="inner-header flex items-center max-w-1200px mx-auto justify-between h-65px w-[calc(100%-40px)]">
<div class="logo-and-nav flex items-center">
<Popover class="relative">
<PopoverButton v-slot="{ open }" class="flex mr-4">
<icon-mdi-menu class="transition-transform text-[1.2em]" :class="open ? 'transform rotate-90' : ''" />
</PopoverButton>
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="translate-y-1 opacity-0"
enter-to-class="translate-y-0 opacity-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="translate-y-0 opacity-100"
leave-to-class="translate-y-1 opacity-0"
>
<PopoverPanel
class="fixed md:absolute z-10 w-9/10 md:w-max background-header top-1/14 md:top-10 left-1/20 shadow1 rounded-md md:rounded-none md:rounded-bl-md md:rounded-r-md border-top-primary text-xs p-[20px]"
>
<p class="text-base font-semibold color-primary mb-4">Hangar</p>
<div class="grid grid-cols-2">
<router-link :to="{ name: 'index' }" class="flex items-center rounded-md px-6 py-2" hover="text-primary-100 bg-primary-50">
<icon-mdi-home class="mr-3 text-[1.2em]" />
Home
</router-link>
<router-link :to="{ name: 'staff' }" class="flex items-center rounded-md px-6 py-2" hover="text-primary-100 bg-primary-50">
<icon-mdi-account-group class="mr-3 text-[1.2em]" />
Team
</router-link>
</div>
<p class="text-base font-semibold color-primary mb-4 mt-10">More from Paper</p>
<div class="grid grid-cols-2">
<a
class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/"
hover="text-primary-100 bg-primary-50">
<icon-mdi-home class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.home") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2" href="https://forums.papermc.io/"
hover="text-primary-100 bg-primary-50">
<icon-mdi-forum class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.forums") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2" href="https://github.com/PaperMC"
hover="text-primary-100 bg-primary-50">
<icon-mdi-code-braces class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.code") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2"
href="https://paper.readthedocs.io/en/latest/"
hover="text-primary-100 bg-primary-50">
<icon-mdi-book-open class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.docs") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/javadocs"
hover="text-primary-100 bg-primary-50">
<icon-mdi-language-java class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.javadocs") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2" href="/"
hover="text-primary-100 bg-primary-50">
<icon-mdi-puzzle class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.hangar") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/downloads"
hover="text-primary-100 bg-primary-50">
<icon-mdi-download-circle class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.downloads") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/community"
hover="text-primary-100 bg-primary-50">
<icon-mdi-account-group class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.community") }}
</a>
<a
class="flex items-center rounded-md px-6 py-2"
href="https://hangar-auth.benndorf.dev/" hover="text-primary-100 bg-primary-50">
<icon-mdi-key class="mr-3 text-[1.2em]"/>
{{ t("nav.hangar.auth") }}
</a>
</div>
</PopoverPanel>
</transition>
</Popover>
<p class="text-base font-semibold color-primary mb-4 mt-10">More from Paper</p>
<div class="grid grid-cols-2">
<a class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/" hover="text-primary-100 bg-primary-50">
<icon-mdi-home class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.home") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://forums.papermc.io/" hover="text-primary-100 bg-primary-50">
<icon-mdi-forum class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.forums") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://github.com/PaperMC" hover="text-primary-100 bg-primary-50">
<icon-mdi-code-braces class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.code") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://paper.readthedocs.io/en/latest/" hover="text-primary-100 bg-primary-50">
<icon-mdi-book-open class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.docs") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/javadocs" hover="text-primary-100 bg-primary-50">
<icon-mdi-language-java class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.javadocs") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="/" hover="text-primary-100 bg-primary-50">
<icon-mdi-puzzle class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.hangar") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/downloads" hover="text-primary-100 bg-primary-50">
<icon-mdi-download-circle class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.downloads") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://papermc.io/community" hover="text-primary-100 bg-primary-50">
<icon-mdi-account-group class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.community") }}
</a>
<a class="flex items-center rounded-md px-6 py-2" href="https://hangar-auth.benndorf.dev/" hover="text-primary-100 bg-primary-50">
<icon-mdi-key class="mr-3 text-[1.2em]" />
{{ t("nav.hangar.auth") }}
</a>
</div>
</PopoverPanel>
</transition>
</Popover>
<div class="site-logo mr-4 h-60px flex items-center">
<img alt="Hangar Logo" src="../../public/logo.svg" class="h-50px object-cover"/>
</div>
<nav class="flex gap-3 invisible md:visible">
<router-link
v-for='navBarLink in navBarLinks'
:key='navBarLink.label'
:to="{ name: navBarLink.link }"
class="relative after:(absolute content-DEFAULT block w-0 top-30px left-1/10 h-4px rounded-8px)"
>
{{ navBarLink.label }}
</router-link>
</nav>
</div>
<div class="login-buttons flex gap-2 items-center">
<button class="flex mr-2" @click="theme.toggleDarkMode()">
<icon-mdi-weather-night v-if="theme.darkMode" class="text-[1.2em]"></icon-mdi-weather-night>
<icon-mdi-white-balance-sunny v-else class="text-[1.2em]"></icon-mdi-white-balance-sunny>
</button>
<div v-if="!loggedIn" class="flex">
<a
class="flex items-center rounded-md px-2 py-2"
href="https://hangar-auth.benndorf.dev/account/login" hover="text-primary-100 bg-primary-50">
<icon-mdi-key-outline class="mr-1 text-[1.2em]"/>
{{ t("nav.login") }}
</a>
<a
class="flex items-center rounded-md px-2 py-2"
href="https://hangar-auth.benndorf.dev/account/signup/" hover="text-primary-100 bg-primary-50">
<icon-mdi-clipboard-outline class="mr-1 text-[1.2em]"/>
{{ t("nav.signup") }}
</a>
</div>
</div>
<div class="site-logo mr-4 h-60px flex items-center">
<img alt="Hangar Logo" src="/logo.svg" class="h-50px object-cover" />
</div>
</header>
<nav class="flex gap-3 invisible md:visible">
<router-link
v-for="navBarLink in navBarLinks"
:key="navBarLink.label"
:to="{ name: navBarLink.link }"
class="relative after:(absolute content-DEFAULT block w-0 top-30px left-1/10 h-4px rounded-8px)"
>
{{ navBarLink.label }}
</router-link>
</nav>
</div>
<div class="login-buttons flex gap-2 items-center">
<button class="flex mr-2" @click="theme.toggleDarkMode()">
<icon-mdi-weather-night v-if="theme.darkMode" class="text-[1.2em]"></icon-mdi-weather-night>
<icon-mdi-white-balance-sunny v-else class="text-[1.2em]"></icon-mdi-white-balance-sunny>
</button>
<div v-if="!loggedIn" class="flex">
<a class="flex items-center rounded-md px-2 py-2" href="https://hangar-auth.benndorf.dev/account/login" hover="text-primary-100 bg-primary-50">
<icon-mdi-key-outline class="mr-1 text-[1.2em]" />
{{ t("nav.login") }}
</a>
<a class="flex items-center rounded-md px-2 py-2" href="https://hangar-auth.benndorf.dev/account/signup/" hover="text-primary-100 bg-primary-50">
<icon-mdi-clipboard-outline class="mr-1 text-[1.2em]" />
{{ t("nav.signup") }}
</a>
</div>
</div>
</div>
</header>
</template>
<style lang="css" scoped>
nav .router-link-active {
color: #4080FF;
font-weight: 700;
color: #4080ff;
font-weight: 700;
}
nav a.router-link-active:after {
background: linear-gradient(-270deg, #004ee9 0%, #367aff 100%);
transition: width .2s ease-in;
width: 80%;
background: linear-gradient(-270deg, #004ee9 0%, #367aff 100%);
transition: width 0.2s ease-in;
width: 80%;
}
nav a:not(.router-link-active):hover:after {
background: #d3e1f6;
transition: width .2s ease-in;
width: 80%;
background: #d3e1f6;
transition: width 0.2s ease-in;
width: 80%;
}
</style>

View File

@ -1,7 +1,7 @@
import type { HangarApiException } from "hangar-api";
import type { AxiosError, AxiosRequestConfig } from "axios";
import qs from "qs";
import { useCookies } from "@vueuse/integrations/useCookies";
import type { AxiosError, AxiosRequestConfig } from "axios";
import type { HangarApiException } from "hangar-api";
import qs from "qs";
import Cookies from "universal-cookie";
import { useApiToken } from "~/composables/useApiToken";
import { useAxios } from "~/composables/useAxios";
@ -75,21 +75,18 @@ export async function useInternalApi<T>(
headers: Record<string, string> = {}
): Promise<T> {
const token = await useApiToken(authed);
if (authed && !token) {
// eslint-disable-next-line prefer-promise-reject-errors
return Promise.reject({
isAxiosError: true,
response: {
data: {
isHangarApiException: true,
httpError: {
statusCode: 401,
},
message: "You must be logged in",
} as HangarApiException,
},
});
} else {
return request(`internal/${url}`, token, method, data, headers);
}
return authed && !token
? Promise.reject({
isAxiosError: true,
response: {
data: {
isHangarApiException: true,
httpError: {
statusCode: 401,
},
message: "You must be logged in",
} as HangarApiException,
},
})
: request(`internal/${url}`, token, method, data, headers);
}

View File

@ -35,11 +35,7 @@ function validateToken(token: string): boolean {
export function useApiToken(forceFetch = true): Promise<string | null> {
const store = useAuthStore();
if (store.token) {
if (validateToken(store.token)) {
return Promise.resolve(store.token);
} else {
return refreshToken();
}
return validateToken(store.token) ? Promise.resolve(store.token) : refreshToken();
} else if (forceFetch) {
return refreshToken();
} else {

View File

@ -2,13 +2,7 @@ import type { Ref } from "vue";
import { onDeactivated, onMounted, onUnmounted, ref } from "vue";
import { useContext } from "vite-ssr/vue";
export async function useInitialState<T>(
key: string,
handler: (type: "server" | "client") => Promise<T>,
blocking = false
) : Promise<Ref<T | null>> {
export async function useInitialState<T>(key: string, handler: (type: "server" | "client") => Promise<T>, blocking = false): Promise<Ref<T | null>> {
const { initialState } = useContext();
const responseValue = ref(initialState[key] || null) as Ref<T | null>;
@ -19,7 +13,6 @@ export async function useInitialState<T>(
}
};
onUnmounted(removeState);
onDeactivated(removeState);

View File

@ -1,5 +1,5 @@
import type { TranslateResult } from "vue-i18n";
import type { HeadObject } from "@vueuse/head";
import type { TranslateResult } from "vue-i18n";
import type { RouteLocationNormalizedLoaded } from "vue-router";
export function useSeo(
@ -112,11 +112,7 @@ function generateBreadcrumbs(route: RouteLocationNormalizedLoaded) {
}
function guessTitle(segment: string): string {
if (segment === "/" || segment === "") {
return "Hangar";
} else {
return segment;
}
return segment === "/" || segment === "" ? "Hangar" : segment;
}
function baseUrl(): string {

View File

@ -37,6 +37,6 @@ export const DEFAULT_LANGUAGE = SUPPORTED_LANGUAGES.find((l) => l.default);
export const DEFAULT_LOCALE = DEFAULT_LANGUAGE?.locale as string;
export function extractLocaleFromPath(path = "") {
const [_, maybeLocale] = path.split("/");
const maybeLocale = path.split("/")[1];
return SUPPORTED_LOCALES.includes(maybeLocale) ? maybeLocale : DEFAULT_LOCALE;
}

View File

@ -103,7 +103,7 @@
"mostDownloads": "Most Downloads",
"mostViews": "Most Views",
"newest": "Newest",
"recentlyUpdated": "Recently Updated",
"recentlyUpdated": "Recently Updated"
},
"category": {
"info": "Category",

View File

@ -1,14 +1,14 @@
<script setup lang="ts">
import Header from '~/components/Header.vue';
import Footer from '~/components/Footer.vue';
import Header from "~/components/Header.vue";
import Footer from "~/components/Footer.vue";
</script>
<template>
<main style="min-height: 60vh;">
<Header/>
<div style="min-height: 60vh;">
<router-view v-bind="$attrs"/>
</div>
<Footer/>
</main>
<main style="min-height: 60vh">
<Header />
<div style="min-height: 60vh">
<router-view v-bind="$attrs" />
</div>
<Footer />
</main>
</template>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"></script>
<template>
<main>Error</main>
<main>Error</main>
</template>

View File

@ -1,12 +1,12 @@
import "windi.css";
import "./styles/main.css";
import viteSSR, { ClientOnly } from "vite-ssr";
import { createHead } from "@vueuse/head";
import generatedRoutes from "virtual:generated-pages";
import { setupLayouts } from "virtual:generated-layouts";
import { createPinia } from "pinia";
import { setupLayouts } from "virtual:generated-layouts";
import generatedRoutes from "virtual:generated-pages";
import viteSSR, { ClientOnly } from "vite-ssr";
import "windi.css";
import App from "~/App.vue";
import { installI18n } from "~/i18n";
import "./styles/main.css";
const routes = setupLayouts(generatedRoutes);

View File

@ -1,167 +1,152 @@
<script setup lang="ts">
import {Menu, MenuButton, MenuItem, MenuItems} from "@headlessui/vue";
import { useI18n } from 'vue-i18n';
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/vue";
import { useI18n } from "vue-i18n";
const {t} = useI18n();
const { t } = useI18n();
const sorters = [
{id: 'stars', label: t("project.sorting.mostStars")},
{id: 'downloads', label: t("project.sorting.mostDownloads")},
{id: 'views', label: t("project.sorting.mostViews")},
{id: 'newest', label: t("project.sorting.newest")},
{id: 'updated', label: t("project.sorting.recentlyUpdated")},
{ id: "stars", label: t("project.sorting.mostStars") },
{ id: "downloads", label: t("project.sorting.mostDownloads") },
{ id: "views", label: t("project.sorting.mostViews") },
{ id: "newest", label: t("project.sorting.newest") },
{ id: "updated", label: t("project.sorting.recentlyUpdated") },
];
const versions = [
{version: '1.18.1'},
{version: '1.18'},
{version: '1.17.1'},
{version: '1.17'},
{version: '1.16.5'},
{version: '1.16.4'},
{version: '1.16.3'},
{version: '1.16.2'},
{version: '1.16.1'},
{version: '1.16'},
{ version: "1.18.1" },
{ version: "1.18" },
{ version: "1.17.1" },
{ version: "1.17" },
{ version: "1.16.5" },
{ version: "1.16.4" },
{ version: "1.16.3" },
{ version: "1.16.2" },
{ version: "1.16.1" },
{ version: "1.16" },
];
const categories = [
{id: 'admin_tools', label: t("project.category.admin_tools")},
{id: 'chat', label: t("project.category.chat")},
{id: 'devel_tools', label: t("project.category.dev_tools")},
{id: 'economy', label: t("project.category.economy")},
{id: 'gameplay', label: t("project.category.gameplay")},
{id: 'games', label: t("project.category.games")},
{id: 'protection', label: t("project.category.protection")},
{id: 'role_playing', label: t("project.category.role_playing")},
{id: 'world_management', label: t("project.category.world_management")},
{id: 'misc', label: t("project.category.misc")},
{ id: "admin_tools", label: t("project.category.admin_tools") },
{ id: "chat", label: t("project.category.chat") },
{ id: "devel_tools", label: t("project.category.dev_tools") },
{ id: "economy", label: t("project.category.economy") },
{ id: "gameplay", label: t("project.category.gameplay") },
{ id: "games", label: t("project.category.games") },
{ id: "protection", label: t("project.category.protection") },
{ id: "role_playing", label: t("project.category.role_playing") },
{ id: "world_management", label: t("project.category.world_management") },
{ id: "misc", label: t("project.category.misc") },
];
const platforms = [
{id: 'paper', label: 'Paper'},
{id: 'velocity', label: 'Velocity'},
{id: 'waterfall', label: 'Waterfall'},
{ id: "paper", label: "Paper" },
{ id: "velocity", label: "Velocity" },
{ id: "waterfall", label: "Waterfall" },
];
const licenses = [
{id: 'gpl-3', label: 'GPL-3'},
{id: 'mit', label: 'MIT'},
{id: 'apache', label: 'APACHE'},
{ id: "gpl-3", label: "GPL-3" },
{ id: "mit", label: "MIT" },
{ id: "apache", label: "APACHE" },
];
</script>
<template>
<div class="flex flex-col items-center pt-10">
<h2 class="text-3xl font-bold uppercase">Find your favorite plugins</h2>
<!-- Search Bar & Sorting button -->
<div class="flex flex-row mt-6 rounded-md big-box-shadow">
<!-- Search Bar -->
<input
class="rounded-l-md p-3 w-[80vw] max-w-800px focus-visible:(border-white) text-black" type="text"
placeholder="Search in 1 projects, proudly made by the community...">
<!-- Sorting Button -->
<div class="rounded-r-md w-100px bg-gradient-to-r from-[#004ee9] to-[#367aff]">
<Menu>
<MenuButton
class="rounded-r-md h-1/1 text-left font-semibold flex flex-row items-center gap-2 text-white p-2">
<span>Sort by</span>
<icon-mdi-sort-variant class="text-[1.2em] pointer-events-none overflow-hidden"/>
</MenuButton>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems
class="absolute flex flex-col z-10 background-header shadow1 rounded-md border-top-primary">
<MenuItem
v-for='sorter in sorters'
:key='sorter.id'
v-slot="{ active }">
<a
:class='{ "bg-gradient-to-r from-[#004ee9] to-[#367aff] text-white": active }'
class="p-2">
{{ sorter.label }}
</a>
</MenuItem>
</MenuItems>
</transition>
</Menu>
</div>
</div>
<div class="flex flex-col items-center pt-10">
<h2 class="text-3xl font-bold uppercase">Find your favorite plugins</h2>
<!-- Search Bar & Sorting button -->
<div class="flex flex-row mt-6 rounded-md big-box-shadow">
<!-- Search Bar -->
<input
class="rounded-l-md p-3 w-[80vw] max-w-800px focus-visible:(border-white) text-black"
type="text"
placeholder="Search in 1 projects, proudly made by the community..."
/>
<!-- Sorting Button -->
<div class="rounded-r-md w-100px bg-gradient-to-r from-[#004ee9] to-[#367aff]">
<Menu>
<MenuButton class="rounded-r-md h-1/1 text-left font-semibold flex flex-row items-center gap-2 text-white p-2">
<span>Sort by</span>
<icon-mdi-sort-variant class="text-[1.2em] pointer-events-none overflow-hidden" />
</MenuButton>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems class="absolute flex flex-col z-10 background-header shadow1 rounded-md border-top-primary">
<MenuItem v-for="sorter in sorters" :key="sorter.id" v-slot="{ active }">
<a :class="{ 'bg-gradient-to-r from-[#004ee9] to-[#367aff] text-white': active }" class="p-2">
{{ sorter.label }}
</a>
</MenuItem>
</MenuItems>
</transition>
</Menu>
</div>
</div>
<div
class="projectsAndSidebar p-4 mt-5 w-screen max-w-1200px flex justify-around m-auto flex-col md:flex-row gap-y-6 md:gap-y-0 md:gap-x-6">
<!-- Projects -->
<div class="md:(w-2/3 min-w-2/3 max-w-2/3) min-h-800px bg-gray-200 rounded-md">
</div>
<div class="projectsAndSidebar p-4 mt-5 w-screen max-w-1200px flex justify-around m-auto flex-col md:flex-row gap-y-6 md:gap-y-0 md:gap-x-6">
<!-- Projects -->
<div class="md:(w-2/3 min-w-2/3 max-w-2/3) min-h-800px bg-gray-200 rounded-md"></div>
<!-- Sidebar -->
<div class="flex flex-col gap-4 bg-gradient-to-r from-[#004ee9] to-[#367aff] rounded-md min-w-300px min-h-800px p-4 text-white">
<div class="versions">
<h3 class="font-bold">Minecraft versions</h3>
<div class="max-h-30 overflow-auto flex flex-col gap-2">
<label v-for="version in versions" :key="version.version" class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ version.version }}
<input :id="version.version" :name="version.version" type="checkbox" class="hidden" />
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"
/>
</label>
</div>
<!-- Sidebar -->
<div
class="flex flex-col gap-4 bg-gradient-to-r from-[#004ee9] to-[#367aff] rounded-md min-w-300px min-h-800px p-4 text-white">
<div class="versions">
<h3 class="font-bold">Minecraft versions</h3>
<div class="max-h-30 overflow-auto flex flex-col gap-2">
<label
v-for='version in versions' :key='version.version'
class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ version.version }}
<input :id='version.version' :name=version.version type="checkbox" class="hidden">
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"/>
</label>
</div>
</div>
<hr>
<div class="categories">
<h3 class="font-bold">Categories</h3>
<div class="flex flex-col gap-2">
<label
v-for='category in categories' :key='category.id'
class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ category.label }}
<input type="checkbox" class="hidden">
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"/>
</label>
</div>
</div>
<hr>
<div class="platforms">
<h3 class="font-bold">Platforms</h3>
<div class="flex flex-col gap-2">
<label
v-for='platform in platforms' :key='platform.id'
class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ platform.label }}
<input type="checkbox" class="hidden">
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"/>
</label>
</div>
</div>
<hr>
<div class="licenses">
<h3 class="font-bold">Licenses</h3>
<div class="flex flex-col gap-2">
<label
v-for='license in licenses' :key='license.id'
class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ license.label }}
<input type="checkbox" class="hidden">
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"/>
</label>
</div>
</div>
</div>
<hr />
<div class="categories">
<h3 class="font-bold">Categories</h3>
<div class="flex flex-col gap-2">
<label v-for="category in categories" :key="category.id" class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ category.label }}
<input type="checkbox" class="hidden" />
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"
/>
</label>
</div>
</div>
<hr />
<div class="platforms">
<h3 class="font-bold">Platforms</h3>
<div class="flex flex-col gap-2">
<label v-for="platform in platforms" :key="platform.id" class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ platform.label }}
<input type="checkbox" class="hidden" />
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"
/>
</label>
</div>
</div>
<hr />
<div class="licenses">
<h3 class="font-bold">Licenses</h3>
<div class="flex flex-col gap-2">
<label v-for="license in licenses" :key="license.id" class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ license.label }}
<input type="checkbox" class="hidden" />
<span
class="absolute top-5px left-0 h-15px w-15px rounded-sm bg-white group-hover:(bg-gray-300) after:(absolute hidden content-DEFAULT top-3px left-6px w-5px h-10px border-solid border-r-3px border-b-3px)"
/>
</label>
</div>
</div>
</div>
</div>
</template>
<route lang="yaml">
@ -170,19 +155,18 @@ meta:
</route>
<style lang="css" scoped>
.big-box-shadow {
box-shadow: 0 0 10px 0 #004ee99e;
box-shadow: 0 0 10px 0 #004ee99e;
}
/*This is needed, because you cannot have more than one parent group in tailwind/windi*/
.customCheckboxContainer input:checked ~ span {
background-color: #000 !important;
background-color: #000 !important;
}
/*The tailwind/windi utility class rotate-45 is BROKEN*/
.customCheckboxContainer input:checked ~ span:after {
display: block;
transform: rotate(45deg);
display: block;
transform: rotate(45deg);
}
</style>

View File

@ -1,3 +1,3 @@
<template>
<h1>Staff</h1>
<h1>Staff</h1>
</template>

View File

@ -0,0 +1,52 @@
import fs from "fs";
import path from "node:path";
import { getFileInfo, check, resolveConfig, format } from "prettier";
import qs from "qs";
import { Plugin } from "vite";
import { createFilter } from "@rollup/pluginutils";
export default function prettier(): Plugin {
const defaults = {
include: ["src/**/*.js", "src/**/*.ts", "src/**/*.vue", "src/**/*.html", "src/**/*.css", "src/**/*.json"],
};
const filter = createFilter(defaults.include, /node_modules/);
function normalize(id: string): string {
return path.relative(process.cwd(), id).split(path.sep).join("/");
}
function checkVueFile(id: string): boolean {
if (!id.includes("?")) return false;
const rawQuery = id.split("?", 2)[1];
return qs.parse(rawQuery).vue !== null;
}
return {
name: "vite:prettier",
async transform(_, id) {
const file = normalize(id);
const fileInfo = getFileInfo.sync(id);
if (!checkVueFile(id) && !fileInfo.ignored && filter(id)) {
const config = resolveConfig.sync(file);
if (config) {
if (!("parser" in config) && fileInfo.inferredParser) {
config.parser = fileInfo.inferredParser;
}
const source = fs.readFileSync(file, "utf-8");
if (source && !check(source, config)) {
this.warn(`${file} has formatting errors, fixing...`);
fs.writeFile(file, format(source, config), (err) => {
if (err) {
this.error(err);
}
});
}
}
}
return null;
},
};
}

View File

@ -1,5 +1,3 @@
/* eslint-disable import/no-duplicates */
declare interface Window {
// extend the window
}

View File

@ -1,16 +1,16 @@
import { defineStore } from "pinia";
import type { Ref} from "vue";
import type { Ref } from "vue";
import { ref } from "vue";
import type {Announcement as AnnouncementObject} from "hangar-api";
import {useInternalApi} from '~/composables/useApi';
import type { Announcement as AnnouncementObject } from "hangar-api";
import { useInternalApi } from "~/composables/useApi";
export const useAPI = defineStore("api", () => {
const announcements: Ref<AnnouncementObject | undefined> = ref();
const announcements: Ref<AnnouncementObject | undefined> = ref();
async function getAnnouncements(): Promise<AnnouncementObject[]> {
return await useInternalApi<AnnouncementObject[]>("data/announcements", false)
}
async function getAnnouncements(): Promise<AnnouncementObject[]> {
return await useInternalApi<AnnouncementObject[]>("data/announcements", false);
}
return { announcements, getAnnouncements };
return { announcements, getAnnouncements };
});

View File

@ -1,5 +1,5 @@
import type { HangarUser } from "hangar-internal";
import { defineStore } from 'pinia';
import { defineStore } from "pinia";
export const useAuthStore = defineStore("auth", {
state: () => {

View File

@ -1,5 +1,5 @@
import { defineStore } from "pinia";
import type { Ref} from "vue";
import type { Ref } from "vue";
import { ref, unref } from "vue";
export const useThemeStore = defineStore("theme", () => {
@ -9,7 +9,6 @@ export const useThemeStore = defineStore("theme", () => {
const mobileBreakPoint = 700;
function toggleDarkMode() {
darkMode.value = !unref(darkMode);
}
@ -22,17 +21,17 @@ export const useThemeStore = defineStore("theme", () => {
darkMode.value = false;
}
function toggleMobile() {
function toggleMobile() {
mobile.value = !unref(mobile);
}
}
function enableMobile() {
function enableMobile() {
mobile.value = true;
}
}
function disableMobile() {
function disableMobile() {
mobile.value = false;
}
}
return { darkMode, toggleDarkMode, enableDarkMode, disableDarkMode, mobile, toggleMobile, enableMobile, disableMobile, mobileBreakPoint };
});

View File

@ -2,51 +2,51 @@
/* TODO do we need this? */
#nprogress {
pointer-events: none;
pointer-events: none;
}
#nprogress .bar {
@apply bg-teal-600 opacity-75;
@apply bg-teal-600 opacity-75;
position: fixed;
z-index: 1031;
top: 0;
left: 0;
position: fixed;
z-index: 1031;
top: 0;
left: 0;
width: 100%;
height: 2px;
width: 100%;
height: 2px;
}
html {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-weight: 400;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
font-weight: 400;
}
.shadow1 {
box-shadow: 0 10px 20px rgb(0 0 0 / 15%), rgb(0 0 0 / 10%) 0 0 0 1px;
box-shadow: 0 10px 20px rgb(0 0 0 / 15%), rgb(0 0 0 / 10%) 0 0 0 1px;
}
.w-fit {
width: fit-content;
width: fit-content;
}
::-webkit-scrollbar {
width: 10px;
width: 10px;
}
* {
scrollbar-color: #004ee9 #f8faff;
scrollbar-width: thin;
scrollbar-color: #004ee9 #f8faff;
scrollbar-width: thin;
}
::-webkit-scrollbar-track {
background: #f8faff;
background: #f8faff;
}
::-webkit-scrollbar-thumb {
background: #004ee9;
background: #004ee9;
}
::-webkit-scrollbar-thumb:hover {
background: #111111;
background: #111111;
}

View File

@ -2,47 +2,47 @@
@import "prism-theme-vars/base.css";
:root {
--prism-font-family: "Input Mono", monospace;
--prism-font-family: "Input Mono", monospace;
}
html:not(.dark) {
--prism-foreground: #393a34;
--prism-background: #fbfbfb;
--prism-comment: #8e8f8e;
--prism-string: #a1644c;
--prism-literal: #3a9c9b;
--prism-keyword: #248358;
--prism-function: #7e8a42;
--prism-deleted: #a14f55;
--prism-class: #2b91af;
--prism-builtin: #a52727;
--prism-property: #ad502b;
--prism-namespace: #c96880;
--prism-punctuation: #8e8f8b;
--prism-decorator: #bd8f8f;
--prism-json-property: #698c96;
--prism-foreground: #393a34;
--prism-background: #fbfbfb;
--prism-comment: #8e8f8e;
--prism-string: #a1644c;
--prism-literal: #3a9c9b;
--prism-keyword: #248358;
--prism-function: #7e8a42;
--prism-deleted: #a14f55;
--prism-class: #2b91af;
--prism-builtin: #a52727;
--prism-property: #ad502b;
--prism-namespace: #c96880;
--prism-punctuation: #8e8f8b;
--prism-decorator: #bd8f8f;
--prism-json-property: #698c96;
}
html.dark {
--prism-scheme: dark;
--prism-foreground: #d4cfbf;
--prism-background: #1e1e1e;
--prism-comment: #758575;
--prism-string: #ce9178;
--prism-literal: #4fb09d;
--prism-keyword: #4d9375;
--prism-function: #c2c275;
--prism-deleted: #a14f55;
--prism-class: #5ebaa8;
--prism-builtin: #cb7676;
--prism-property: #dd8e6e;
--prism-namespace: #c96880;
--prism-punctuation: #d4d4d4;
--prism-decorator: #bd8f8f;
--prism-regex: #ab5e3f;
--prism-json-property: #6b8b9e;
--prism-line-number: #888888;
--prism-line-number-gutter: #eeeeee;
--prism-line-highlight-background: #444444;
--prism-selection-background: #444444;
--prism-scheme: dark;
--prism-foreground: #d4cfbf;
--prism-background: #1e1e1e;
--prism-comment: #758575;
--prism-string: #ce9178;
--prism-literal: #4fb09d;
--prism-keyword: #4d9375;
--prism-function: #c2c275;
--prism-deleted: #a14f55;
--prism-class: #5ebaa8;
--prism-builtin: #cb7676;
--prism-property: #dd8e6e;
--prism-namespace: #c96880;
--prism-punctuation: #d4d4d4;
--prism-decorator: #bd8f8f;
--prism-regex: #ab5e3f;
--prism-json-property: #6b8b9e;
--prism-line-number: #888888;
--prism-line-number-gutter: #eeeeee;
--prism-line-highlight-background: #444444;
--prism-selection-background: #444444;
}

View File

@ -26,14 +26,14 @@ declare module "hangar-api" {
}
interface Announcement {
text: String;
color: String;
text: string;
color: string;
}
interface Sponsor {
image: String;
name: String;
link: String;
image: string;
name: string;
link: string;
}
interface Visible {

View File

@ -33,7 +33,7 @@ declare module "hangar-api" {
stats: VersionStats;
fileInfo: FileInfo;
externalUrl: string | null;
author: String;
author: string;
reviewState: ReviewState;
tags: Tag[];
recommended: Platform[];

View File

@ -1,4 +1,3 @@
/* eslint-disable no-unused-vars */
export enum RoleCategory {
GLOBAL = "global",
PROJECT = "project",

View File

@ -0,0 +1,25 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
declare module "vue" {
export interface GlobalComponents {
IconMdiAccountGroup: typeof import("~icons/mdi/account-group")["default"];
IconMdiBookOpen: typeof import("~icons/mdi/book-open")["default"];
IconMdiClipboardOutline: typeof import("~icons/mdi/clipboard-outline")["default"];
IconMdiCodeBraces: typeof import("~icons/mdi/code-braces")["default"];
IconMdiDownloadCircle: typeof import("~icons/mdi/download-circle")["default"];
IconMdiForum: typeof import("~icons/mdi/forum")["default"];
IconMdiHome: typeof import("~icons/mdi/home")["default"];
IconMdiKey: typeof import("~icons/mdi/key")["default"];
IconMdiKeyOutline: typeof import("~icons/mdi/key-outline")["default"];
IconMdiLanguageJava: typeof import("~icons/mdi/language-java")["default"];
IconMdiMenu: typeof import("~icons/mdi/menu")["default"];
IconMdiPuzzle: typeof import("~icons/mdi/puzzle")["default"];
IconMdiSortVariant: typeof import("~icons/mdi/sort-variant")["default"];
IconMdiWeatherNight: typeof import("~icons/mdi/weather-night")["default"];
IconMdiWhiteBalanceSunny: typeof import("~icons/mdi/white-balance-sunny")["default"];
}
}
export {};

View File

@ -1,25 +0,0 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
declare module 'vue' {
export interface GlobalComponents {
IconMdiAccountGroup: typeof import('~icons/mdi/account-group')['default']
IconMdiBookOpen: typeof import('~icons/mdi/book-open')['default']
IconMdiClipboardOutline: typeof import('~icons/mdi/clipboard-outline')['default']
IconMdiCodeBraces: typeof import('~icons/mdi/code-braces')['default']
IconMdiDownloadCircle: typeof import('~icons/mdi/download-circle')['default']
IconMdiForum: typeof import('~icons/mdi/forum')['default']
IconMdiHome: typeof import('~icons/mdi/home')['default']
IconMdiKey: typeof import('~icons/mdi/key')['default']
IconMdiKeyOutline: typeof import('~icons/mdi/key-outline')['default']
IconMdiLanguageJava: typeof import('~icons/mdi/language-java')['default']
IconMdiMenu: typeof import('~icons/mdi/menu')['default']
IconMdiPuzzle: typeof import('~icons/mdi/puzzle')['default']
IconMdiSortVariant: typeof import('~icons/mdi/sort-variant')['default']
IconMdiWeatherNight: typeof import('~icons/mdi/weather-night')['default']
IconMdiWhiteBalanceSunny: typeof import('~icons/mdi/white-balance-sunny')['default']
}
}
export { }

View File

@ -1,5 +1,3 @@
declare module "swagger-ui" {
import { SwaggerUIBundle } from "swagger-ui-dist";
declare module "swagger-ui" {}
export default SwaggerUIBundle;
}
export { SwaggerUIBundle as default } from "swagger-ui-dist";

View File

@ -13,7 +13,7 @@
"noUnusedLocals": true,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"types": ["vite/client", "vite-plugin-pages/client", "vite-plugin-vue-layouts/client"],
"types": ["vite/client", "vite-plugin-pages/client", "vite-plugin-vue-layouts/client", "prettier"],
"paths": {
"~/*": ["src/*"]
}

View File

@ -1,20 +1,20 @@
import path from "path";
import { defineConfig } from "vite";
import Vue from "@vitejs/plugin-vue";
import Pages from "vite-plugin-pages";
import Layouts from "vite-plugin-vue-layouts";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import Icons from "unplugin-icons/vite";
import IconsResolver from "unplugin-icons/resolver";
import Markdown from "vite-plugin-md";
import WindiCSS from "vite-plugin-windicss";
import { VitePWA } from "vite-plugin-pwa";
import VueI18n from "@intlify/vite-plugin-vue-i18n";
import Prism from "markdown-it-prism";
import Vue from "@vitejs/plugin-vue";
import LinkAttributes from "markdown-it-link-attributes";
import viteSSR from "vite-ssr/plugin";
import Prism from "markdown-it-prism";
import path from "node:path";
import IconsResolver from "unplugin-icons/resolver";
import Icons from "unplugin-icons/vite";
import Components from "unplugin-vue-components/vite";
import { defineConfig } from "vite";
import EslintPlugin from "vite-plugin-eslint";
import Markdown from "vite-plugin-md";
import Pages from "vite-plugin-pages";
import { VitePWA } from "vite-plugin-pwa";
import Layouts from "vite-plugin-vue-layouts";
import WindiCSS from "vite-plugin-windicss";
import viteSSR from "vite-ssr/plugin";
import prettier from "./src/plugins/prettier";
const proxyHost = process.env.proxyHost || "http://localhost:8080";
const authHost = process.env.authHost || "http://localhost:3001";
@ -57,7 +57,7 @@ export default defineConfig({
},
}),
// https://github.com/antfu/vite-plugin-components
// https://github.com/antfu/unplugin-vue-components
Components({
// we don't want to import components, just icons
dirs: ["none"],
@ -66,18 +66,18 @@ export default defineConfig({
// https://github.com/antfu/vite-plugin-icons
IconsResolver({
componentPrefix: "icon",
enabledCollections: ["mdi"]
enabledCollections: ["mdi"],
}),
],
dts: "src/types/icons.d.ts",
dts: "src/types/generated/icons.d.ts",
}),
// https://github.com/antfu/vite-plugin-icons
// https://github.com/antfu/unplugin-icons
Icons({
autoInstall: true,
}),
// https://github.com/antfu/vite-plugin-windicss
// https://github.com/windicss/vite-plugin-windicss
WindiCSS({
safelist: "prose prose-sm m-auto",
}),
@ -111,7 +111,7 @@ export default defineConfig({
},
}),
// https://github.com/intlify/vite-plugin-vue-i18n
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
VueI18n({
include: [path.resolve(__dirname, "src/i18n/locales/*.json")],
}),
@ -119,6 +119,7 @@ export default defineConfig({
EslintPlugin({
fix: true,
}),
prettier(),
],
optimizeDeps: {

View File

@ -35,20 +35,20 @@ export default defineConfig({
},
},
colors: {
'background-dark-90': '#111111',
'background-dark-80': '#181a1b',
'background-light-10': '#f8faff',
'background-light-0': '#ffffff',
'primary-100': '#004ee9',
'primary-70': '#aec9ff',
'primary-50': '#ecf2fb'
"background-dark-90": "#111111",
"background-dark-80": "#181a1b",
"background-light-10": "#f8faff",
"background-light-0": "#ffffff",
"primary-100": "#004ee9",
"primary-70": "#aec9ff",
"primary-50": "#ecf2fb",
},
},
},
shortcuts: {
'background-header': 'bg-background-light-0 dark:bg-background-dark-90',
'background-body': 'bg-background-light-10 dark:bg-background-dark-80',
'color-primary': 'text-primary-100 dark:text-primary-70',
'border-top-primary': 'border-solid border-t-4 border-t-primary-100',
"background-header": "bg-background-light-0 dark:bg-background-dark-90",
"background-body": "bg-background-light-10 dark:bg-background-dark-80",
"color-primary": "text-primary-100 dark:text-primary-70",
"border-top-primary": "border-solid border-t-4 border-t-primary-100",
},
});