refactor: resolve by one valaxy.config.ts

This commit is contained in:
YunYouJun 2022-07-18 03:30:33 +08:00
parent f3ab87f7a9
commit f27e23d38a
53 changed files with 663 additions and 500 deletions

View File

@ -1,5 +1,5 @@
{
"cSpell.words": ["algoliasearch", "instantsearch", "valaxy", "valaxyjs", "beian", "jiti", "defu"],
"cSpell.words": ["algoliasearch", "instantsearch", "valaxy", "valaxyjs", "beian", "jiti", "defu", "twikoo"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": ["packages/valaxy/src/client/locales"],

View File

@ -1,5 +1,8 @@
{
"name": "yun-demo",
"slidev": {
"theme": "yun"
},
"scripts": {
"build": "npm run build:ssg && npm run rss",
"build:spa": "valaxy build",

View File

@ -1,184 +0,0 @@
import { defineSite } from 'valaxy'
import type { ThemeConfig } from 'valaxy-theme-yun'
/**
* Blog Config
* do not use export const config to avoid defu conflict
*/
export default defineSite<ThemeConfig>({
lang: 'zh-CN',
title: 'Valaxy Theme Yun',
url: 'https://valaxy.yyj.moe/',
author: {
avatar: 'https://www.yunyoujun.cn/images/avatar.jpg',
name: '云游君',
},
description: 'Valaxy Theme Yun Preview.',
social: [
{
name: 'RSS',
link: '/atom.xml',
icon: 'i-ri-rss-line',
color: 'orange',
},
{
name: 'QQ 群 1050458482',
link: 'https://qm.qq.com/cgi-bin/qm/qr?k=kZJzggTTCf4SpvEQ8lXWoi5ZjhAx0ILZ&jump_from=webapi',
icon: 'i-ri-qq-line',
color: '#12B7F5',
},
{
name: 'GitHub',
link: 'https://github.com/YunYouJun',
icon: 'i-ri-github-line',
color: '#6e5494',
},
{
name: '微博',
link: 'https://weibo.com/jizhideyunyoujun',
icon: 'i-ri-weibo-line',
color: '#E6162D',
},
{
name: '豆瓣',
link: 'https://www.douban.com/people/yunyoujun/',
icon: 'i-ri-douban-line',
color: '#007722',
},
{
name: '网易云音乐',
link: 'https://music.163.com/#/user/home?id=247102977',
icon: 'i-ri-netease-cloud-music-line',
color: '#C20C0C',
},
{
name: '知乎',
link: 'https://www.zhihu.com/people/yunyoujun/',
icon: 'i-ri-zhihu-line',
color: '#0084FF',
},
{
name: '哔哩哔哩',
link: 'https://space.bilibili.com/1579790',
icon: 'i-ri-bilibili-line',
color: '#FF8EB3',
},
{
name: '微信公众号',
link: 'https://cdn.yunyoujun.cn/img/about/white-qrcode-and-search.jpg',
icon: 'i-ri-wechat-2-line',
color: '#1AAD19',
},
{
name: 'Twitter',
link: 'https://twitter.com/YunYouJun',
icon: 'i-ri-twitter-line',
color: '#1da1f2',
},
{
name: 'Telegram Channel',
link: 'https://t.me/elpsycn',
icon: 'i-ri-telegram-line',
color: '#0088CC',
},
{
name: 'E-Mail',
link: 'mailto:me@yunyoujun.cn',
icon: 'i-ri-mail-line',
color: '#8E71C1',
},
{
name: 'Travelling',
link: 'https://travellings.link',
icon: 'i-ri-train-line',
color: 'var(--va-c-text)',
},
],
search: {
enable: true,
algolia: {
enable: true,
appId: 'UVMHTMG1T5',
apiKey: '805f2584a8866388aa1631ff0348ddae',
indexName: 'valaxy',
// test
// appId: 'BH4D9OD16A',
// apiKey: '978ef82b43148b59dc771ea53b7a56af',
// indexName: 'elpsy',
},
},
comment: {
enable: true,
waline: {
enable: true,
serverURL: 'https://waline.yunyoujun.cn',
},
twikoo: {
// enable: true,
envId: 'https://twikoo.vercel.app',
},
},
sponsor: {
enable: true,
methods: [
{
name: '支付宝',
url: 'https://cdn.yunyoujun.cn/img/donate/alipay-qrcode.jpg',
color: '#00A3EE',
icon: 'i-ri-alipay-line',
},
{
name: 'QQ 支付',
url: 'https://cdn.yunyoujun.cn/img/donate/qqpay-qrcode.png',
color: '#12B7F5',
icon: 'i-ri-qq-line',
},
{
name: '微信支付',
url: 'https://cdn.yunyoujun.cn/img/donate/wechatpay-qrcode.jpg',
color: '#2DC100',
icon: 'i-ri-wechat-pay-line',
},
],
},
theme: 'yun',
themeConfig: {
// colors: {
// primary: 'red',
// },
banner: {
enable: true,
title: '云游君的小站',
},
pages: [
{
name: '我的小伙伴们',
url: '/links/',
icon: 'i-ri-genderless-line',
color: 'dodgerblue',
},
{
name: '喜欢的女孩子',
url: '/girls/',
icon: 'i-ri-women-line',
color: 'hotpink',
},
],
footer: {
since: 2016,
beian: {
enable: true,
icp: '苏ICP备17038157号',
},
},
},
})

View File

@ -1,20 +1,200 @@
import { defineConfig } from 'valaxy'
import type { ThemeConfig } from 'valaxy-theme-yun'
// import { VitePWA } from 'vite-plugin-pwa'
import Inspect from 'vite-plugin-inspect'
// import site from './site.config'
const safelist = [
'i-ri-home-line',
]
export default defineConfig({
export default defineConfig<ThemeConfig>({
lang: 'zh-CN',
title: 'Valaxy Theme Yun',
url: 'https://valaxy.yyj.moe/',
author: {
avatar: 'https://www.yunyoujun.cn/images/avatar.jpg',
name: '云游君',
},
description: 'Valaxy Theme Yun Preview.',
social: [
{
name: 'RSS',
link: '/atom.xml',
icon: 'i-ri-rss-line',
color: 'orange',
},
{
name: 'QQ 群 1050458482',
link: 'https://qm.qq.com/cgi-bin/qm/qr?k=kZJzggTTCf4SpvEQ8lXWoi5ZjhAx0ILZ&jump_from=webapi',
icon: 'i-ri-qq-line',
color: '#12B7F5',
},
{
name: 'GitHub',
link: 'https://github.com/YunYouJun',
icon: 'i-ri-github-line',
color: '#6e5494',
},
{
name: '微博',
link: 'https://weibo.com/jizhideyunyoujun',
icon: 'i-ri-weibo-line',
color: '#E6162D',
},
{
name: '豆瓣',
link: 'https://www.douban.com/people/yunyoujun/',
icon: 'i-ri-douban-line',
color: '#007722',
},
{
name: '网易云音乐',
link: 'https://music.163.com/#/user/home?id=247102977',
icon: 'i-ri-netease-cloud-music-line',
color: '#C20C0C',
},
{
name: '知乎',
link: 'https://www.zhihu.com/people/yunyoujun/',
icon: 'i-ri-zhihu-line',
color: '#0084FF',
},
{
name: '哔哩哔哩',
link: 'https://space.bilibili.com/1579790',
icon: 'i-ri-bilibili-line',
color: '#FF8EB3',
},
{
name: '微信公众号',
link: 'https://cdn.yunyoujun.cn/img/about/white-qrcode-and-search.jpg',
icon: 'i-ri-wechat-2-line',
color: '#1AAD19',
},
{
name: 'Twitter',
link: 'https://twitter.com/YunYouJun',
icon: 'i-ri-twitter-line',
color: '#1da1f2',
},
{
name: 'Telegram Channel',
link: 'https://t.me/elpsycn',
icon: 'i-ri-telegram-line',
color: '#0088CC',
},
{
name: 'E-Mail',
link: 'mailto:me@yunyoujun.cn',
icon: 'i-ri-mail-line',
color: '#8E71C1',
},
{
name: 'Travelling',
link: 'https://travellings.link',
icon: 'i-ri-train-line',
color: 'var(--va-c-text)',
},
],
search: {
enable: true,
algolia: {
enable: true,
appId: 'UVMHTMG1T5',
apiKey: '805f2584a8866388aa1631ff0348ddae',
indexName: 'valaxy',
// test
// appId: 'BH4D9OD16A',
// apiKey: '978ef82b43148b59dc771ea53b7a56af',
// indexName: 'elpsy',
},
},
comment: {
enable: true,
waline: {
enable: true,
serverURL: 'https://waline.yunyoujun.cn',
},
twikoo: {
// enable: true,
envId: 'https://twikoo.vercel.app',
},
},
sponsor: {
enable: true,
methods: [
{
name: '支付宝',
url: 'https://cdn.yunyoujun.cn/img/donate/alipay-qrcode.jpg',
color: '#00A3EE',
icon: 'i-ri-alipay-line',
},
{
name: 'QQ 支付',
url: 'https://cdn.yunyoujun.cn/img/donate/qqpay-qrcode.png',
color: '#12B7F5',
icon: 'i-ri-qq-line',
},
{
name: '微信支付',
url: 'https://cdn.yunyoujun.cn/img/donate/wechatpay-qrcode.jpg',
color: '#2DC100',
icon: 'i-ri-wechat-pay-line',
},
],
},
theme: 'yun',
themeConfig: {
// colors: {
// primary: 'red',
// },
banner: {
enable: true,
title: '云游君的小站',
},
pages: [
{
name: '我的小伙伴们',
url: '/links/',
icon: 'i-ri-genderless-line',
color: 'dodgerblue',
},
{
name: '喜欢的女孩子',
url: '/girls/',
icon: 'i-ri-women-line',
color: 'hotpink',
},
],
footer: {
since: 2016,
beian: {
enable: true,
icp: '苏ICP备17038157号',
},
},
},
vite: {
// https://github.com/antfu/vite-plugin-inspect
// Visit http://localhost:3333/__inspect/ to see the inspector
plugins: [Inspect()],
},
unocss: {
safelist,
},
markdown: {
blocks: {
tip: {

View File

@ -27,4 +27,4 @@ features:
details: Go wild with true SSG + SPA architecture. Static on page load, but engage users with 100% interactivity from there.
---
<div m="t-8" class="text-center" text="4xl">WORK IN PROGRESS</div>
<div m="y-8" text="center 4xl" font="black">🧪 <br /><br />WORK IN PROGRESS</div>

View File

@ -74,10 +74,10 @@ Valaxy 决定中心化地提供各类封装好的评论钩子函数。
```vue {2}
<script lang="ts" setup>
import { useSite, useWaline } from 'valaxy'
import { useConfig, useWaline } from 'valaxy'
// 读取用户配置
const config = useSite()
const config = useConfig()
// 挂载 Waline
useWaline(config.value.comment.waline)
</script>

View File

@ -3,6 +3,7 @@ import { defineSite } from 'valaxy'
export default defineSite({
title: 'Valaxy',
url: 'https://valaxy.site',
description: 'Valaxy Site Docs',
theme: 'press',
themeConfig: {},

View File

@ -1,4 +1,5 @@
import { defineConfig } from 'valaxy'
import type { ThemeConfig } from 'valaxy-theme-yun'
// add icons what you will need
const safelist = [
@ -8,6 +9,154 @@ const safelist = [
/**
* User Config
*/
export default defineConfig({
export default defineConfig<ThemeConfig>({
lang: 'zh-CN',
title: 'Valaxy Theme Yun',
author: {
name: '云游君',
},
description: 'Valaxy Theme Yun Preview.',
social: [
{
name: 'RSS',
link: '/atom.xml',
icon: 'i-ri-rss-line',
color: 'orange',
},
{
name: 'QQ 群 1050458482',
link: 'https://qm.qq.com/cgi-bin/qm/qr?k=kZJzggTTCf4SpvEQ8lXWoi5ZjhAx0ILZ&jump_from=webapi',
icon: 'i-ri-qq-line',
color: '#12B7F5',
},
{
name: 'GitHub',
link: 'https://github.com/YunYouJun',
icon: 'i-ri-github-line',
color: '#6e5494',
},
{
name: '微博',
link: 'https://weibo.com/jizhideyunyoujun',
icon: 'i-ri-weibo-line',
color: '#E6162D',
},
{
name: '豆瓣',
link: 'https://www.douban.com/people/yunyoujun/',
icon: 'i-ri-douban-line',
color: '#007722',
},
{
name: '网易云音乐',
link: 'https://music.163.com/#/user/home?id=247102977',
icon: 'i-ri-netease-cloud-music-line',
color: '#C20C0C',
},
{
name: '知乎',
link: 'https://www.zhihu.com/people/yunyoujun/',
icon: 'i-ri-zhihu-line',
color: '#0084FF',
},
{
name: '哔哩哔哩',
link: 'https://space.bilibili.com/1579790',
icon: 'i-ri-bilibili-line',
color: '#FF8EB3',
},
{
name: '微信公众号',
link: 'https://cdn.yunyoujun.cn/img/about/white-qrcode-and-search.jpg',
icon: 'i-ri-wechat-2-line',
color: '#1AAD19',
},
{
name: 'Twitter',
link: 'https://twitter.com/YunYouJun',
icon: 'i-ri-twitter-line',
color: '#1da1f2',
},
{
name: 'Telegram Channel',
link: 'https://t.me/elpsycn',
icon: 'i-ri-telegram-line',
color: '#0088CC',
},
{
name: 'E-Mail',
link: 'mailto:me@yunyoujun.cn',
icon: 'i-ri-mail-line',
color: '#8E71C1',
},
{
name: 'Travelling',
link: 'https://travellings.link',
icon: 'i-ri-train-line',
color: 'var(--va-c-text)',
},
],
search: {
enable: false,
},
sponsor: {
enable: true,
title: '我很可爱,请给我钱!',
methods: [
{
name: '支付宝',
url: 'https://cdn.yunyoujun.cn/img/donate/alipay-qrcode.jpg',
color: '#00A3EE',
icon: 'i-ri-alipay-line',
},
{
name: 'QQ 支付',
url: 'https://cdn.yunyoujun.cn/img/donate/qqpay-qrcode.png',
color: '#12B7F5',
icon: 'i-ri-qq-line',
},
{
name: '微信支付',
url: 'https://cdn.yunyoujun.cn/img/donate/wechatpay-qrcode.jpg',
color: '#2DC100',
icon: 'i-ri-wechat-pay-line',
},
],
},
theme: 'yun',
themeConfig: {
banner: {
enable: true,
title: '云游君的小站',
},
pages: [
{
name: '我的小伙伴们',
url: '/links/',
icon: 'i-ri-genderless-line',
color: 'dodgerblue',
},
{
name: '喜欢的女孩子',
url: '/girls/',
icon: 'i-ri-women-line',
color: 'hotpink',
},
],
footer: {
since: 2016,
beian: {
enable: true,
icp: '苏ICP备17038157号',
},
},
},
unocss: { safelist },
})

View File

@ -27,7 +27,7 @@ const app = useAppStore()
z="10"
:class="app.isRightSidebarOpen && 'open'"
>
<div class="aside-container" flex="~ col">
<div class="aside-container lt-xl:fixed" flex="~ col">
<PressToc v-if="frontmatter.toc !== false" :headers="data.headers || []" />
<div class="flex-grow" />
<div v-if="$slots.default" class="custom-container">
@ -65,13 +65,17 @@ const app = useAppStore()
.aside-container {
position: sticky;
top: 0;
top: calc(var(--pr-nav-height) + 32px);
margin-top: calc(var(--pr-nav-height) * -1 - 32px);
padding-top: calc(var(--pr-nav-height) + 32px);
height: 100vh;
}
@include media('xl') {
.aside-container {
top: 0;
}
.press-aside {
transform: translateX(0);
}

View File

@ -30,7 +30,7 @@ const getTitle = (post: Post | any) => {
<template>
<li v-if="category.total" class="category-list-item inline-flex items-center">
<span class="folder-action inline-flex" @click="collapsable = !collapsable">
<span class="folder-action inline-flex cursor-pointer" @click="collapsable = !collapsable">
<div v-if="collapsable" i-ri-folder-add-line />
<div v-else style="color:var(--va-c-primary)" i-ri-folder-reduce-line /></span>
<span class="category-name" m="l-1" @click="displayCategory ? displayCategory(name) : null">
@ -42,7 +42,6 @@ const getTitle = (post: Post | any) => {
<ul v-if="!isParentCategory(category)">
<li v-for="post, i in category.posts" :key="i" class="post-list-item" m="l-4">
<router-link v-if="post.title" :to="post.path || ''" class="inline-flex items-center">
<div i-ri-file-text-line />
<span m="l-1">{{ getTitle(post) }}</span>
</router-link>
</li>

View File

@ -35,14 +35,14 @@ defineProps<{
align-items: center;
margin-bottom: 20px;
border-radius: 6px;
background-color: var(--vp-c-gray-light-4);
background-color: var(--va-c-gray-light-4);
width: 48px;
height: 48px;
font-size: 24px;
}
.dark .icon {
background-color: var(--vp-c-bg);
background-color: var(--va-c-bg);
}
.title {
@ -56,6 +56,6 @@ defineProps<{
line-height: 24px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-2);
color: var(--va-c-text-light);
}
</style>

View File

@ -64,12 +64,12 @@ function scrollToTop() {
line-height: 24px;
font-size: 12px;
font-weight: 500;
color: var(--vp-c-text-2);
color: var(--va-c-text-light);
transition: color 0.5s;
}
.menu:hover {
color: var(--vp-c-text-1);
color: var(--va-c-text);
transition: color 0.25s;
}

View File

@ -1,13 +1,13 @@
<script lang="ts" setup>
import type { PageData, Post } from 'valaxy'
import { useFrontmatter, useLayout, useSidebar, useSite } from 'valaxy'
import { useConfig, useFrontmatter, useLayout, useSidebar } from 'valaxy'
defineProps<{
frontmatter: Post
data?: PageData
}>()
const config = useSite()
const config = useConfig()
const frontmatter = useFrontmatter()
const { hasSidebar } = useSidebar()

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { useSidebar, useSite } from 'valaxy'
import { useConfig, useSidebar } from 'valaxy'
import { useThemeConfig } from '../../composables'
import PressSwitchAppearance from './PressSwitchAppearance.vue'
@ -13,7 +13,7 @@ defineEmits<{
const { hasSidebar } = useSidebar()
const config = useSite()
const config = useConfig()
const themeConfig = useThemeConfig()
</script>

View File

@ -1,5 +1,5 @@
import { computed } from 'vue'
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
import type { ThemeConfig } from '../types'
/**
@ -7,6 +7,6 @@ import type { ThemeConfig } from '../types'
* @returns
*/
export function useThemeConfig<T = ThemeConfig>() {
const config = useSite<T>()
const config = useConfig<T>()
return computed(() => config!.value.themeConfig)
}

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { PageData, Post } from 'valaxy'
import { usePostTitle, useSite } from 'valaxy'
import { useConfig, usePostTitle } from 'valaxy'
import { computed, defineAsyncComponent } from 'vue'
import { usePostProperty } from '../composables'
@ -8,7 +8,7 @@ const props = defineProps<{
frontmatter: Post
data?: PageData
}>()
const config = useSite()
const config = useConfig()
const { styles, icon, color } = usePostProperty(props.frontmatter.type)
const title = usePostTitle(computed(() => props.frontmatter))

View File

@ -4,12 +4,12 @@ import docsearch from '@docsearch/js'
import type { DocSearchHit } from '@docsearch/react/dist/esm/types'
import { onMounted } from 'vue'
import type { AlgoliaSearchOptions } from 'valaxy'
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const config = useSite()
const config = useConfig()
onMounted(() => {
initialize(config.value.search.algolia)
@ -142,9 +142,9 @@ function getRelativePath(absoluteUrl: string) {
.dark .DocSearch {
--docsearch-modal-shadow: none;
--docsearch-footer-shadow: none;
--docsearch-logo-color: var(--va-c-text-2);
--docsearch-logo-color: var(--va-c-text-light);
--docsearch-hit-background: var(--va-c-bg-mute);
--docsearch-hit-color: var(--va-c-text-2);
--docsearch-hit-color: var(--va-c-text-light);
--docsearch-hit-shadow: none;
}

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { capitalize, computed } from 'vue'
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
import { useI18n } from 'vue-i18n'
import pkg from 'valaxy/package.json'
@ -8,7 +8,7 @@ import { useThemeConfig } from '../composables'
const { t } = useI18n()
const config = useSite()
const config = useConfig()
const themeConfig = useThemeConfig()
const year = new Date().getFullYear()

View File

@ -1,8 +1,8 @@
<script lang="ts" setup>
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
import { useRouter } from 'vue-router'
const config = useSite()
const config = useConfig()
const router = useRouter()
</script>

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
const config = useSite()
const config = useConfig()
</script>
<template>

View File

@ -1,10 +1,10 @@
<script lang="ts" setup>
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const config = useSite()
const config = useConfig()
const showQr = ref(false)
</script>

View File

@ -110,7 +110,7 @@ function handleClick({ target: el }: Event) {
.outline-link {
display: block;
line-height: 28px;
color: var(--va-c-text-2);
color: var(--va-c-text-light);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { useSite, useTwikoo } from 'valaxy'
import { useConfig, useTwikoo } from 'valaxy'
const config = useSite()
const config = useConfig()
useTwikoo(config.value.comment.twikoo)
</script>

View File

@ -1,9 +1,9 @@
<script lang="ts" setup>
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
// we need import on demand
import { useWaline } from 'valaxy/client/composables/comments/waline'
const config = useSite()
const config = useConfig()
useWaline(config.value.comment.waline, config.value.cdn.prefix)
</script>

View File

@ -1,5 +1,5 @@
import { computed } from 'vue'
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
import type { YunTheme } from '../types'
/**
@ -7,6 +7,6 @@ import type { YunTheme } from '../types'
* @returns
*/
export function useThemeConfig<ThemeConfig = YunTheme.Config>() {
const config = useSite<ThemeConfig>()
const config = useConfig<ThemeConfig>()
return computed(() => config!.value.themeConfig)
}

View File

@ -1,9 +1,9 @@
<script lang="ts" setup>
import { useAppStore, useLayout, useSite } from 'valaxy'
import { useAppStore, useConfig, useLayout } from 'valaxy'
import { useThemeConfig } from '../composables'
const app = useAppStore()
const config = useSite()
const config = useConfig()
const themeConfig = useThemeConfig()
const isHome = useLayout('home')
</script>

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { useSite } from 'valaxy'
import { useConfig } from 'valaxy'
const config = useSite()
const config = useConfig()
</script>
<template>

View File

@ -1,8 +1,8 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { useFrontmatter, useFullUrl, useSite } from 'valaxy'
import { useConfig, useFrontmatter, useFullUrl } from 'valaxy'
const config = useSite()
const config = useConfig()
const frontmatter = useFrontmatter()
const url = useFullUrl()

View File

@ -104,5 +104,3 @@ export const defaultThemeConfig: ThemeConfig = {
},
},
}
export default defaultThemeConfig

View File

@ -1,3 +1,4 @@
import type { ResolvedValaxyOptions } from 'valaxy/node'
import type { ThemeUserConfig } from '../types'
/**
@ -5,7 +6,8 @@ import type { ThemeUserConfig } from '../types'
* @param themeConfig
* @returns
*/
export function generateSafelist(themeConfig: ThemeUserConfig) {
export function generateSafelist(options: ResolvedValaxyOptions<ThemeUserConfig>) {
const themeConfig = options.config.themeConfig || {}
const safelist = []
const types = themeConfig.types

View File

@ -1,11 +1,11 @@
import type { ResolvedValaxyOptions } from 'valaxy'
import { defineConfig } from 'valaxy/node'
import { defineTheme } from 'valaxy/node'
import type { Plugin } from 'vite'
import type { ThemeConfig } from './types'
import { generateSafelist } from './node'
import { defaultThemeConfig, generateSafelist } from './node'
function ThemeVitePlugin(options: ResolvedValaxyOptions<ThemeConfig>): Plugin {
const themeConfig = options.config.themeConfig
const themeConfig = options.config.themeConfig || {}
return {
name: 'valaxy-theme-yun',
enforce: 'pre',
@ -27,15 +27,14 @@ function ThemeVitePlugin(options: ResolvedValaxyOptions<ThemeConfig>): Plugin {
}
}
const config = defineConfig<ThemeConfig>((options) => {
export default defineTheme<ThemeConfig>((options) => {
return {
themeConfig: defaultThemeConfig,
vite: {
plugins: [ThemeVitePlugin(options)],
},
unocss: {
safelist: generateSafelist(options.config.themeConfig),
safelist: generateSafelist(options),
},
}
})
export default config

View File

@ -6,20 +6,20 @@ import { isDark } from './composables'
// https://github.com/vueuse/head
// you can use this to manipulate the document head in any components,
// they will be rendered correctly in the html results with vite-ssg
import { useSite } from './config'
import { useConfig } from './config'
// <link rel="apple-touch-icon" href="/pwa-192x192.png">
// <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#00aba9">
// <meta name="msapplication-TileColor" content = "#00aba9" >
const config = useSite()
const config = useConfig()
useHead({
title: config.value.title,
link: [
{
rel: 'icon',
href: config.value.favicon,
type: config.value.favicon.endsWith('svg') ? 'image/svg+xml' : 'image/png',
type: config.value.favicon?.endsWith('svg') ? 'image/svg+xml' : 'image/png',
},
],
meta: [

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useSite } from '../config'
import { useConfig } from '../config'
withDefaults(defineProps<{
url?: string
@ -11,7 +11,7 @@ withDefaults(defineProps<{
const { t, locale } = useI18n()
const config = useSite()
const config = useConfig()
const ccVersion = (config.value.license.type === 'zero') ? '1.0' : '4.0'
const ccPrefix = (config.value.license.type === 'zero') ? 'publicdomain' : 'licenses'

View File

@ -2,7 +2,7 @@ import { isClient, useScriptTag } from '@vueuse/core'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import { useSite } from '../..'
import { useConfig } from '../..'
declare global {
interface Window {
@ -24,7 +24,7 @@ declare global {
* @param options
*/
export function useTwikoo(options: {} = {}) {
const config = useSite()
const config = useConfig()
const cdnPrefix = computed(() => config.value.cdn.prefix)
const route = useRoute()

View File

@ -3,7 +3,7 @@ import { computed, inject } from 'vue'
import { isClient } from '@vueuse/core'
import type { PageData, Post } from '../../types'
import { useSite } from '../config'
import { useConfig } from '../config'
export function useFrontmatter() {
const route = useRoute()
@ -25,7 +25,7 @@ export function useData(): PageData {
* get full url
*/
export function useFullUrl() {
const config = useSite()
const config = useConfig()
const route = useRoute()
const url = computed(() => {
const siteUrl = config.value.url.endsWith('/') ? config.value.url.slice(0, -1) : config.value.url

View File

@ -1,7 +1,7 @@
import { useScriptTag } from '@vueuse/core'
import { useHead } from '@vueuse/head'
import { computed } from 'vue'
import { useSite } from '../..'
import { useConfig } from '../..'
/**
* use MetingJS and Aplayer
@ -9,7 +9,7 @@ import { useSite } from '../..'
* @see https://github.com/metowolf/MetingJS
*/
export function useAplayer() {
const config = useSite()
const config = useConfig()
const cdnPrefix = computed(() => config.value.cdn.prefix)
useHead({

View File

@ -8,7 +8,7 @@ import { computed, inject, readonly, shallowRef } from 'vue'
// fix build caused by pnpm
// This is likely not portable. A type annotation is necessary.
// https://github.com/microsoft/TypeScript/issues/42873
import type { ValaxySiteConfig } from 'valaxy/types'
import type { ValaxySiteConfig, ValaxyThemeConfig } from 'valaxy/types'
/**
* parse valaxy config
@ -50,25 +50,35 @@ export function initContext() {
return computed(() => valaxyContextRef.value)
}
/*
/**
* get valaxy config
* @public
* @returns
*/
export function useSite<ThemeConfig = any>() {
export function useSite<ThemeConfig = ValaxyThemeConfig>() {
const config = inject<ComputedRef<ValaxySiteConfig<ThemeConfig>>>(valaxySiteConfigSymbol)
if (!config)
throw new Error('[Valaxy] config not properly injected in app')
throw new Error('[Valaxy] site config not properly injected in app')
return config!
}
/**
* alias for useSite
* @public
* @returns
*/
export function useConfig<ThemeConfig = ValaxyThemeConfig>() {
return useSite<ThemeConfig>()
}
/**
* You can use like this: import { useThemeConfig } from 'valaxy-theme-xxx'
* if you want to: import { useThemeConfig } from 'valaxy'
* you need pass themeConfig by yourself
* @internal
* @returns
*/
export function useThemeConfig<T = Record<string, any>>() {
const config = useSite<T>()
export function useThemeConfig<ThemeConfig = ValaxyThemeConfig>() {
const config = useSite<ThemeConfig>()
return computed(() => config!.value.themeConfig)
}

View File

@ -54,7 +54,7 @@ $light: map.merge(
"c-bg-light": white,
"c-bg-dark": #fafafa,
"c-bg-soft": white,
"c-bg-soft": #f9f9f9,
"c-bg-alt": #f9f9f9,
"c-bg-mute": #f1f1f1,

View File

@ -1,19 +1,17 @@
import type { InlineConfig } from 'vite'
import { mergeConfig, build as viteBuild } from 'vite'
import { mergeConfig as mergeViteConfig, build as viteBuild } from 'vite'
import { build as viteSsgBuild } from 'vite-ssg/node'
import generateSitemap from 'vite-ssg-sitemap'
import type { ResolvedValaxyOptions } from './options'
import { ViteValaxyPlugins } from './plugins/preset'
import { resolveValaxyConfig } from './utils/config'
export async function build(
options: ResolvedValaxyOptions,
viteConfig: InlineConfig = {},
) {
const config = await resolveValaxyConfig(options, viteConfig)
const inlineConfig = mergeConfig(config.vite!, {
plugins: await ViteValaxyPlugins(options, config),
const inlineConfig = mergeViteConfig(viteConfig, {
plugins: await ViteValaxyPlugins(options),
})
await viteBuild(inlineConfig)
@ -23,10 +21,8 @@ export async function ssgBuild(
options: ResolvedValaxyOptions,
viteConfig: InlineConfig = {},
) {
const config = await resolveValaxyConfig(options, viteConfig)
const defaultConfig: InlineConfig = {
plugins: await ViteValaxyPlugins(options, config),
plugins: await ViteValaxyPlugins(options),
}
defaultConfig.ssgOptions = {
@ -41,7 +37,7 @@ export async function ssgBuild(
},
dirStyle: 'nested',
}
const inlineConfig: InlineConfig = mergeConfig(config.vite!, defaultConfig)
const inlineConfig: InlineConfig = mergeViteConfig(defaultConfig, viteConfig)
await viteSsgBuild({}, inlineConfig)
}

View File

@ -66,7 +66,7 @@ cli.command(
const port = userPort || await findFreePort(4859)
const options = await resolveOptions({ userRoot: root })
const viteConfig: InlineConfig = {
const viteConfig: InlineConfig = mergeConfig({
// avoid load userRoot/vite.config.ts repeatedly
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),
server: {
@ -81,7 +81,8 @@ cli.command(
host: remote ? '0.0.0.0' : 'localhost',
},
logLevel: log as LogLevel,
}
}, options.config.vite || {})
await initServer(options, viteConfig)
printInfo(options, port, remote)
@ -135,8 +136,9 @@ cli.command(
const options = await resolveOptions({ userRoot: root }, 'build')
printInfo(options)
const viteConfig = mergeConfig(
await mergeViteConfigs(options, 'build'),
const valaxyViteConfig: InlineConfig = mergeConfig(await mergeViteConfigs(options, 'build'), options.config.vite || {})
const viteConfig: InlineConfig = mergeConfig(
valaxyViteConfig,
{
// avoid load userRoot/vite.config.ts repeatedly
configFile: path.resolve(options.clientRoot, 'vite.config.ts'),

View File

@ -3,10 +3,9 @@ import { join } from 'path'
import type { ConfigEnv, InlineConfig } from 'vite'
import { uniq } from '@antfu/utils'
import { loadConfigFromFile, mergeConfig } from 'vite'
import { loadConfig } from 'unconfig'
import type { ResolvedValaxyOptions, ValaxyConfig } from './options'
import { mergeFullConfig, toAtFS } from './utils'
import type { ValaxyConfigExport } from './config'
import type { ResolvedValaxyOptions } from './options'
import { toAtFS } from './utils'
export async function mergeViteConfigs({ userRoot, themeRoot }: ResolvedValaxyOptions, command: 'serve' | 'build') {
const configEnv: ConfigEnv = {
mode: 'development',
@ -30,29 +29,6 @@ export async function mergeViteConfigs({ userRoot, themeRoot }: ResolvedValaxyOp
return resolvedConfig
}
export async function mergeValaxyConfigs(options: ResolvedValaxyOptions) {
const { userRoot, themeRoot } = options
let valaxyConfig: ValaxyConfig = { vite: {} }
for await (const root of uniq([themeRoot, userRoot])) {
// no need to judge empty, unconfig will do it for us
const { config } = await loadConfig<ValaxyConfig>({
sources: {
files: 'valaxy.config',
async rewrite(c: ValaxyConfigExport) {
return await (typeof c === 'function' ? c(options) : c)
},
},
cwd: root,
merge: false,
})
if (!config)
continue
valaxyConfig = mergeFullConfig(valaxyConfig, config)
}
return valaxyConfig
}
export async function getIndexHtml({ clientRoot, themeRoot, userRoot, config }: ResolvedValaxyOptions): Promise<string> {
let main = await fs.readFile(join(clientRoot, 'index.html'), 'utf-8')
let head = ''

View File

@ -1,20 +1,13 @@
// import { loadConfig } from 'c12'
import path from 'path'
import fs from 'fs-extra'
import defu from 'defu'
import { ensureSuffix } from '@antfu/utils'
import { normalizePath } from 'vite'
import { loadConfig } from 'unconfig'
import type { VitePluginConfig as UnoCssConfig } from 'unocss/vite'
import type { Awaitable } from '@antfu/utils'
import jiti from 'jiti'
import type { UserConfig, ValaxySiteConfig } from '../types'
import type { ResolvedValaxyOptions, ThemeSetup, ValaxyConfig, ValaxyEntryOptions } from './options'
import { getThemeRoot } from './utils/theme'
import type { DefaultThemeConfig, SiteConfig, UserSiteConfig } from '../types'
import type { ResolvedValaxyOptions } from './options'
import type { UserConfig, ValaxyConfig } from './types'
/**
* Type site helper
*/
export function defineSite<ThemeConfig>(config: UserConfig<ThemeConfig>) {
export function defineSite<ThemeConfig>(config: UserSiteConfig<ThemeConfig>) {
return config
}
@ -22,21 +15,27 @@ export function defineSite<ThemeConfig>(config: UserConfig<ThemeConfig>) {
* Type site helper for custom theme site
*/
export function defineSiteWithTheme<ThemeConfig>(
config: UserConfig<ThemeConfig>,
config: UserSiteConfig<ThemeConfig>,
) {
return config
}
export type ValaxyConfigExport<T = Record<string, any>> = ValaxyConfig | Promise<ValaxyConfig> | ValaxyConfigFn<T>
export type ValaxyConfigFn<T> = (options: ResolvedValaxyOptions<T>) => ValaxyConfig | Promise<ValaxyConfig>
/**
* Type valaxy config helper
*/
export function defineConfig<ThemeConfig>(config: ValaxyConfigExport<ThemeConfig>) {
export function defineConfig<ThemeConfig>(config: UserConfig<ThemeConfig>) {
return config
}
const defaultSiteConfig: ValaxySiteConfig = {
export type ValaxyConfigExtendKey = 'vite' | 'vue' | 'unocss' | 'unocssPresets' | 'markdown' | 'extendMd'
export type ValaxyTheme<ThemeConfig = DefaultThemeConfig> = Pick<ValaxyConfig, ValaxyConfigExtendKey> & { themeConfig?: ThemeConfig }
export function defineTheme<ThemeConfig = DefaultThemeConfig>(
theme: ValaxyTheme<ThemeConfig> | ((options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyTheme<ThemeConfig>),
) {
return theme
}
export const defaultSiteConfig: SiteConfig = {
mode: 'auto',
url: '/',
lang: 'en',
@ -44,13 +43,14 @@ const defaultSiteConfig: ValaxySiteConfig = {
description: 'A blog generated by Valaxy.',
subtitle: 'Next Generation Static Blog Framework.',
author: {
// todo valaxy logo
avatar: 'https://www.yunyoujun.cn/images/avatar.jpg',
email: 'me@yunyoujun.cn',
link: 'https://www.yunyoujun.cn',
name: 'YunYouJun',
email: 'i@valaxy.site',
link: 'https://valaxy.site',
name: 'VALAXY Developer',
status: {
emoji: '😊',
message: 'All at sea.',
emoji: '🌌',
message: 'The moonlight is beautiful.',
},
},
favicon: '/favicon.svg',
@ -73,7 +73,7 @@ const defaultSiteConfig: ValaxySiteConfig = {
sponsor: {
enable: true,
title: '我很可爱,请给我钱',
title: '赞助',
methods: [],
},
@ -120,64 +120,6 @@ const defaultSiteConfig: ValaxySiteConfig = {
// },
}
// for user config
export async function resolveSiteConfig(options: ValaxyEntryOptions = {}) {
// c12 merge array twice, so i deprecated it
// const { config, configFile } = await loadConfig<ValaxySiteConfig>({
// name: 'valaxy',
// defaults: defaultSiteConfig,
// })
const { config: userConfig, sources } = await loadConfig<ValaxySiteConfig>({
sources: [
{
files: 'site.config',
extensions: ['ts', 'js', 'mjs', 'cjs', 'json'],
},
],
merge: false,
})
const configFile = normalizePath(sources[0] || '')
const config = defu(userConfig, defaultSiteConfig)
// ensure suffix for cdn prefix
config.cdn.prefix = ensureSuffix('/', config.cdn.prefix)
const theme = options.theme || config.theme || 'yun'
let themeSetup: ThemeSetup = {}
try {
const themeEntry = path.resolve(getThemeRoot(theme), 'node/index.ts')
if (!(await fs.pathExists(themeEntry)))
throw new Error('theme entry not found')
themeSetup = jiti(__filename)(themeEntry)
config.themeConfig = defu(config.themeConfig, themeSetup.defaultThemeConfig || {})
}
catch (e) {
console.error(e)
console.error(`valaxy-theme-${theme} doesn't have default config`)
}
try {
const pkg = fs.readFileSync(require.resolve(`valaxy-theme-${theme}/package.json`), 'utf-8')
config.themeConfig.pkg = JSON.parse(pkg)
}
catch (e) {
console.error(`valaxy-theme-${theme} doesn't have package.json`)
}
config.url = ensureSuffix('/', config.url)
return {
config,
configFile,
theme,
themeSetup,
}
}
export type UnoSetup = () => Awaitable<Partial<UnoCssConfig> | undefined>
export function defineUnoSetup(fn: UnoSetup) {

View File

@ -1,18 +1,15 @@
import { dirname, resolve } from 'path'
import fs from 'fs'
import _debug from 'debug'
import fg from 'fast-glob'
import type Vue from '@vitejs/plugin-vue'
import type Components from 'unplugin-vue-components/vite'
import type { VitePluginConfig as UnoCSSConfig } from 'unocss/vite'
import { uniq } from '@antfu/utils'
import type Pages from 'vite-plugin-pages'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { presetAttributify, presetIcons, presetTypography, presetUno } from 'unocss'
import type { ValaxySiteConfig } from '../types'
import { resolveSiteConfig } from './config'
import { ensureSuffix, uniq } from '@antfu/utils'
import defu from 'defu'
import type { DefaultThemeConfig } from '../types'
import { resolveImportPath } from './utils'
import type { MarkdownOptions } from './markdown'
import { getThemeRoot } from './utils/theme'
import { mergeValaxyConfig, resolveValaxyConfig, resolveValaxyConfigFromRoot } from './utils/config'
import type { ValaxyConfig } from './types'
import { defaultSiteConfig } from './config'
// for cli entry
export interface ValaxyEntryOptions {
@ -23,41 +20,7 @@ export interface ValaxyEntryOptions {
userRoot?: string
}
export interface ValaxyConfig {
vite?: ViteUserConfig
vue?: Parameters<typeof Vue>[0]
components?: Parameters<typeof Components>[0]
unocss?: UnoCSSConfig
/**
* unocss presets
*/
unocssPresets?: {
uno?: Parameters<typeof presetUno>[0]
attributify?: Parameters<typeof presetAttributify>[0]
icons?: Parameters<typeof presetIcons>[0]
typography?: Parameters<typeof presetTypography>[0]
}
pages?: Parameters<typeof Pages>[0]
/**
* for markdown
*/
markdown?: MarkdownOptions
extendMd?: (ctx: {
route: any
data: Record<string, any>
excerpt?: string
path: string
}) => void
plugins?: ValaxyPluginOption[]
}
export type ValaxyPluginLike = ValaxyConfig | ValaxyConfig[] | false | null | undefined
export type ValaxyPluginOption = ValaxyPluginLike | string | [string, any]
export interface ThemeSetup {
defaultThemeConfig?: Record<string, any>
}
export interface ResolvedValaxyOptions<T = Record<string, any>> {
export interface ResolvedValaxyOptions<ThemeConfig = DefaultThemeConfig> {
mode: 'dev' | 'build'
/**
* package.json root
@ -82,11 +45,10 @@ export interface ResolvedValaxyOptions<T = Record<string, any>> {
*/
roots: string[]
theme: string
themeSetup: ThemeSetup
/**
* Valaxy Config
*/
config: ValaxySiteConfig<T>
config: ValaxyConfig<ThemeConfig>
/**
* config file path
*/
@ -95,7 +57,7 @@ export interface ResolvedValaxyOptions<T = Record<string, any>> {
}
export interface ValaxyServerOptions {
onConfigReload?: (newConfig: ValaxySiteConfig, config: ValaxySiteConfig, force?: boolean) => void
onConfigReload?: (newConfig: ValaxyConfig, config: ValaxyConfig, force?: boolean) => void
}
const debug = _debug('valaxy:options')
@ -106,8 +68,9 @@ export async function resolveOptions(options: ValaxyEntryOptions, mode: Resolved
const clientRoot = resolve(pkgRoot, 'client')
const userRoot = resolve(options.userRoot || process.cwd())
const { config: siteConfig, configFile, theme, themeSetup } = await resolveSiteConfig(options)
const themeRoot = getThemeRoot(theme, userRoot)
const { config: userValaxyConfig, configFile, theme } = await resolveValaxyConfig(options)
const themeRoot = getThemeRoot(theme, options.userRoot)
const roots = uniq([clientRoot, themeRoot, userRoot])
@ -132,12 +95,31 @@ export async function resolveOptions(options: ValaxyEntryOptions, mode: Resolved
themeRoot,
roots,
theme,
themeSetup,
config: siteConfig,
config: userValaxyConfig,
configFile: configFile || '',
pages,
}
debug(valaxyOptions)
// resolve theme valaxy.config.ts and merge theme
const { config: themeValaxyConfig } = await resolveValaxyConfigFromRoot(themeRoot, valaxyOptions)
const valaxyConfig = mergeValaxyConfig(userValaxyConfig, themeValaxyConfig)
const config = defu(valaxyConfig, defaultSiteConfig)
valaxyOptions.config = config
// optimize config
config.url = ensureSuffix('/', config.url)
// ensure suffix for cdn prefix
config.cdn.prefix = ensureSuffix('/', config.cdn.prefix)
// mount pkg info
try {
const pkg = fs.readFileSync(require.resolve(`valaxy-theme-${theme}/package.json`), 'utf-8')
config.themeConfig.pkg = JSON.parse(pkg)
}
catch (e) {
console.error(`valaxy-theme-${theme} doesn't have package.json`)
}
return valaxyOptions
}

View File

@ -2,6 +2,7 @@ import { dirname, join, resolve } from 'path'
import type { InlineConfig, Plugin } from 'vite'
import { mergeConfig } from 'vite'
import isInstalledGlobally from 'is-installed-globally'
import fs from 'fs-extra'
import type { ResolvedValaxyOptions } from '../options'
import { resolveImportPath, toAtFS } from '../utils'
import { getIndexHtml } from '../common'
@ -81,6 +82,13 @@ export function createConfigPlugin(options: ResolvedValaxyOptions): Plugin {
res.end(await getIndexHtml(options))
return
}
// patch rss
if (req.url! === '/atom.xml') {
res.setHeader('Content-Type', 'application/xml')
res.statusCode = 200
res.end(await fs.readFile(resolve(options.userRoot, 'dist/atom.xml'), 'utf-8'))
return
}
next()
})
}

View File

@ -1,10 +1,10 @@
import fs from 'fs'
import { basename, join, relative } from 'path'
import { join, relative } from 'path'
import type { Plugin, ResolvedConfig } from 'vite'
// import consola from 'consola'
import { resolveSiteConfig } from '../config'
import type { ResolvedValaxyOptions, ValaxyConfig, ValaxyServerOptions } from '../options'
import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
import { resolveOptions } from '../options'
import { resolveImportPath, slash, toAtFS } from '../utils'
import { createMarkdownToVueRenderFn } from '../markdown/markdownToVue'
import type { PageDataPayload } from '../../types'
@ -19,7 +19,7 @@ function generateStyles(roots: string[], options: ResolvedValaxyOptions) {
const imports: string[] = []
// katex
if (options.config.features.katex) {
if (options.config.features?.katex) {
imports.push(`import "${toAtFS(resolveImportPath('katex/dist/katex.min.css', true))}"`)
imports.push(`import "${toAtFS(join(options.clientRoot, 'styles/third/katex.scss'))}"`)
}
@ -63,7 +63,9 @@ function generateLocales(roots: string[]) {
return imports.join('\n')
}
export function createValaxyPlugin(options: ResolvedValaxyOptions, valaxyConfig: ValaxyConfig, serverOptions: ValaxyServerOptions = {}): Plugin {
export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions: ValaxyServerOptions = {}): Plugin {
const { config: valaxyConfig } = options
const valaxyPrefix = '/@valaxy'
let siteConfig = options.config
@ -184,14 +186,10 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, valaxyConfig:
// handle site.config.ts hmr
const { file, server, read } = ctx
const fileName = basename(file)
const isSiteConfig = fileName.startsWith('site.config')
const isValaxyConfig = fileName.startsWith('valaxy.config')
if (file === options.configFile) {
const { config } = await resolveOptions({ userRoot: options.userRoot })
if (isSiteConfig || isValaxyConfig) {
const { config } = await resolveSiteConfig()
serverOptions.onConfigReload?.(config, options.config, isValaxyConfig)
serverOptions.onConfigReload?.(config, options.config)
Object.assign(options.config, config)
siteConfig = config

View File

@ -12,7 +12,7 @@ import Components from 'unplugin-vue-components/vite'
import { vueI18n } from '@intlify/vite-plugin-vue-i18n'
import dayjs from 'dayjs'
import type { ResolvedValaxyOptions, ValaxyConfig, ValaxyServerOptions } from '../options'
import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
import { setupMarkdownPlugins } from '../markdown'
// import { createMarkdownPlugin, excerpt_separator } from './markdown'
// import { formatMdDate } from '../utils/date'
@ -23,15 +23,14 @@ import { createValaxyPlugin } from '.'
export async function ViteValaxyPlugins(
options: ResolvedValaxyOptions,
valaxyConfig: ValaxyConfig = {},
serverOptions: ValaxyServerOptions = {},
): Promise<(PluginOption | PluginOption[])[] | undefined> {
const { roots } = options
const { roots, config: valaxyConfig } = options
// const MarkdownPlugin = createMarkdownPlugin(options)
const UnocssPlugin = await createUnocssPlugin(options, valaxyConfig)
const ValaxyPlugin = createValaxyPlugin(options, valaxyConfig, serverOptions)
const ValaxyPlugin = createValaxyPlugin(options, serverOptions)
// for render markdown excerpt
const mdIt = new MarkdownIt({ html: true })
@ -139,7 +138,7 @@ export async function ViteValaxyPlugins(
// options.config.lastUpdated,
// )
const lastUpdated = options.config.lastUpdated
const format = options.config.date.format
const format = options.config.date?.format
if (!data.date)
data.date = fs.statSync(path).mtime

View File

@ -35,20 +35,20 @@ export async function build(options: ResolvedValaxyOptions) {
const DOMAIN = config.url.slice(0, -1)
const author: Author = {
name: options.config.author.name,
email: options.config.author.email,
link: options.config.author.link,
name: config?.author?.name,
email: config?.author?.email,
link: config?.author?.link,
}
consola.info(`RSS Site Url: ${cyan(siteUrl)}`)
const ccVersion = (config.license.type === 'zero') ? '1.0' : '4.0'
const ccVersion = (config.license?.type === 'zero') ? '1.0' : '4.0'
const feedOptions: FeedOptions = {
title: config.title,
title: config.title || 'Valaxy Blog',
description: config.description,
id: siteUrl || 'valaxy',
link: siteUrl,
copyright: `CC ${config.license.type.toUpperCase()} ${ccVersion} ${new Date().getFullYear()} © ${config.author.name}`,
copyright: `CC ${config.license?.type?.toUpperCase()} ${ccVersion} ${new Date().getFullYear()} © ${config.author?.name}`,
feedLinks: {
json: `${siteUrl}feed.json`,
atom: `${siteUrl}feed.atom`,
@ -70,7 +70,7 @@ export async function build(options: ResolvedValaxyOptions) {
continue
}
await formatMdDate(data, i, config.date.format, config.lastUpdated)
await formatMdDate(data, i, config.date?.format, config.lastUpdated)
// todo i18n
@ -99,23 +99,23 @@ export async function build(options: ResolvedValaxyOptions) {
// write
feedOptions.author = author
feedOptions.image = config.author.avatar.startsWith('http') ? config.author.avatar : `${DOMAIN}${config.author.avatar}`
feedOptions.favicon = `${DOMAIN}${config.feed.favicon || config.favicon}`
feedOptions.image = config.author?.avatar?.startsWith('http') ? config.author.avatar : `${DOMAIN}${config.author?.avatar}`
feedOptions.favicon = `${DOMAIN}${config.feed?.favicon || config.favicon}`
const feed = new Feed(feedOptions)
posts.forEach(item => feed.addItem(item))
// items.forEach(i=> console.log(i.title, i.date))
await fs.ensureDir(dirname(`./dist/${config.feed.name}`))
await fs.ensureDir(dirname(`./dist/${config.feed?.name}`))
const path = './dist'
const types = ['xml', 'atom', 'json']
types.forEach((type) => {
let data = ''
let name = `${path}/${config.feed.name || 'feed'}.${type}`
let name = `${path}/${config.feed?.name || 'feed'}.${type}`
if (type === 'xml') { data = feed.rss2() }
else if (type === 'atom') {
if (!config.feed.name)
if (!config.feed?.name)
name = `${path}/atom.xml`
data = feed.atom1()
}

View File

@ -3,7 +3,6 @@ import { createServer as createViteServer, mergeConfig as mergeViteConfig } from
import type { ResolvedValaxyOptions, ValaxyServerOptions } from './options'
import { ViteValaxyPlugins } from './plugins/preset'
import { resolveValaxyConfig } from './utils/config'
export async function createServer(
options: ResolvedValaxyOptions,
@ -13,13 +12,11 @@ export async function createServer(
// default editor vscode
process.env.EDITOR = process.env.EDITOR || 'code'
const config = await resolveValaxyConfig(options, viteConfig)
const server = await createViteServer(
mergeViteConfig(
config.vite!,
viteConfig,
{
plugins: await ViteValaxyPlugins(options, config, serverOptions),
plugins: await ViteValaxyPlugins(options, serverOptions),
},
),
)

View File

@ -0,0 +1,44 @@
import type Vue from '@vitejs/plugin-vue'
import type Components from 'unplugin-vue-components/vite'
import type { VitePluginConfig as UnoCSSConfig } from 'unocss/vite'
import type Pages from 'vite-plugin-pages'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { presetAttributify, presetIcons, presetTypography, presetUno } from 'unocss'
import type { DefaultThemeConfig, UserSiteConfig } from '../types'
import type { ResolvedValaxyOptions } from './options'
import type { MarkdownOptions } from './markdown'
export type ValaxyConfig<ThemeConfig = DefaultThemeConfig> = UserSiteConfig<ThemeConfig> & ValaxyExtendConfig
export type UserConfig<ThemeConfig = DefaultThemeConfig> = ValaxyConfig<ThemeConfig>
/**
* fn with options for theme config
*/
export type ValaxyConfigFn<ThemeConfig = DefaultThemeConfig> = (options: ResolvedValaxyOptions<ThemeConfig>) => ValaxyConfig | Promise<ValaxyConfig>
export type ValaxyConfigExport<ThemeConfig = DefaultThemeConfig> = ValaxyConfig<ThemeConfig> | ValaxyConfigFn<ThemeConfig>
export interface ValaxyExtendConfig {
vite?: ViteUserConfig
vue?: Parameters<typeof Vue>[0]
components?: Parameters<typeof Components>[0]
unocss?: UnoCSSConfig
/**
* unocss presets
*/
unocssPresets?: {
uno?: Parameters<typeof presetUno>[0]
attributify?: Parameters<typeof presetAttributify>[0]
icons?: Parameters<typeof presetIcons>[0]
typography?: Parameters<typeof presetTypography>[0]
}
pages?: Parameters<typeof Pages>[0]
/**
* for markdown
*/
markdown?: MarkdownOptions
extendMd?: (ctx: {
route: any
data: Record<string, any>
excerpt?: string
path: string
}) => void
}

View File

@ -10,6 +10,8 @@ import { createServer } from '../server'
import type { ResolvedValaxyOptions } from '../options'
import { version } from '../../package.json'
import { mergeViteConfigs } from '../common'
import type { ValaxyConfigExtendKey } from '../config'
let server: ViteDevServer | undefined
export function printInfo(options: ResolvedValaxyOptions, port?: number, remote?: string | boolean) {
@ -38,6 +40,16 @@ export function printInfo(options: ResolvedValaxyOptions, port?: number, remote?
console.log()
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const CONFIG_RESTART_FIELDS: ValaxyConfigExtendKey[] = [
'vite',
'vue',
'unocss',
'unocssPresets',
'markdown',
'extendMd',
]
export async function initServer(options: ResolvedValaxyOptions, viteConfig: InlineConfig) {
if (server)
await server.close()
@ -49,7 +61,7 @@ export async function initServer(options: ResolvedValaxyOptions, viteConfig: Inl
try {
server = await createServer(options, viteConfigs, {
async onConfigReload(newSiteConfig, siteConfig, force = false) {
async onConfigReload(newConfig, config, force = false) {
if (force) {
consola.info('[valaxy]', `${yellow('force')} reload the server`)
initServer(options, viteConfig)
@ -57,7 +69,7 @@ export async function initServer(options: ResolvedValaxyOptions, viteConfig: Inl
let reload = false
if (newSiteConfig.theme !== siteConfig.theme)
if (newConfig.theme !== config.theme)
reload = true
// consola.info('Find new icon, reload server...')
@ -65,6 +77,11 @@ export async function initServer(options: ResolvedValaxyOptions, viteConfig: Inl
// console.log()
// reload = true
// if (CONFIG_RESTART_FIELDS.some(i => !equal(newConfig[i], config[i]))) {
// reload = true
// console.log(yellow('\n restarting on config change\n'))
// }
if (reload)
initServer(options, viteConfig)
},

View File

@ -1,15 +1,73 @@
import type { InlineConfig } from 'vite'
import { mergeConfig as mergeViteConfig } from 'vite'
import type { ResolvedValaxyOptions } from '../options'
import { mergeValaxyConfigs } from '../common'
import { mergeConfig as mergeViteConfig, normalizePath } from 'vite'
import { loadConfig } from 'unconfig'
import { createDefu } from 'defu'
import { isFunction } from '@antfu/utils'
import type { ResolvedValaxyOptions, ValaxyEntryOptions } from '../options'
import type { ValaxyConfig, ValaxyConfigFn } from '../types'
export async function resolveValaxyConfig(options: ResolvedValaxyOptions, viteConfig: InlineConfig = {}) {
const resolved = await mergeValaxyConfigs(options)
/**
* merge valaxy.config
* (source, default)
*/
export const mergeValaxyConfig = createDefu((obj: any, key, value) => {
if (isFunction(obj[key]) && isFunction(value)) {
obj[key] = function (...args: any[]) {
obj[key].call(this, ...args)
value.call(this, ...args)
}
}
if (key === 'vite') {
// a deep copy and needs to be taken over
obj[key] = mergeViteConfig(obj[key], value)
return true
}
})
if (!resolved.vite)
resolved.vite = {}
/**
* resolve valaxy config from special root
* @param options
* @returns
*/
export async function resolveValaxyConfigFromRoot(root: string, options?: ResolvedValaxyOptions) {
// c12 merge array twice, so i deprecated it
const { config, sources } = await loadConfig<ValaxyConfig>({
sources: {
files: 'valaxy.config',
async rewrite(c: ValaxyConfig | ValaxyConfigFn) {
const config = await (typeof c === 'function' ? c(options || {} as ResolvedValaxyOptions) : c)
return config
},
},
cwd: root,
})
resolved.vite = mergeViteConfig(resolved.vite, viteConfig)
if (!config.vite)
config.vite = {}
return resolved
return {
config,
sources,
}
}
/**
* resolve user valaxy config
* options only have userRoot
* @param options
* @param viteConfig
* @returns
*/
export async function resolveValaxyConfig(options: ValaxyEntryOptions) {
// const resolved = await mergeValaxyConfig(options)
// valaxyConfig = mergeValaxyConfig(valaxyConfig, config)
const { config: userValaxyConfig, sources } = await resolveValaxyConfigFromRoot(options.userRoot || process.cwd())
const configFile = normalizePath(sources[0] || '')
const theme = options.theme || userValaxyConfig.theme || 'yun'
return {
config: userValaxyConfig,
configFile,
theme,
}
}

View File

@ -3,27 +3,11 @@ import isInstalledGlobally from 'is-installed-globally'
import globalDirs from 'global-dirs'
import { sync as resolve } from 'resolve'
import consola from 'consola'
import { createDefu } from 'defu'
import { isFunction } from '@antfu/utils'
import { mergeConfig as mergeViteConfig } from 'vite'
export * from './getGitTimestamp'
export const EXTERNAL_URL_RE = /^https?:/i
export const mergeFullConfig = createDefu((obj: any, key, value) => {
if (isFunction(obj[key]) && isFunction(value)) {
obj[key] = function (...args: any[]) {
obj[key].call(this, ...args)
value.call(this, ...args)
}
}
if (key === 'vite') {
// a deep copy and needs to be taken over
obj[key] = mergeViteConfig(obj[key], value)
return true
}
})
/**
* transform obj for vite code
* @param obj

View File

@ -1,4 +1,4 @@
export type ValaxyThemeConfig = Record<string, any>
export type DefaultThemeConfig = Record<string, any>
export interface SocialLink {
/**
@ -25,8 +25,8 @@ export interface AlgoliaSearchOptions {
initialQuery?: string
}
// packages/valaxy/node/config.ts
export interface ValaxySiteConfig<T = ValaxyThemeConfig> {
// shared with valaxy node and client
export interface SiteConfig<T = DefaultThemeConfig> {
/**
* enable auto (light/dark mode)
* @default 'auto'
@ -226,5 +226,4 @@ export type PartialDeep<T> = {
* Valaxy User Config
* @description Valaxy
*/
export type UserConfig<ThemeConfig = ValaxyThemeConfig> = PartialDeep<ValaxySiteConfig<ThemeConfig>>
export type UserSiteConfig<ThemeConfig = DefaultThemeConfig> = PartialDeep<SiteConfig<ThemeConfig>>