diff --git a/.gitignore b/.gitignore index 77ae667..8cab7ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ .DS_Store node_modules /dist - +/.nuxt +/.output +/.nitro # local env files .env.local diff --git a/README.md b/README.md index 00576f9..021649a 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,11 @@ ```sh # Project setup -yarn install +npm install # Compiles and hot-reloads for development -yarn serve +npm run dev + +# Generate static site +npm run generate ``` diff --git a/index.html b/index.html deleted file mode 100644 index 2f87c87..0000000 --- a/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - Home - - - - - -
- - - - - - diff --git a/nuxt.config.ts b/nuxt.config.ts new file mode 100644 index 0000000..542bf00 --- /dev/null +++ b/nuxt.config.ts @@ -0,0 +1,30 @@ +export default defineNuxtConfig({ + srcDir: 'src/', + ssr: true, + modules: ['@unocss/nuxt'], + css: ['@fortawesome/fontawesome-free/css/all.min.css'], + app: { + head: { + script: [ + { + src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js', + integrity: 'sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==', + crossorigin: 'anonymous', + referrerpolicy: 'no-referrer' + }, + { + src: 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js', + integrity: 'sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==', + crossorigin: 'anonymous', + referrerpolicy: 'no-referrer' + } + ] + } + }, + nitro: { + prerender: { + crawlLinks: true, + routes: ['/', '/about', '/life', '/blog', '/photo', '/others', '/kitchen-menu', '/friends', '/projects'] + } + } +}) diff --git a/package.json b/package.json index 19e984a..a1383e4 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,36 @@ { - "name": "home-page", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "vite", - "serve": "vite", - "build": "vue-tsc --noEmit && vite build" - }, - "dependencies": { - "@fortawesome/fontawesome-free": "^6.6.0", - "animsition": "^4.0.2", - "core-js": "^3.37.1", - "emoji-regex": "^10.3.0", - "linkify-urls": "^4.1.0", - "lxgw-wenkai-webfont": "^1.7.0", - "marked": "^4.3.0", - "moment": "^2.30.1", - "tg-blog": "^1.1.7", - "vue": "^3.4.35", - "vue-i18n": "^11.1.12", - "vue-router": "^4.4.0" - }, - "devDependencies": { - "@types/jquery": "^3.5.30", - "@types/jqueryui": "^1.12.23", - "@types/marked": "^4.3.2", - "@types/node": "^24.9.1", - "@vitejs/plugin-vue": "^6.0.1", - "eslint": "^9.8.0", - "sass": "^1.77.8", - "tslib": "^2.6.3", - "typescript": "^5.5.4", - "unocss": "^66.5.4", - "vite": "^7.1.12", - "vue-tsc": "3.1.1" - } + "name": "home-page", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "nuxt dev", + "build": "nuxt build", + "generate": "nuxt generate", + "preview": "nuxt preview", + "typecheck": "nuxt typecheck" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^6.6.0", + "animsition": "^4.0.2", + "emoji-regex": "^10.3.0", + "linkify-urls": "^4.1.0", + "lxgw-wenkai-webfont": "^1.7.0", + "marked": "^4.3.0", + "moment": "^2.30.1", + "tg-blog": "^1.1.7", + "vue-i18n": "^11.1.12", + "nuxt": "^4.4.2" + }, + "devDependencies": { + "@types/jquery": "^3.5.30", + "@types/jqueryui": "^1.12.23", + "@types/marked": "^4.3.2", + "@types/node": "^24.9.1", + "eslint": "^9.8.0", + "sass": "^1.77.8", + "tslib": "^2.6.3", + "typescript": "^5.5.4", + "unocss": "^66.5.4", + "@unocss/nuxt": "^66.6.8" + } } diff --git a/src/App.vue b/src/App.vue deleted file mode 100644 index ead0e85..0000000 --- a/src/App.vue +++ /dev/null @@ -1,266 +0,0 @@ - - - - - diff --git a/src/app.vue b/src/app.vue new file mode 100644 index 0000000..4057e8d --- /dev/null +++ b/src/app.vue @@ -0,0 +1,273 @@ + + + + + diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index 9d027ab..0000000 --- a/src/main.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {createApp, h} from 'vue' -import App from './App.vue' -import router from './scripts/router' -import {i18n} from "@/scripts/messages" -import '@fortawesome/fontawesome-free/css/all.min.css' -import Collapse from "@/components/Collapse.vue" -import BlogIndex from "@/components/BlogIndex.vue"; -import Tag from "@/components/Tag.vue"; -import 'virtual:uno.css' - -const app = createApp(App).use(router).use(i18n) - .component('Collapse', Collapse) - .component('BlogIndex', BlogIndex) - .component('Dynamic', { - props: ['template'], - render() { - return h({template: this.template}) - } - }) - .component('Tag', Tag) - -// app.config.performance = true -app.mount('#app') diff --git a/src/pages/about.vue b/src/pages/about.vue new file mode 100644 index 0000000..5d034d3 --- /dev/null +++ b/src/pages/about.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/blog.vue b/src/pages/blog.vue new file mode 100644 index 0000000..a9444d1 --- /dev/null +++ b/src/pages/blog.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/friends.vue b/src/pages/friends.vue new file mode 100644 index 0000000..7db9dad --- /dev/null +++ b/src/pages/friends.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/index.vue b/src/pages/index.vue new file mode 100644 index 0000000..3aa932f --- /dev/null +++ b/src/pages/index.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/kitchen-menu.vue b/src/pages/kitchen-menu.vue new file mode 100644 index 0000000..3a3044f --- /dev/null +++ b/src/pages/kitchen-menu.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/life.vue b/src/pages/life.vue new file mode 100644 index 0000000..9cb7e2e --- /dev/null +++ b/src/pages/life.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/others.vue b/src/pages/others.vue new file mode 100644 index 0000000..7b82b6d --- /dev/null +++ b/src/pages/others.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/photo/[id].vue b/src/pages/photo/[id].vue new file mode 100644 index 0000000..63c257f --- /dev/null +++ b/src/pages/photo/[id].vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/photo/index.vue b/src/pages/photo/index.vue new file mode 100644 index 0000000..63c257f --- /dev/null +++ b/src/pages/photo/index.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/projects.vue b/src/pages/projects.vue new file mode 100644 index 0000000..168af8b --- /dev/null +++ b/src/pages/projects.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts new file mode 100644 index 0000000..f552bd9 --- /dev/null +++ b/src/plugins/i18n.ts @@ -0,0 +1,12 @@ +import {createI18n} from 'vue-i18n' +import {messages, resolveLocale} from '@/scripts/messages' + +export default defineNuxtPlugin((nuxtApp) => { + const i18n = createI18n({ + messages, + locale: resolveLocale(), + fallbackLocale: 'en' + }) + + nuxtApp.vueApp.use(i18n) +}) diff --git a/src/scripts/constants.ts b/src/scripts/constants.ts index a5ffc78..db512db 100644 --- a/src/scripts/constants.ts +++ b/src/scripts/constants.ts @@ -1,11 +1,15 @@ const production = true export const hosts = { - api: 'https://profile-api.hydev.org', - content: production ? 'https://profile-content.hydev.org' : 'http://localhost:8082' + api: 'https://profile-api.hydev.org', + content: production ? 'https://profile-content.hydev.org' : 'http://localhost:8082' } -export const $ = (window as any).jQuery +export const $ = (...args: any[]) => { + const jquery = (globalThis as any).jQuery + if (!jquery) throw new Error('jQuery is not available') + return jquery(...args) +} export const fab = [ "monero", "hooli", "yelp", "cc-visa", "lastfm", "shopware", "creative-commons-nc", "aws", "redhat", "yoast", "cloudflare", "ups", "wpexplorer", "dyalog", "bity", "stackpath", "buysellads", "first-order", "modx", "guilded", "vnv", "square-js", "microsoft", "qq", "orcid", "java", "invision", "creative-commons-pd-alt", "centercode", "glide-g", "drupal", "hire-a-helper", "creative-commons-by", "unity", "whmcs", "rocketchat", "vk", "untappd", "mailchimp", "css3-alt", "square-reddit", "vimeo-v", "contao", "square-font-awesome", "deskpro", "sistrix", "square-instagram", "battle-net", "the-red-yeti", "square-hacker-news", "edge", "napster", "square-snapchat", "google-plus-g", "artstation", "markdown", "sourcetree", "google-plus", "diaspora", "foursquare", "stack-overflow", "github-alt", "phoenix-squadron", "pagelines", "algolia", "red-river", "creative-commons-sa", "safari", "google", "square-font-awesome-stroke", "atlassian", "linkedin-in", "digital-ocean", "nimblr", "chromecast", "evernote", "hacker-news", "creative-commons-sampling", "adversal", "creative-commons", "watchman-monitoring", "fonticons", "weixin", "shirtsinbulk", "codepen", "git-alt", "lyft", "rev", "windows", "wizards-of-the-coast", "square-viadeo", "meetup", "centos", "adn", "cloudsmith", "pied-piper-alt", "square-dribbble", "codiepie", "node", "mix", "steam", "cc-apple-pay", "scribd", "openid", "instalod", "expeditedssl", "sellcast", "square-twitter", "r-project", "delicious", "freebsd", "vuejs", "accusoft", "ioxhost", "fonticons-fi", "app-store", "cc-mastercard", "itunes-note", "golang", "kickstarter", "grav", "weibo", "uncharted", "firstdraft", "square-youtube", "wikipedia-w", "wpressr", "angellist", "galactic-republic", "nfc-directional", "skype", "joget", "fedora", "stripe-s", "meta", "laravel", "hotjar", "bluetooth-b", "sticker-mule", "creative-commons-zero", "hips", "behance", "reddit", "discord", "chrome", "app-store-ios", "cc-discover", "wpbeginner", "confluence", "mdb", "dochub", "accessible-icon", "ebay", "amazon", "unsplash", "yarn", "square-steam", "500px", "square-vimeo", "asymmetrik", "font-awesome", "gratipay", "apple", "hive", "gitkraken", "keybase", "apple-pay", "padlet", "amazon-pay", "square-github", "stumbleupon", "fedex", "phoenix-framework", "shopify", "neos", "hackerrank", "researchgate", "swift", "angular", "speakap", "angrycreative", "y-combinator", "empire", "envira", "square-gitlab", "studiovinari", "pied-piper", "wordpress", "product-hunt", "firefox", "linode", "goodreads", "square-odnoklassniki", "jsfiddle", "sith", "themeisle", "page4", "hashnode", "react", "cc-paypal", "squarespace", "cc-stripe", "creative-commons-share", "bitcoin", "keycdn", "opera", "itch-io", "umbraco", "galactic-senate", "ubuntu", "draft2digital", "stripe", "houzz", "gg", "dhl", "square-pinterest", "xing", "blackberry", "creative-commons-pd", "playstation", "quinscape", "less", "blogger-b", "opencart", "vine", "paypal", "gitlab", "typo3", "reddit-alien", "yahoo", "dailymotion", "affiliatetheme", "pied-piper-pp", "bootstrap", "odnoklassniki", "nfc-symbol", "ethereum", "speaker-deck", "creative-commons-nc-eu", "patreon", "avianex", "ello", "gofore", "bimobject", "facebook-f", "square-google-plus", "mandalorian", "first-order-alt", "osi", "google-wallet", "d-and-d-beyond", "periscope", "fulcrum", "cloudscale", "forumbee", "mizuni", "schlix", "square-xing", "bandcamp", "wpforms", "cloudversify", "usps", "megaport", "magento", "spotify", "optin-monster", "fly", "aviato", "itunes", "cuttlefish", "blogger", "flickr", "viber", "soundcloud", "digg", "tencent-weibo", "symfony", "maxcdn", "etsy", "facebook-messenger", "audible", "think-peaks", "bilibili", "erlang", "cotton-bureau", "dashcube", "42-group", "stack-exchange", "elementor", "square-pied-piper", "creative-commons-nd", "palfed", "superpowers", "resolving", "xbox", "searchengin", "tiktok", "square-facebook", "renren", "linux", "glide", "linkedin", "hubspot", "deploydog", "twitch", "ravelry", "mixer", "square-lastfm", "vimeo", "mendeley", "uniregistry", "figma", "creative-commons-remix", "cc-amazon-pay", "dropbox", "instagram", "cmplid", "facebook", "gripfire", "jedi-order", "uikit", "fort-awesome-alt", "phabricator", "ussunnah", "earlybirds", "trade-federation", "autoprefixer", "whatsapp", "slideshare", "google-play", "viadeo", "line", "google-drive", "servicestack", "simplybuilt", "bitbucket", "imdb", "deezer", "raspberry-pi", "jira", "docker", "screenpal", "bluetooth", "gitter", "d-and-d", "microblog", "cc-diners-club", "gg-circle", "pied-piper-hat", "kickstarter-k", "yandex", "readme", "html5", "sellsy", "sass", "wirsindhandwerk", "buromobelexperte", "salesforce", "octopus-deploy", "medapps", "ns8", "pinterest-p", "apper", "fort-awesome", "waze", "cc-jcb", "snapchat", "fantasy-flight-games", "rust", "wix", "square-behance", "supple", "rebel", "css3", "staylinked", "kaggle", "space-awesome", "deviantart", "cpanel", "goodreads-g", "square-git", "square-tumblr", "trello", "creative-commons-nc-jp", "get-pocket", "perbyte", "grunt", "weebly", "connectdevelop", "leanpub", "black-tie", "themeco", "python", "android", "bots", "free-code-camp", "hornbill", "js", "ideal", "git", "dev", "sketch", "yandex-international", "cc-amex", "uber", "github", "php", "alipay", "youtube", "skyatlas", "firefox-browser", "replyd", "suse", "jenkins", "twitter", "rockrms", "pinterest", "buffer", "npm", "yammer", "btc", "dribbble", "stumbleupon-circle", "internet-explorer", "telegram", "old-republic", "square-whatsapp", "node-js", "edge-legacy", "slack", "medrt", "usb", "tumblr", "vaadin", "quora", "reacteurope", "medium", "amilia", "mixcloud", "flipboard", "viacoin", "critical-role", "sitrox", "discourse", "joomla", "mastodon", "airbnb", "wolf-pack-battalion", "buy-n-large", "gulp", "creative-commons-sampling-plus", "strava", "ember", "canadian-maple-leaf", "teamspeak", "pushed", "wordpress-simple", "nutritionix", "wodu", "google-pay", "intercom", "zhihu", "korvue", "pix", "steam-symbol" diff --git a/src/scripts/messages.ts b/src/scripts/messages.ts index 0cc2949..65b307a 100644 --- a/src/scripts/messages.ts +++ b/src/scripts/messages.ts @@ -1,31 +1,19 @@ -import {createI18n} from "vue-i18n"; - export const messages = { - en: { - nav: { - home: 'Home', - about: '关于', - blog: '记事本', - life: '生活', - projects: 'Projects', - others: '更多', - photo: '相册' - } - }, - zh: { - // nav: { - // home: '温馨家', - // about: '关于我', - // blog: '部落格', - // projects: '我做的', - // } + en: { + nav: { + home: 'Home', + about: '关于', + blog: '记事本', + life: '生活', + projects: 'Projects', + others: '更多', + photo: '相册' } + }, + zh: {} } -export const i18n = createI18n({ - messages, - locale: navigator.language.split('-')[0], - fallbackLocale: 'en' -}) - -console.log(navigator.language) +export const resolveLocale = (): string => { + if (typeof navigator === 'undefined') return 'en' + return navigator.language.split('-')[0] +} diff --git a/src/scripts/router.ts b/src/scripts/router.ts index 9cc832a..c5d9754 100644 --- a/src/scripts/router.ts +++ b/src/scripts/router.ts @@ -1,88 +1,15 @@ -import {createRouter, createWebHistory, NavigationFailure, RouteRecordRaw} from 'vue-router' -import Home from '../views/Home.vue' +import {NavigationFailure, useRoute, useRouter} from 'vue-router' -const routes: Array = [ - { - path: '/', - name: 'Home', - meta: {title: 'Home', nav: true}, - component: Home - }, - { - path: '/about', - name: 'About', - meta: {title: '关于', nav: true}, - component: () => import('../views/About.vue') - }, - { - path: '/life', - name: 'Life', - meta: {title: '生活', nav: true}, - component: () => import('../views/Life.vue') - }, - { - path: '/blog', - name: 'Blog', - meta: {title: '记事本', nav: true}, - component: () => import('../views/Blog.vue'), - props: route => (route.query) - }, - { - path: '/photo', - name: 'Photo', - meta: {title: '相册', nav: true}, - component: () => import('../views/Photo.vue') - }, - { - path: '/photo/:id', - name: 'Photo ID', - meta: {title: '相册', navBookmark: 'Photo'}, - component: () => import('../views/Photo.vue') - }, - { - path: '/others', - name: 'Others', - meta: {title: '更多', nav: true}, - component: () => import('../views/Others.vue') - }, - { - path: '/kitchen-menu', - name: 'Menu', - meta: {title: '菜单', navBookmark: 'Others'}, - component: () => import('../views/others/Menu.vue') - }, - { - path: '/friends', - name: 'Friends', - meta: {title: '朋友们', navBookmark: 'Others'}, - component: () => import('../views/others/Friends.vue') - }, - { - path: '/projects', - name: 'Projects', - meta: {title: '我做的', navBookmark: 'Others'}, - component: () => import('../views/others/Projects.vue') - }, -] +export function pushQuery(query: {[id: string]: string | null}): Promise { + const route = useRoute() + const router = useRouter() -export const router = createRouter({ - history: createWebHistory(), - routes -}) + const queries = {...route.query} -export function pushQuery(query: {[id: string]: string | null}): Promise -{ - const queries = {...router.currentRoute.value.query ?? {}} + for (const k of Object.keys(query)) { + if (query[k] == null) delete queries[k] + else queries[k] = query[k] + } - console.log(query) - - for (const k of Object.keys(query)) - { - if (query[k] == null) delete queries[k] - else queries[k] = query[k] - } - - return router.push({query: queries}) + return router.push({query: queries}) } - -export default router diff --git a/src/views/Blog.vue b/src/views/Blog.vue index 766f9b4..b3dc0f2 100644 --- a/src/views/Blog.vue +++ b/src/views/Blog.vue @@ -1,18 +1,18 @@ @@ -64,11 +63,11 @@ const activePost = computed(() => { @use "../css/responsive" #breadcrumb - color: colors.$color-text-light - margin-bottom: 20px + color: colors.$color-text-light + margin-bottom: 20px - span:not(.no-after):after - content: ">" - margin: 0 10px + span:not(.no-after):after + content: ">" + margin: 0 10px diff --git a/tsconfig.json b/tsconfig.json index 1162ac1..a21bd59 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,41 +1,6 @@ { - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": false, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "paths": { - "@/*": [ - "src/*" - ] - }, - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ], - - "emitDecoratorMetadata": true, - "allowJs": true, - "resolveJsonModule": true - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - "src/**/*.vue", - "tests/**/*.ts", - "tests/**/*.tsx" - ], - "exclude": [ - "node_modules" - ] + "extends": "./.nuxt/tsconfig.json", + "compilerOptions": { + "types": ["@types/jquery", "@types/jqueryui"] + } } diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 5d22005..0000000 --- a/vite.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { defineConfig } from "vite"; -import vue from "@vitejs/plugin-vue"; -import UnoCSS from 'unocss/vite'; -import path from "path"; - -const src = path.resolve(__dirname, 'src') - -export default defineConfig({ - plugins: [ - vue(), UnoCSS() - ], - resolve: { - alias: { - '@': src, - - // Runtime compilation - vue: "vue/dist/vue.esm-bundler.js" - }, - dedupe: ['vue'], - }, - server: { - watch: { - usePolling: true - } - } -});