diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..52b0b26d2 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,28 @@ +name: Build + +# a pull request is built the way a deploy is, so dead links and build errors show up before merging +on: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + run_install: true + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: pnpm + + - name: Build with VitePress + run: pnpm docs:build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/deploy-sub.yml b/.github/workflows/deploy-sub.yml index e45be86a4..211db872c 100644 --- a/.github/workflows/deploy-sub.yml +++ b/.github/workflows/deploy-sub.yml @@ -40,6 +40,8 @@ jobs: - name: Build with VitePress run: pnpm docs:build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Push build uses: peaceiris/actions-gh-pages@v4 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 429c870cd..ce819b7af 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -26,6 +26,8 @@ jobs: - name: Build with VitePress run: pnpm docs:build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Push gh-pages uses: peaceiris/actions-gh-pages@v4 diff --git a/.vitepress/config/community.ts b/.vitepress/config/community.ts new file mode 100644 index 000000000..1f530fe3a --- /dev/null +++ b/.vitepress/config/community.ts @@ -0,0 +1,51 @@ +import type { DefaultTheme } from 'vitepress' +import { LINKS } from '../links' + +interface Words { + title: string + connect: string + learn: string + videos: string + contribute: string + guide: string + language: string + languageAnchor: string +} + +const row = (text: string, link: string, icon: string, color?: string) => ({ + text: `${text}`, + link, + noIcon: true // the theme only drops its external arrow for links holding an svg or img +}) + +export function community(words: Words, prefix = '', videos: 'youtube' | 'bilibili' = 'youtube'): DefaultTheme.NavItemWithChildren { + return { + text: words.title, + items: [ + { + text: words.connect, + items: [ + row('Discord', LINKS.discord, 'icon-[simple-icons--discord]', '#5865F2'), + row('X', LINKS.x, 'icon-[simple-icons--x]', '#000000') + ] + }, + { + text: words.learn, + items: [ + videos === 'youtube' + ? row(words.videos, LINKS.youtube, 'icon-[simple-icons--youtube]', '#FF0000') + : row(words.videos, LINKS.bilibili, 'icon-[simple-icons--bilibili]', '#00A1D6'), + row('DevChalk', LINKS.devchalk, 'is-devchalk') + ] + }, + { + text: words.contribute, + items: [ + row(words.guide, `${prefix}/prologue/contributions`, 'icon-[lucide--git-pull-request]'), + row(words.language, `${prefix}/prologue/contributions#${words.languageAnchor}`, 'icon-[lucide--languages]'), + row('Open Collective', LINKS.openCollective, 'icon-[simple-icons--opencollective]', '#7FADF2') + ] + } + ] + } +} diff --git a/.vitepress/config/en.ts b/.vitepress/config/en.ts index 9a23cef46..f92d6a907 100644 --- a/.vitepress/config/en.ts +++ b/.vitepress/config/en.ts @@ -1,4 +1,5 @@ import { defineConfig, type DefaultTheme } from 'vitepress' +import { community } from './community' export const config = defineConfig({ lang: 'en-US', @@ -10,56 +11,67 @@ export const config = defineConfig({ { text: 'Prologue', base: '/prologue/', + collapsed: true, items: sidebarPrologue() }, { text: 'Upgrade', base: '/upgrade/', + collapsed: true, items: sidebarUpgrade() }, { text: 'Getting Started', base: '/getting-started/', + collapsed: true, items: sidebarGettingStarted() }, { text: 'Architecture Concepts', base: '/architecture-concepts/', + collapsed: true, items: sidebarFoundation() }, { text: 'The Basics', base: '/the-basics/', + collapsed: true, items: sidebarBasic() }, { text: 'Digging Deeper', base: '/digging-deeper/', + collapsed: true, items: sidebarAdvanced() }, { text: 'AI', base: '/ai/', + collapsed: true, items: sidebarAI() }, { text: 'Security', base: '/security/', + collapsed: true, items: sidebarSecurity() }, { text: 'Database', base: '/database/', + collapsed: true, items: sidebarDatabase() }, { text: 'ORM', base: '/orm/', + collapsed: true, items: sidebarOrm() }, { text: 'Testing', base: '/testing/', + collapsed: true, items: sidebarTesting() } ], @@ -99,44 +111,32 @@ export const config = defineConfig({ function nav(): DefaultTheme.NavItem[] { return [ { - text: 'Quickstart', + text: 'Docs', link: '/getting-started/installation', - activeMatch: '/getting-started/' - }, - { - text: 'Video Tutorials', - items: [ - { - text: 'YouTube', - link: 'https://www.youtube.com/playlist?list=PL40Xne4u-oXJ0Z5uFiPWHqIMvzZaG_BDf' - }, - { - text: 'DevChalk', - link: 'https://devchalk.com/goravel' - }, - ] - }, - { - text: 'Versions', - items: [ - { - text: 'v1.18 (Latest)', - link: 'https://www.goravel.dev/' - }, - { - text: 'v1.17', - link: 'https://v117.goravel.dev/' - }, - { - text: 'v1.16', - link: 'https://v116.goravel.dev/' - }, - ] - }, - { - text: 'Translate', - link: '/prologue/contributions#add-a-new-language' - } + activeMatch: '^/(?!getting-started/packages)(getting-started|architecture-concepts|the-basics|digging-deeper|database|orm|testing|security|ai)/' + }, + { + text: 'Packages', + link: '/getting-started/packages', + activeMatch: '^/getting-started/packages' + }, + { + text: 'Releases', + link: '/prologue/releases', + activeMatch: '^/(prologue/releases|upgrade/)' + }, + community( + { + title: 'Community', + connect: 'Connect', + learn: 'Learn', + videos: 'Video Tutorials', + contribute: 'Contribute', + guide: 'Contribution Guide', + language: 'Add a Language', + languageAnchor: 'add-a-new-language' + } + ) ] } diff --git a/.vitepress/config/goravel-code.ts b/.vitepress/config/goravel-code.ts new file mode 100644 index 000000000..051585ec7 --- /dev/null +++ b/.vitepress/config/goravel-code.ts @@ -0,0 +1,36 @@ +import type { ThemeOptions } from 'vitepress' + +const INK = '#101820' +const GREY = '#68747d' +const CYAN = '#0077b3' +const RED = '#b02b2b' + +const rule = (scope: string[], foreground: string) => ({ scope, settings: { foreground } }) + +export const goravelCode: ThemeOptions = { + name: 'goravel', + type: 'light', + // transparent, so a callout's lighter ground shows through + colors: { 'editor.background': '#00000000', 'editor.foreground': INK }, + tokenColors: [ + { settings: { foreground: INK } }, + rule(['comment', 'punctuation.definition.comment', 'string.comment'], GREY), + rule(['keyword', 'storage', 'constant.language', 'variable.language'], INK), + rule(['entity.name.function', 'support.function', 'entity.name.command'], CYAN), + rule(['string', 'constant.numeric', 'constant.character'], GREY), + rule(['punctuation', 'keyword.operator', 'meta.brace'], GREY), + rule(['markup.inserted', 'meta.diff.header.to-file'], CYAN), + rule(['markup.deleted', 'meta.diff.header.from-file'], RED), + // narrower scopes that override the grey and cyan rules above + rule( + [ + 'entity.name.type', 'entity.name.class', 'entity.name.package', 'entity.name.import.go', + 'support.type', 'support.class', 'storage.type.numeric.go', 'storage.type.string.go', + 'storage.type.boolean.go', 'storage.type.byte.go', 'storage.type.error.go', + 'variable', 'meta.definition.variable', 'punctuation.definition.variable.php', + 'string.unquoted.argument.shell', 'constant.other.option' + ], + INK + ) + ] +} diff --git a/.vitepress/config/shared.ts b/.vitepress/config/shared.ts index 8a25556cd..8160dfea5 100644 --- a/.vitepress/config/shared.ts +++ b/.vitepress/config/shared.ts @@ -1,8 +1,19 @@ +import { + transformerMetaWordHighlight, + transformerNotationWordHighlight +} from '@shikijs/transformers' +import { fileURLToPath, URL } from 'node:url' import { transformerTwoslash } from '@shikijs/vitepress-twoslash' import { createFileSystemTypesCache } from '@shikijs/vitepress-twoslash/cache-fs' import tailwindcss from '@tailwindcss/vite' -import { defineConfig } from 'vitepress' +import { defineConfig, type MarkdownRenderer } from 'vitepress' import timeline from 'vitepress-markdown-timeline' +import deflist from 'markdown-it-deflist' +import footnote from 'markdown-it-footnote' +import sup from 'markdown-it-sup' +import taskLists from 'markdown-it-task-lists' +import { LINKS } from '../links' +import { goravelCode } from './goravel-code' import { groupIconMdPlugin, groupIconVitePlugin @@ -10,6 +21,45 @@ import { // import {enSearch, zh_CNSearch} from './search' +function markCustomContainerTitles(md: MarkdownRenderer) { + for (const name of ['info', 'tip', 'warning', 'danger', 'details']) { + const key = `container_${name}_open` + const original = md.renderer.rules[key] + if (!original) continue + md.renderer.rules[key] = (tokens, idx, options, env, self) => { + const html = original(tokens, idx, options, env, self) + // text after the type on the fence is a custom title + const custom = /^[a-z-]+[ \t]+\S/i.test((tokens[idx].info || '').trim()) + return custom ? html.replace('custom-block', 'custom-block has-custom-title') : html + } + } +} + +// a first line that is only a file path comment, like `// config/app.go`, becomes the block's title +function liftFileNames(md: MarkdownRenderer) { + const fence = md.renderer.rules.fence! + md.renderer.rules.fence = (tokens, idx, options, env, self) => { + const token = tokens[idx] + const path = token.content.match(/^(?:\/\/|#|--) ?([\w.@-]+(?:\/[\w.@-]+)*\.\w+)\n/) + // line highlights like {2,4} count from the first line, so a block using them keeps it + if (!path || /\{[\d,-]+\}/.test(token.info)) return fence(tokens, idx, options, env, self) + token.content = token.content.slice(path[0].length) + return fence(tokens, idx, options, env, self).replace(/[^<]*<\/span>/, `${path[1]}`) + } +} + +// a percentage in the packages table's coverage column gets a bar beside it when the page is built +function drawCoverageBars(md: MarkdownRenderer) { + const close = md.renderer.rules.td_close ?? ((tokens, idx, options, _env, self) => self.renderToken(tokens, idx, options)) + md.renderer.rules.td_close = (tokens, idx, options, env, self) => { + const value = env.relativePath?.includes('getting-started/packages') && tokens[idx - 1].content.match(/^([\d.]+)%$/) + const bar = value + ? `` + : '' + return bar + close(tokens, idx, options, env, self) + } +} + export const shared = defineConfig({ title: 'Goravel', @@ -17,11 +67,23 @@ export const shared = defineConfig({ 'en/:rest*': ':rest*' }, + // there is no dark design + appearance: false, lastUpdated: true, cleanUrls: false, metaChunk: true, head: [ + // the fonts, requested with the page instead of after the stylesheet + ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }], + ['link', { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }], + [ + 'link', + { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Mona+Sans:wdth,wght@75..125,200..900&display=swap' + } + ], [ 'script', { @@ -37,7 +99,11 @@ export const shared = defineConfig({ ], markdown: { + theme: goravelCode, + lineNumbers: true, codeTransformers: [ + transformerNotationWordHighlight(), + transformerMetaWordHighlight(), transformerTwoslash({ typesCache: createFileSystemTypesCache() }) @@ -45,18 +111,21 @@ export const shared = defineConfig({ config(md) { md.use(groupIconMdPlugin) md.use(timeline) + md.use(footnote) + md.use(taskLists, { label: true }) + md.use(sup) + md.use(deflist) + markCustomContainerTitles(md) + liftFileNames(md) + drawCoverageBars(md) }, languages: ['go'] }, themeConfig: { - logo: '/logo.png', + logo: '/logo@2x.png', siteTitle: false, - socialLinks: [ - { icon: 'github', link: 'https://github.com/goravel/goravel' }, - { icon: 'discord', link: 'https://discord.gg/cFc5csczzS' }, - { icon: 'x', link: 'https://x.com/goravelgolang' } - ], + socialLinks: [{ icon: 'github', link: LINKS.github }], search: { provider: 'algolia', options: { @@ -65,10 +134,10 @@ export const shared = defineConfig({ indexName: 'goravel', locales: { root: { - placeholder: 'Search Documentation', + placeholder: 'Search docs', translations: { button: { - buttonText: 'Search' + buttonText: 'Search docs' } } }, @@ -84,7 +153,7 @@ export const shared = defineConfig({ placeholder: 'Fayllarni qidirish', translations: { button: { - buttonText: 'Fayllarni qidirish' + buttonText: 'Hujjatlarda qidirish' } } } @@ -94,6 +163,14 @@ export const shared = defineConfig({ }, vite: { - plugins: [groupIconVitePlugin(), tailwindcss() as any] + plugins: [groupIconVitePlugin(), tailwindcss() as any], + resolve: { + alias: [ + { + find: /^.*\/VPNavBar\.vue$/, + replacement: fileURLToPath(new URL('../theme/components/NavBar.vue', import.meta.url)) + } + ] + } } }) diff --git a/.vitepress/config/uz_UZ.ts b/.vitepress/config/uz_UZ.ts index 3ee325456..97878deaa 100644 --- a/.vitepress/config/uz_UZ.ts +++ b/.vitepress/config/uz_UZ.ts @@ -1,4 +1,5 @@ import { defineConfig, type DefaultTheme } from 'vitepress'; +import { community } from './community' export const config = defineConfig({ lang: "uz-UZ", description: "Goravel — bu to‘liq funksiyalarga ega va yuqori darajada kengaytiriladigan web-ilovalar frameworki hisoblanadi. U Go dasturchilari (gopherlar) uchun boshlang‘ich platforma (scaffolding) sifatida xizmat qiladi va ularga o‘z ilovalarini tez, tartibli va professional tarzda yaratishga yordam beradi.", @@ -7,46 +8,57 @@ export const config = defineConfig({ sidebar: [{ text: "Kirish", base: "/uz_UZ/prologue/", + collapsed: true, items: sidebarPrologue() }, { text: "Yangilash", base: "/uz_UZ/upgrade/", + collapsed: true, items: sidebarUpgrade() }, { text: "Boshlash", base: "/uz_UZ/getting-started/", + collapsed: true, items: sidebarGettingStarted() }, { text: "Arxitektura tushunchalari", base: "/uz_UZ/architecture-concepts/", + collapsed: true, items: sidebarFoundation() }, { text: "Asosiy tushunchalar", base: "/uz_UZ/the-basics/", + collapsed: true, items: sidebarBasic() }, { text: "Chuqurroq o'rganish", base: "/uz_UZ/digging-deeper/", + collapsed: true, items: sidebarAdvanced() }, { text: "AI", base: "/uz_UZ/ai/", + collapsed: true, items: sidebarAI() }, { text: "Xavfsizlik", base: "/uz_UZ/security/", + collapsed: true, items: sidebarSecurity() }, { text: "Ma'lumotlar bazasi", base: "/uz_UZ/database/", + collapsed: true, items: sidebarDatabase() }, { text: 'ORM', base: "/uz_UZ/orm/", + collapsed: true, items: sidebarOrm() }, { text: "Testlash", base: "/uz_UZ/testing/", + collapsed: true, items: sidebarTesting() }], editLink: { @@ -81,36 +93,38 @@ export const config = defineConfig({ } }); function nav(): DefaultTheme.NavItem[] { - return [{ - text: "Tez boshlash", - link: "/uz_UZ/getting-started/installation", - activeMatch: "/uz_UZ/getting-started/" - }, { - text: "Video darsliklar", - items: [{ - text: 'YouTube', - link: 'https://www.youtube.com/playlist?list=PL40Xne4u-oXJ0Z5uFiPWHqIMvzZaG_BDf' - }, { - text: 'DevChalk', - link: 'https://devchalk.com/goravel' - }] - }, { - text: "Versiyalar", - items: [{ - text: "v1.18 (Eng so'nggi)", - link: 'https://www.goravel.dev/' - }, { - text: "v1.17", - link: 'https://v117.goravel.dev/' - }, { - text: 'v1.16', - link: 'https://v116.goravel.dev/' - }] - }, { - text: "Tarjima qilish", - link: "/uz_UZ/prologue/contributions#add-a-new-language" - }]; + return [ + { + text: 'Hujjatlar', + link: '/uz_UZ/getting-started/installation', + activeMatch: '^/uz_UZ/(?!getting-started/packages)(getting-started|architecture-concepts|the-basics|digging-deeper|database|orm|testing|security|ai)/' + }, + { + text: 'Paketlar', + link: '/uz_UZ/getting-started/packages', + activeMatch: '^/uz_UZ/getting-started/packages' + }, + { + text: 'Relizlar', + link: '/uz_UZ/prologue/releases', + activeMatch: '^/uz_UZ/(prologue/releases|upgrade/)' + }, + community( + { + title: 'Hamjamiyat', + connect: 'Aloqa', + learn: "O'rganish", + videos: 'Video darsliklar', + contribute: "Hissa qo'shish", + guide: "Hissa qo'shish bo'yicha qo'llanma", + language: "Til qo'shish", + languageAnchor: 'add-a-new-language' + }, + '/uz_UZ' + ) + ] } + function sidebarGettingStarted(): DefaultTheme.SidebarItem[] { return [{ text: "O'rnatish", diff --git a/.vitepress/config/zh_CN.ts b/.vitepress/config/zh_CN.ts index dc70bd581..5180fe9a1 100644 --- a/.vitepress/config/zh_CN.ts +++ b/.vitepress/config/zh_CN.ts @@ -1,4 +1,5 @@ import { defineConfig, type DefaultTheme } from 'vitepress'; +import { community } from './community' export const config = defineConfig({ lang: "zh-CN", description: "Goravel 是一个功能完整且可扩展性极强的 Web 应用程序框架。作为一个起始脚手架,帮助 Gopher 快速构建自己的应用程序。", @@ -7,46 +8,57 @@ export const config = defineConfig({ sidebar: [{ text: "序言", base: "/zh_CN/prologue/", + collapsed: true, items: sidebarPrologue() }, { text: "升级", base: "/zh_CN/upgrade/", + collapsed: true, items: sidebarUpgrade() }, { text: "快速开始", base: "/zh_CN/getting-started/", + collapsed: true, items: sidebarGettingStarted() }, { text: "核心架构", base: "/zh_CN/architecture-concepts/", + collapsed: true, items: sidebarFoundation() }, { text: "基础功能", base: "/zh_CN/the-basics/", + collapsed: true, items: sidebarBasic() }, { text: "高级功能", base: "/zh_CN/digging-deeper/", + collapsed: true, items: sidebarAdvanced() - }, { - text: "安全", - base: "/zh_CN/security/", - items: sidebarSecurity() }, { text: 'AI', base: '/zh_CN/ai/', + collapsed: true, items: sidebarAI() + }, { + text: "安全", + base: "/zh_CN/security/", + collapsed: true, + items: sidebarSecurity() }, { text: "数据库", base: "/zh_CN/database/", + collapsed: true, items: sidebarDatabase() }, { text: 'ORM', base: "/zh_CN/orm/", + collapsed: true, items: sidebarOrm() }, { text: "测试", base: "/zh_CN/testing/", + collapsed: true, items: sidebarTesting() }], editLink: { @@ -81,36 +93,39 @@ export const config = defineConfig({ } }); function nav(): DefaultTheme.NavItem[] { - return [{ - text: "快速开始", - link: "/zh_CN/getting-started/installation", - activeMatch: "/zh_CN/getting-started/" - }, { - text: "视频教程", - items: [{ - text: 'YouTube', - link: "https://space.bilibili.com/1886603340/channel/seriesdetail?sid=4302621&ctype=0" - }, { - text: 'DevChalk', - link: 'https://devchalk.com/goravel' - }] - }, { - text: "版本", - items: [{ - text: "v1.18 (最新)", - link: 'https://www.goravel.dev/' - }, { - text: "v1.17", - link: 'https://v117.goravel.dev/' - }, { - text: 'v1.16', - link: 'https://v116.goravel.dev/' - }] - }, { - text: "翻译", - link: "/zh_CN/prologue/contributions#新增语言" - }]; + return [ + { + text: '文档', + link: '/zh_CN/getting-started/installation', + activeMatch: '^/zh_CN/(?!getting-started/packages)(getting-started|architecture-concepts|the-basics|digging-deeper|database|orm|testing|security|ai)/' + }, + { + text: '扩展包', + link: '/zh_CN/getting-started/packages', + activeMatch: '^/zh_CN/getting-started/packages' + }, + { + text: '版本发布', + link: '/zh_CN/prologue/releases', + activeMatch: '^/zh_CN/(prologue/releases|upgrade/)' + }, + community( + { + title: '社区', + connect: '联系', + learn: '学习', + videos: '视频教程', + contribute: '参与贡献', + guide: '贡献指南', + language: '新增语言', + languageAnchor: '新增语言' + }, + '/zh_CN', + 'bilibili' + ) + ] } + function sidebarGettingStarted(): DefaultTheme.SidebarItem[] { return [{ text: "安装", diff --git a/.vitepress/links.ts b/.vitepress/links.ts new file mode 100644 index 000000000..5cf1fb36a --- /dev/null +++ b/.vitepress/links.ts @@ -0,0 +1,15 @@ +export const LINKS = { + github: 'https://github.com/goravel/goravel', + discord: 'https://discord.gg/cFc5csczzS', + x: 'https://x.com/goravel_dev', + openCollective: 'https://opencollective.com/goravel', + devchalk: 'https://devchalk.com/goravel', + youtube: 'https://www.youtube.com/playlist?list=PL40Xne4u-oXJ0Z5uFiPWHqIMvzZaG_BDf', + bilibili: 'https://space.bilibili.com/1886603340/channel/seriesdetail?sid=4302621&ctype=0' +} + +export const VERSIONS = [ + { text: 'v1.18', note: 'Latest', link: 'https://www.goravel.dev/', selected: true }, + { text: 'v1.17', link: 'https://v117.goravel.dev/' }, + { text: 'v1.16', link: 'https://v116.goravel.dev/' } +] diff --git a/.vitepress/theme/Layout.vue b/.vitepress/theme/Layout.vue new file mode 100644 index 000000000..5ee90bc50 --- /dev/null +++ b/.vitepress/theme/Layout.vue @@ -0,0 +1,18 @@ + + + diff --git a/.vitepress/theme/components/Brand.vue b/.vitepress/theme/components/Brand.vue new file mode 100644 index 000000000..e9baa8e73 --- /dev/null +++ b/.vitepress/theme/components/Brand.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/.vitepress/theme/components/DocMeta.vue b/.vitepress/theme/components/DocMeta.vue new file mode 100644 index 000000000..094989bc0 --- /dev/null +++ b/.vitepress/theme/components/DocMeta.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/.vitepress/theme/components/DocsFooterLinks.vue b/.vitepress/theme/components/DocsFooterLinks.vue new file mode 100644 index 000000000..184c2f90a --- /dev/null +++ b/.vitepress/theme/components/DocsFooterLinks.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/.vitepress/theme/components/MethodIndex.vue b/.vitepress/theme/components/MethodIndex.vue new file mode 100644 index 000000000..58c8307c4 --- /dev/null +++ b/.vitepress/theme/components/MethodIndex.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/.vitepress/theme/components/NavBar.vue b/.vitepress/theme/components/NavBar.vue new file mode 100644 index 000000000..69fee9b93 --- /dev/null +++ b/.vitepress/theme/components/NavBar.vue @@ -0,0 +1,400 @@ + + + + + diff --git a/.vitepress/theme/components/NotFound.vue b/.vitepress/theme/components/NotFound.vue new file mode 100644 index 000000000..1be963dac --- /dev/null +++ b/.vitepress/theme/components/NotFound.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/.vitepress/theme/components/SelectMenu.vue b/.vitepress/theme/components/SelectMenu.vue new file mode 100644 index 000000000..0ab6adf14 --- /dev/null +++ b/.vitepress/theme/components/SelectMenu.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/.vitepress/theme/dismiss.ts b/.vitepress/theme/dismiss.ts new file mode 100644 index 000000000..ab6329438 --- /dev/null +++ b/.vitepress/theme/dismiss.ts @@ -0,0 +1,12 @@ +import { onClickOutside, onKeyStroke } from '@vueuse/core' +import type { Ref } from 'vue' + +// Closes a menu on Escape, on a click outside it, and when keyboard focus leaves it. +// A click outside is watched directly, since Safari does not focus a clicked button. +export function useDismiss(root: Ref, close: () => void) { + onClickOutside(root, close) + onKeyStroke('Escape', close) + return (event: FocusEvent) => { + if (!root.value?.contains(event.relatedTarget as Node)) close() + } +} diff --git a/.vitepress/theme/goravel.css b/.vitepress/theme/goravel.css new file mode 100644 index 000000000..ddc8db6ea --- /dev/null +++ b/.vitepress/theme/goravel.css @@ -0,0 +1,979 @@ +:root { + --g-white: #ffffff; + --g-soft: #f7f9fa; + --g-hover: #eef2f5; + --g-ink: #101820; + --g-grey: #68747d; + --g-line: #e5eaed; + --g-cyan: #009fe8; + --g-cyan-text: #0077b3; + --g-cyan-tint: #ebf7fd; + --g-construct: rgba(104, 116, 125, 0.4); + + --g-amber: #e08700; + --g-amber-text: #8f5a00; + --g-amber-tint: #fdf6eb; + --g-red: #dc3a3a; + --g-red-text: #b02b2b; + --g-red-tint: #fdeeee; + + --g-shell-inset: 40px; + --g-control: 34px; + --g-gutter: 64px; /* sidebar rule to the text */ + --g-measure: 704px; /* about 68 characters at 17px */ + --g-rail: 32px; /* column rule to the outline */ + --g-aside: 368px; /* outline 240 + rail 32 + margin 96 */ + --g-frame: 1440px; /* the widest the site gets; wider screens frame it */ + --g-frame-x: 0px; /* where the fixed nav and sidebar start; see the frame in shell.css */ + --g-col: calc(var(--g-measure) + var(--g-gutter) + var(--g-rail)); + + --vp-font-family-base: 'Mona Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, + 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans SC', sans-serif; + --vp-font-family-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace; + + --vp-c-brand-1: var(--g-cyan-text); + --vp-c-brand-2: var(--g-ink); + --vp-c-brand-3: var(--g-cyan); + --vp-c-brand-soft: var(--g-cyan-tint); + --vp-c-text-1: var(--g-ink); + --vp-c-text-2: var(--g-grey); + --vp-c-text-3: var(--g-grey); + --vp-c-divider: var(--g-line); + --vp-c-gutter: var(--g-line); + --vp-c-border: var(--g-line); + --vp-c-bg: var(--g-white); + --vp-c-bg-alt: var(--g-white); + --vp-c-bg-soft: var(--g-soft); + --vp-c-bg-elv: var(--g-white); + + --vp-code-block-color: var(--g-ink); + --vp-code-line-highlight-color: var(--g-cyan-tint); + --vp-code-line-number-color: var(--g-grey); + --vp-code-copy-code-hover-bg: var(--g-white); + --vp-code-tab-divider: var(--g-line); + --vp-code-tab-text-color: var(--g-grey); + --vp-code-tab-active-text-color: var(--g-ink); + --vp-code-tab-active-bar-color: var(--g-cyan); + + --vp-nav-height: 64px; + --vp-sidebar-width: 272px; +} + +/* ------------------------------------------------------------------ labels and marks */ +.g-label, +.vp-doc .custom-block .custom-block-title, +.vp-doc th, +.vp-doc .footnotes::before, +.VPDocAsideOutline .outline-title, +.goravel-methods .outline-title, +.VPNavScreenMenuGroupSection .title { + font-family: var(--vp-font-family-mono); + font-size: 12px; + font-weight: 500; + letter-spacing: 0.13em; + text-transform: uppercase; + color: var(--g-grey); +} + +.g-diamond { + display: flex; + align-items: center; + gap: 8px; +} + +/* the lattice cell, the one marker shape on the site */ +.g-diamond::before, +.vp-doc .custom-block .custom-block-title::before, +.VPDocAsideOutline .outline-title::before, +.goravel-methods .outline-title::before, +.VPNavScreenMenuGroupSection .title::before, +.VPSidebarItem.level-1.is-active > .item::before, +.VPDocOutlineItem .outline-link.active::before { + content: ''; + flex-shrink: 0; + width: 6px; + height: 6px; + background: currentColor; + transform: rotate(45deg); +} + +/* ------------------------------------------------------------------ bands */ +.VPDoc { + --g-left: var(--g-gutter); + --g-right: var(--g-rail); +} + +@media (max-width: 959px) { + .VPDoc { + --g-left: 24px; + --g-right: 24px; + } +} + +.vp-doc h2, +.vp-doc hr, +.vp-doc blockquote, +.vp-doc .custom-block, +.vp-doc .footnotes, +.vp-doc p:has(> strong:only-child):not(li > p):not(blockquote p):not(.custom-block p) { + margin-left: calc(var(--g-left) * -1); + margin-right: calc(var(--g-right) * -1); + padding-left: var(--g-left); + padding-right: var(--g-right); +} + +/* the theme scopes .edit-info and giscus sets inline styles */ +.VPDocFooter .edit-info, +.VPDocFooter .prev-next, +#giscus { + margin-left: calc(var(--g-left) * -1) !important; + margin-right: calc(var(--g-right) * -1) !important; + padding-left: var(--g-left) !important; + padding-right: var(--g-right) !important; +} + +/* ------------------------------------------------------------------ type */ +.vp-doc h1 { + margin-bottom: 12px; + font-size: 48px; + line-height: 52px; + font-weight: 700; + font-stretch: 108%; + letter-spacing: -0.035em; +} + +.vp-doc h1 + p, +.vp-doc h2:first-of-type + p { + font-size: 18px; + line-height: 30px; + color: var(--g-grey); +} + +.vp-doc h2 { + margin-top: 36px; + padding-top: 24px; + font-size: 28px; + line-height: 36px; + font-weight: 650; +} + +.vp-doc h3 { + margin-top: 44px; + margin-bottom: 10px; + line-height: 30px; + font-weight: 650; +} + +.vp-doc h4 { + margin-top: 28px; + font-size: 17px; + font-weight: 650; +} + +.vp-doc h2 + p, +.vp-doc h3 + p, +.vp-doc h4 + p { + margin-top: 10px; +} + +.vp-doc h2 + div[class*='language-'], +.vp-doc h3 + div[class*='language-'], +.vp-doc h2 + .vp-code-group, +.vp-doc h3 + .vp-code-group { + margin-top: 14px; +} + +.vp-doc .header-anchor { + color: var(--g-cyan-text); + font-weight: 400; +} + +.vp-doc p, +.vp-doc li { + font-size: 17px; + line-height: 29px; +} + +.vp-doc strong { + font-weight: 650; +} + +.vp-doc a { + font-weight: 400; + text-decoration: underline 1px rgba(0, 119, 179, 0.32); + text-underline-offset: 3px; +} + +.vp-doc a:hover { + text-decoration-color: var(--g-cyan-text); +} + +.vp-doc :not(pre) > code { + padding: 2px 6px; + border-radius: 0; + background: var(--g-soft); + font-size: 14px; + color: var(--g-ink); +} + +.vp-doc p:has(> strong:only-child):not(li > p):not(blockquote p):not(.custom-block p) { + margin-top: 36px; + padding-top: 18px; + border-top: 1px solid var(--g-line); +} + +.vp-doc p:has(> strong:only-child) > strong { + font-family: var(--vp-font-family-mono); + font-size: 16px; + font-weight: 600; + letter-spacing: -0.01em; +} + +.vp-doc p:has(> strong:only-child) > strong::after { + content: '#'; + margin-left: 10px; + font-family: var(--vp-font-family-mono); + font-size: 14px; + font-weight: 400; + color: var(--g-cyan-text); + opacity: 0; +} + +.vp-doc p:has(> strong:only-child):hover > strong::after { + opacity: 1; +} + +/* ------------------------------------------------------------------ code */ +/* The ground and rules are painted past the box, so the text keeps the article's edge. */ +.vp-doc { + --g-code-ground: var(--g-soft); + --g-code-left: var(--g-left); + --g-code-right: var(--g-right); +} + +.vp-doc div[class*='language-'] { + position: relative; + overflow: visible; + margin: 28px 0; + padding-top: 44px; + border-radius: 0; + background: var(--g-code-ground); + box-shadow: + calc(var(--g-code-left) * -1) 0 0 0 var(--g-code-ground), + var(--g-code-right) 0 0 0 var(--g-code-ground); +} + +.vp-doc div[class*='language-']::before, +.vp-doc div[class*='language-']::after { + content: ''; + position: absolute; + left: calc(var(--g-code-left) * -1); + right: calc(var(--g-code-right) * -1); + pointer-events: none; +} + +.vp-doc div[class*='language-']::before { + top: 0; + bottom: 0; + border-top: 1px solid var(--g-line); + border-bottom: 1px solid var(--g-line); +} + +.vp-doc div[class*='language-']::after { + top: 43px; + z-index: 2; + border-top: 1px solid var(--g-line); +} + +.vp-doc div[class*='language-'] > pre { + padding-left: 0; +} + +.vp-doc [class*='language-'] code { + font-size: 14px; + line-height: 24px; +} + +.vp-doc [class*='language-'] > .line-numbers-wrapper { + top: 44px; + width: 40px; + padding-top: 20px; + border-right: 1px solid var(--g-line); + font-family: var(--vp-font-family-mono); + font-size: 12px; + line-height: 24px; + text-align: center; +} + +.vp-doc [class*='language-'] > span.lang { + top: 14px; + right: auto; + left: 0; + font-family: var(--vp-font-family-mono); + font-size: 12px; + letter-spacing: 0.02em; + color: var(--g-grey); +} + +/* the theme hides the language on hover */ +.vp-doc [class*='language-'] > span.lang, +.vp-doc [class*='language-']:hover > button.copy + span.lang, +.vp-doc [class*='language-'] > button.copy:focus + span.lang { + opacity: 1; +} + +.vp-doc [class*='language-'] > button.copy { + top: 6px; + right: 12px; + width: 32px; + height: 32px; + border: 0; + border-radius: 0; + background-color: transparent; + opacity: 1; +} + +.vp-doc div[class*='language-']:has(> span.lang:empty) { + padding-top: 0; +} + +.vp-doc div[class*='language-']:has(> span.lang:empty)::after { + content: none; +} + +.vp-doc div[class*='language-']:has(> span.lang:empty) > button.copy { + top: 10px; +} + +.vp-doc div[class*='language-']:has(> span.lang:empty) > .line-numbers-wrapper { + top: 0; +} + +.vp-doc [class*='language-'] .line.diff.add { + background: var(--g-cyan-tint); +} + +.vp-doc [class*='language-'] .line.diff.remove, +.vp-doc [class*='language-'] .line.error { + background: var(--g-red-tint); +} + +.vp-doc [class*='language-'] .line.warning { + background: var(--g-amber-tint); +} + +.vp-doc [class*='language-'] .line.diff.remove { + opacity: 0.7; +} + +.vp-doc [class*='language-'] pre:has(.line.diff) code { + padding-left: 36px; +} + +.vp-doc [class*='language-'] .line.diff::before { + left: 12px; + font-weight: 600; +} + +.vp-doc [class*='language-'] .line.diff.add::before { + color: var(--g-cyan-text); +} + +.vp-doc [class*='language-'] .line.diff.remove::before { + color: var(--g-red-text); +} + +.vp-doc [class*='language-'] .highlighted-word { + padding: 1px 2px; + border-bottom: 1px solid var(--g-cyan); + background: var(--g-cyan-tint); +} + +.vp-doc .vp-code-group { + position: relative; + margin: 28px 0; + background: var(--g-code-ground); + box-shadow: + calc(var(--g-code-left) * -1) 0 0 0 var(--g-code-ground), + var(--g-code-right) 0 0 0 var(--g-code-ground); +} + +.vp-doc .vp-code-group::before { + content: ''; + position: absolute; + top: 0; + left: calc(var(--g-code-left) * -1); + right: calc(var(--g-code-right) * -1); + border-top: 1px solid var(--g-line); +} + +.vp-code-group .tabs { + margin: 0; + padding: 0; + border-radius: 0; + background: transparent; + box-shadow: none; +} + +/* tab text starts on the article's edge, like the block's own label */ +.vp-code-group .tabs label { + padding: 0 24px 0 0; + font-family: var(--vp-font-family-mono); + font-size: 12px; + letter-spacing: 0.02em; +} + +.vp-code-group .tabs label::after { + left: 0; + right: 24px; +} + +.vp-doc .vp-code-group div[class*='language-'] { + margin: 0 !important; + border-radius: 0; + background: transparent; + box-shadow: none; +} + +.vp-doc div[class*='language-markdown']::before { + border-top: 2px solid var(--g-ink); +} + +.vp-doc div[class*='language-markdown'] > span.lang { + font-size: 0; + font-weight: 500; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--g-ink); +} + +.vp-doc div[class*='language-markdown'] > span.lang::after { + content: 'Guide for your AI agent'; + font-size: 12px; +} + +.vp-doc div[class*='language-markdown'].line-numbers-mode { + padding-left: 0; +} + +.vp-doc div[class*='language-markdown'] > .line-numbers-wrapper { + display: none; +} + +.vp-doc div[class*='language-markdown'] pre { + max-height: 432px; + overflow-y: auto; +} + +.vp-doc div[class*='language-markdown'] code { + padding: 0; + white-space: pre-wrap; + overflow-wrap: anywhere; +} + +@media (max-width: 959px) { + .vp-doc { + --g-code-left: 0px; + --g-code-right: 0px; + } + + .vp-doc div[class*='language-'], + .vp-doc .vp-code-group { + margin-left: -24px !important; + margin-right: -24px !important; + } + + .vp-doc div[class*='language-'] { + padding-left: 0 !important; + } + + .vp-code-group .tabs { + padding-left: 24px; + } + + .vp-doc div[class*='language-'] > .line-numbers-wrapper { + display: none; + } + + .vp-doc div[class*='language-'] > span.lang { + left: 24px; + } + + .vp-doc div[class*='language-'] code { + padding: 0 24px !important; + } + + .vp-doc [class*='language-'] pre:has(.line.diff) code { + padding-left: 34px !important; + } +} + +/* ------------------------------------------------------------------ callouts */ +/* callouts and blockquote notes are bands with a rule above and below */ +.vp-doc .custom-block, +.vp-doc blockquote { + margin-top: 28px; + margin-bottom: 28px; + border: 0; + border-top: 1px solid var(--g-line); + border-bottom: 1px solid var(--g-line); + background: var(--g-white); +} + +.vp-doc .custom-block { + --g-code-ground: rgba(255, 255, 255, 0.66); + padding-top: 16px; + padding-bottom: 18px; + border-radius: 0; + font-size: 16px; + line-height: 28px; +} + +.vp-doc .custom-block.tip { + border-top: 2px solid var(--g-cyan); + border-bottom-color: var(--g-cyan); + background: var(--g-cyan-tint); +} + +.vp-doc .custom-block.warning { + border-top: 2px solid var(--g-amber); + border-bottom-color: var(--g-amber); + background: var(--g-amber-tint); +} + +.vp-doc .custom-block.danger { + border-top: 2px solid var(--g-red); + border-bottom-color: var(--g-red); + background: var(--g-red-tint); +} + +.vp-doc .custom-block .custom-block-title { + display: flex; + align-items: center; + gap: 10px; + line-height: 16px; +} + +.vp-doc .custom-block.tip .custom-block-title { + color: var(--g-cyan-text); +} + +.vp-doc .custom-block.warning .custom-block-title { + color: var(--g-amber-text); +} + +.vp-doc .custom-block.danger .custom-block-title { + color: var(--g-red-text); +} + +.vp-doc .custom-block .custom-block-title::before { + width: 8px; + height: 8px; +} + +.vp-doc .custom-block.info .custom-block-title::before { + background: transparent; + box-shadow: inset 0 0 0 1.25px currentColor; +} + +.vp-doc .custom-block.has-custom-title .custom-block-title { + margin-bottom: 6px; + font-family: var(--vp-font-family-base); + font-size: 16px; + line-height: 26px; + font-weight: 650; + letter-spacing: -0.005em; + text-transform: none; +} + +.vp-doc .custom-block.has-custom-title .custom-block-title::before { + width: 9px; + height: 9px; +} + +.vp-doc .custom-block p { + margin: 0; +} + +.vp-doc .custom-block p + p { + margin-top: 8px; +} + +.vp-doc .custom-block code { + background: rgba(255, 255, 255, 0.72); +} + +.vp-doc .custom-block.info code { + background: var(--g-soft); +} + +.vp-doc .custom-block div[class*='language-'], +.vp-doc .custom-block .vp-code-group { + margin-top: 14px; + margin-bottom: 14px; +} + +.vp-doc .custom-block.details { + padding-top: 14px; + padding-bottom: 16px; +} + +.vp-doc .custom-block.details summary { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 0; + font-size: 16px; + line-height: 26px; + font-weight: 500; + color: var(--g-ink); + list-style: none; +} + +.vp-doc .custom-block.details[open] summary { + margin-bottom: 10px; +} + +.vp-doc .custom-block.details summary::-webkit-details-marker { + display: none; +} + +.vp-doc .custom-block.details summary::before, +.vp-doc .custom-block.details summary::after { + content: ''; + flex-shrink: 0; + color: var(--g-grey); + transition: background-color 0.15s ease, transform 0.2s ease; +} + +.vp-doc .custom-block.details summary:hover::before, +.vp-doc .custom-block.details summary:hover::after { + color: var(--g-ink); +} + +.vp-doc .custom-block.details summary::before { + width: 8px; + height: 8px; + box-shadow: inset 0 0 0 1.25px currentColor; + transform: rotate(45deg); +} + +.vp-doc .custom-block.details[open] summary::before { + background: currentColor; +} + +.vp-doc .custom-block.details summary::after { + width: 6px; + height: 6px; + margin: 0 2px 0 auto; + border-right: 1.5px solid currentColor; + border-bottom: 1.5px solid currentColor; + transform: rotate(-45deg); +} + +.vp-doc .custom-block.details[open] summary::after { + transform: rotate(45deg); +} + +.vp-doc blockquote { + padding-top: 14px; + padding-bottom: 16px; + color: var(--g-ink); +} + +.vp-doc blockquote > p { + margin: 0; + font-size: 17px; + line-height: 29px; +} + +.vp-doc blockquote > p + p { + margin-top: 10px; +} + +.vp-doc blockquote blockquote { + margin: 12px 0 0; + padding: 0 0 0 18px; + border: 0; + border-left: 2px solid var(--g-line); +} + +.vp-doc blockquote blockquote > p { + color: var(--g-grey); +} + +/* ------------------------------------------------------------------ tables */ +.vp-doc table { + display: table; + width: calc(100% + var(--g-left) + var(--g-right)); + max-width: calc(100% + var(--g-left) + var(--g-right)); + margin: 24px calc(var(--g-right) * -1) 24px calc(var(--g-left) * -1); + border-collapse: collapse; +} + +.vp-doc tr, +.vp-doc tr:nth-child(2n) { + border: 0; + border-top: 1px solid var(--g-line); + background: transparent; +} + +.vp-doc thead tr { + border-top: 0; +} + +.vp-doc th, +.vp-doc td { + border: 0; + white-space: normal; + overflow-wrap: anywhere; +} + +.vp-doc th { + padding: 0 24px 10px 0; + background: transparent; + text-align: left; +} + +.vp-doc td { + padding: 10px 24px 10px 0; + font-size: 15px; + line-height: 24px; +} + +.vp-doc th:first-child, +.vp-doc td:first-child { + padding-left: var(--g-left); +} + +.vp-doc th:last-child, +.vp-doc td:last-child { + padding-right: var(--g-right); +} + +.vp-doc th code, +.vp-doc td code, +.vp-doc th a, +.vp-doc td a { + white-space: normal; + overflow-wrap: anywhere; +} + +.vp-doc td:first-child > a { + overflow-wrap: normal; +} + +.vp-doc td:has(> .goravel-coverage) { + white-space: nowrap; +} + +.goravel-coverage { + display: inline-flex; + align-items: center; + margin-left: 10px; + vertical-align: middle; +} + +.goravel-coverage .track { + display: block; + width: 72px; + height: 2px; + background: var(--g-line); +} + +.goravel-coverage .fill { + display: block; + height: 2px; + background: var(--g-cyan); +} + +/* ------------------------------------------------------------------ footnotes, tasks, terms */ +.vp-doc .footnotes-sep { + display: none; +} + +.vp-doc .footnotes { + margin-top: 48px; + padding-top: 22px; + border-top: 1px solid var(--g-line); +} + +.vp-doc .footnotes::before { + content: 'Notes'; + display: block; + margin-bottom: 12px; +} + +.vp-doc .footnotes ol { + margin: 0; + padding-left: 18px; +} + +.vp-doc .footnotes li, +.vp-doc .footnotes p { + font-size: 15px; + line-height: 25px; + color: var(--g-grey); +} + +.vp-doc .footnotes li + li { + margin-top: 6px; +} + +.vp-doc .footnote-backref, +.vp-doc .footnote-ref a { + text-decoration: none; +} + +.vp-doc .footnote-backref { + margin-left: 6px; +} + +.vp-doc .footnote-ref a { + padding: 0 1px; + font-family: var(--vp-font-family-mono); + font-size: 11px; +} + +.vp-doc .footnote-ref a:hover { + text-decoration: underline; +} + +.vp-doc .contains-task-list { + padding-left: 0; + list-style: none; +} + +.vp-doc .task-list-item { + display: flex; + align-items: flex-start; + gap: 12px; +} + +.vp-doc .task-list-item + .task-list-item { + margin-top: 6px; +} + +/* (line height 29 - box 15) / 2 */ +.vp-doc .task-list-item input[type='checkbox'] { + appearance: none; + flex-shrink: 0; + width: 15px; + height: 15px; + margin: 7px 0 0; + border: 1.5px solid var(--g-line); + border-radius: 2px; + background: var(--g-white) center / 11px no-repeat; +} + +.vp-doc .task-list-item input[type='checkbox']:checked { + border-color: var(--g-cyan); + background-color: var(--g-cyan); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-6'/%3E%3C/svg%3E"); +} + +.vp-doc dl { + margin: 20px 0; +} + +.vp-doc dt { + margin-top: 16px; + font-weight: 650; +} + +.vp-doc dd { + margin: 4px 0 0; + padding-left: 18px; + border-left: 2px solid var(--g-line); + color: var(--g-grey); +} + +/* ------------------------------------------------------------------ the end of a page */ +.VPDocFooter .edit-info { + padding-top: 20px; + padding-bottom: 20px; + border-top: 1px solid var(--g-line); +} + +.VPDocFooter .edit-link-button { + font-size: 15px; + font-weight: 500; + color: var(--g-ink) !important; +} + +.VPDocFooter .edit-link-icon { + display: none; +} + +.VPDocFooter .last-updated, +.VPDocFooter .pager-link .desc { + font-family: var(--vp-font-family-mono); + font-size: 12px; + letter-spacing: 0.02em; + color: var(--g-grey); +} + +/* one rule across the band, with the page ahead marked on it in cyan */ +.VPDocFooter .prev-next { + gap: 0 !important; + padding-top: 0; + border-top: 1px solid var(--g-line); +} + +.VPDocFooter .pager-link { + display: block; + width: auto !important; + padding: 20px 0 0; + border: 0; + border-radius: 0; + background: transparent; +} + +.VPDocFooter .pager-link.next { + margin: -1px calc(var(--g-right) * -1) 0 0; + padding: 20px var(--g-right) 0 24px; + border-top: 2px solid var(--g-cyan); + text-align: right; +} + +/* stacked on a phone, the cyan rule would float between the two links, so it runs edge to edge */ +@media (max-width: 639px) { + .VPDocFooter .pager-link.next { + margin: 20px calc(var(--g-right) * -1) 0 calc(var(--g-left) * -1); + padding-left: var(--g-left); + } +} + +.VPDocFooter .pager-link .title { + font-size: 18px; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--g-ink); +} + +#giscus { + margin-top: 40px; + padding-top: 28px !important; + border-top: 1px solid var(--g-line) !important; +} + +/* ------------------------------------------------------------------ Chinese */ +/* negative tracking crowds CJK glyphs */ +:lang(zh) .g-home .g-display, +:lang(zh) .g-home .g-h2, +:lang(zh) .g-home .g-h3, +:lang(zh) .vp-doc h1, +:lang(zh) .vp-doc h2, +:lang(zh) .vp-doc h3, +:lang(zh) .VPDocFooter .pager-link .title, +:lang(zh) .vp-doc .custom-block.has-custom-title .custom-block-title { + letter-spacing: 0; +} + +:lang(zh) .g-home .g-display { + line-height: 1.12; +} + +:lang(zh) .g-home .g-h2 { + line-height: 1.25; +} diff --git a/.vitepress/theme/home/CodeLines.vue b/.vitepress/theme/home/CodeLines.vue new file mode 100644 index 000000000..2099684c4 --- /dev/null +++ b/.vitepress/theme/home/CodeLines.vue @@ -0,0 +1,31 @@ + + + diff --git a/.vitepress/theme/home/GoravelMark.vue b/.vitepress/theme/home/GoravelMark.vue new file mode 100644 index 000000000..8b6dddfa7 --- /dev/null +++ b/.vitepress/theme/home/GoravelMark.vue @@ -0,0 +1,114 @@ + + + diff --git a/.vitepress/theme/home/Home.vue b/.vitepress/theme/home/Home.vue new file mode 100644 index 000000000..c86b152f9 --- /dev/null +++ b/.vitepress/theme/home/Home.vue @@ -0,0 +1,21 @@ + + + diff --git a/.vitepress/theme/home/HomeFacades.vue b/.vitepress/theme/home/HomeFacades.vue new file mode 100644 index 000000000..3ff832b13 --- /dev/null +++ b/.vitepress/theme/home/HomeFacades.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/.vitepress/theme/home/HomeFooter.vue b/.vitepress/theme/home/HomeFooter.vue new file mode 100644 index 000000000..94d3b20a4 --- /dev/null +++ b/.vitepress/theme/home/HomeFooter.vue @@ -0,0 +1,31 @@ + + + diff --git a/.vitepress/theme/home/HomeHero.vue b/.vitepress/theme/home/HomeHero.vue new file mode 100644 index 000000000..6eb4da6d4 --- /dev/null +++ b/.vitepress/theme/home/HomeHero.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/.vitepress/theme/home/HomeLaravel.vue b/.vitepress/theme/home/HomeLaravel.vue new file mode 100644 index 000000000..8bbb013cc --- /dev/null +++ b/.vitepress/theme/home/HomeLaravel.vue @@ -0,0 +1,280 @@ + + + + + diff --git a/.vitepress/theme/home/HomeLite.vue b/.vitepress/theme/home/HomeLite.vue new file mode 100644 index 000000000..10bf30c70 --- /dev/null +++ b/.vitepress/theme/home/HomeLite.vue @@ -0,0 +1,261 @@ + + + + + diff --git a/.vitepress/theme/home/HomeOpenSource.vue b/.vitepress/theme/home/HomeOpenSource.vue new file mode 100644 index 000000000..cbfcacc95 --- /dev/null +++ b/.vitepress/theme/home/HomeOpenSource.vue @@ -0,0 +1,600 @@ + + + + + diff --git a/.vitepress/theme/home/config.ts b/.vitepress/theme/home/config.ts new file mode 100644 index 000000000..8389d7ee4 --- /dev/null +++ b/.vitepress/theme/home/config.ts @@ -0,0 +1,255 @@ +import { LINKS } from '../../links' + +export type PieceKey = 'http' | 'app' | 'core' | 'data' | 'async' +export type PieceState = 'solid' | 'dim' | 'ghost' + +interface Concept { + name: string + phpFile: string + goFile: string + php: string + go: string + ties: [number, number][] +} + +interface Capability { + title: string + says: string + code: string + lit?: number[] + facade?: string +} + +interface LiteStep { + cmd: string + pick?: string + add: string[] +} + +export const HERO = { + title: ['Familiar structure.', 'Native Go.'], + lead: 'Routing, an ORM, validation, queues, events and cache, in one framework.', + cta: { text: 'Get started', link: '/getting-started/installation.html' }, + install: 'go install github.com/goravel/installer/goravel@latest' +} + +const CONCEPTS: Concept[] = [ + { + name: 'Routing', phpFile: 'routes/web.php', goFile: 'routes/web.go', + php: "Route::{{middleware}}('auth')->{{group}}(function () {\n Route::{{get}}('/tasks', [TaskController::class, 'index']);\n});", + go: '[[facades.Route]]().[[Middleware]](middleware.Auth()).\n\t[[Group]](func(router route.Router) {\n\t\trouter.[[Get]]("/tasks", taskController.Index)\n\t})', + ties: [[1, 1], [1, 2], [2, 3]] + }, + { + name: 'ORM', phpFile: 'app/Services/TaskService.php', goFile: 'app/services/task_service.go', + php: "$tasks = Task::{{where}}('done', false)\n ->{{orderByDesc}}('created_at')\n ->{{limit}}(20)\n ->{{get}}();", + go: 'var tasks []models.Task\n[[facades.Orm]]().[[Query]]().\n\t[[Where]]("done", false).\n\t[[OrderByDesc]]("created_at").\n\t[[Limit]](20).\n\t[[Get]](&tasks)', + ties: [[1, 3], [2, 4], [3, 5], [4, 6]] + }, + { + name: 'Validation', phpFile: 'app/Http/Controllers/TaskController.php', goFile: 'app/http/controllers/task_controller.go', + php: "$validated = $request->{{validate}}([\n 'title' => 'required|max:255',\n 'due_at' => 'required|date',\n]);", + go: 'validator, err := ctx.[[Request]]().[[Validate]](map[string]any{\n\t"title": "required|max:255",\n\t"due_at": "required|date",\n})\nif validator.[[Fails]]() {\n\treturn ctx.[[Response]]().[[Status]](422).\n\t\t[[Json]](validator.Errors().All())\n}', + ties: [[1, 1], [2, 2], [3, 3]] + }, + { + name: 'Queues', phpFile: 'app/Services/TaskService.php', goFile: 'app/services/task_service.go', + php: "SyncTasks::{{dispatch}}($task)\n ->{{onQueue}}('sync');", + go: '[[facades.Queue]]().\n\t[[Job]](&jobs.SyncTasks{}, []queue.Arg{\n\t\t{Type: "int", Value: task.ID},\n\t}).\n\t[[OnQueue]]("sync").\n\t[[Dispatch]]()', + ties: [[1, 2], [2, 5]] + }, + { + name: 'Events', phpFile: 'app/Services/TaskService.php', goFile: 'app/services/task_service.go', + php: 'TasksViewed::{{dispatch}}($tasks);', + go: '[[facades.Event]]().\n\t[[Job]](&events.TasksViewed{}, []event.Arg{\n\t\t{Type: "int", Value: len(tasks)},\n\t}).\n\t[[Dispatch]]()', + ties: [[1, 2]] + }, + { + name: 'Scheduling', phpFile: 'routes/console.php', goFile: 'bootstrap/app.go', + php: "Schedule::{{command}}('emails:send')\n ->{{daily}}();", + go: '[[WithSchedule]](func() []schedule.Event {\n\treturn []schedule.Event{\n\t\t[[facades.Schedule]]().[[Command]]("emails:send").\n\t\t\t[[Daily]](),\n\t}\n})', + ties: [[1, 3], [2, 4]] + }, + { + name: 'Cache', phpFile: 'app/Services/TaskService.php', goFile: 'app/services/task_service.go', + php: "$tasks = Cache::{{remember}}('tasks.open', 600, function () {\n return Task::{{where}}('done', false)->{{get}}();\n});", + go: '[[facades.Cache]]().[[Remember]]("tasks.open", 10*time.Minute,\n\tfunc() (any, error) {\n\t\tvar tasks []models.Task\n\t\terr := [[facades.Orm]]().[[Query]]().\n\t\t\t[[Where]]("done", false).[[Get]](&tasks)\n\t\treturn tasks, err\n\t})', + ties: [[1, 1], [2, 4]] + }, + { + name: 'Testing', phpFile: 'tests/Feature/TaskTest.php', goFile: 'tests/feature/task_test.go', + php: "public function {{test_it_lists_open_tasks}}(): void\n{\n $this->{{get}}('/tasks')\n ->{{assertStatus}}(200);\n}", + go: 'func (s *TaskTestSuite) [[TestIndex]]() {\n\tresponse, err := s.[[Http]](s.T()).[[Get]]("/tasks")\n\ts.[[Nil]](err)\n\tresponse.[[AssertStatus]](200)\n}', + ties: [[1, 1], [3, 2], [4, 4]] + }, + { + name: 'Artisan', phpFile: 'Terminal', goFile: 'Terminal', + php: 'php artisan {{make:controller}} TaskController', + go: 'go run . artisan [[make:controller]] TaskController', + ties: [[1, 1]] + } +] + +export const LARAVEL = { + title: 'Laravel, line for line.', + checks: ['Familiar facades, familiar method names', 'The same file layout, artisan included'], + compare: { text: 'Compare with Laravel', link: '/prologue/compare-with-laravel.html' }, + concepts: CONCEPTS +} + +export const FACADES: Record = { + AI: ['/ai/sdk.html', 'Agents and conversations with AI providers'], + App: ['/architecture-concepts/service-container.html', 'The service container'], + Artisan: ['/digging-deeper/artisan-console.html', 'Console commands'], + Auth: ['/security/authentication.html', 'JWT and session guards'], + Cache: ['/digging-deeper/cache.html', 'Cache stores'], + Config: ['/getting-started/configuration.html', 'Configuration values'], + Crypt: ['/security/encryption.html', 'Encryption and decryption'], + DB: ['/database/queries.html', 'Query builder'], + Event: ['/digging-deeper/event.html', 'Events and listeners'], + Gate: ['/security/authorization.html', 'Authorization gates and policies'], + Grpc: ['/the-basics/grpc.html', 'gRPC servers and clients'], + Hash: ['/security/hashing.html', 'Password hashing'], + Http: ['/digging-deeper/http-client.html', 'HTTP client for outgoing requests'], + Lang: ['/digging-deeper/localization.html', 'Localization'], + Log: ['/the-basics/logging.html', 'Logging to channels'], + Mail: ['/digging-deeper/mail.html', 'Sending mail'], + Orm: ['/orm/getting-started.html', 'Models, relationships and queries'], + Process: ['/digging-deeper/processes.html', 'Run system processes'], + Queue: ['/digging-deeper/queues.html', 'Background jobs'], + RateLimiter: ['/the-basics/routing.html#rate-limiting', 'Named rate limiters'], + Route: ['/the-basics/routing.html', 'Routes, groups and middleware'], + Schedule: ['/digging-deeper/task-scheduling.html', 'Task scheduling'], + Schema: ['/database/migrations.html', 'Migrations'], + Seeder: ['/database/seeding.html', 'Database seeders'], + Session: ['/the-basics/session.html', 'Session data across requests'], + Storage: ['/digging-deeper/filesystem.html', 'File storage'], + Telemetry: ['/digging-deeper/telemetry.html', 'Traces, metrics and logs'], + Testing: ['/testing/getting-started.html', 'Test helpers, like Docker databases'], + Validation: ['/the-basics/validation.html', 'Validate requests and data'], + View: ['/the-basics/views.html', 'Templates rendered as responses'] +} + +export const FACADES_TITLE = 'facades. One framework.' + +export const FRESH = ['AI', 'Telemetry'] + +export const CAPABILITIES: Capability[] = [ + { + title: 'One process', + says: 'HTTP, gRPC, queue, scheduler and telemetry start together.', + code: '// config/app.go\n"disabled_runners": []string{\n\t[["goravel:schedule"]],\n},' + }, + { + title: 'Gin or Fiber', + says: 'Runs on gin. Install fiber, change one line.', + lit: [4], + code: '// config/http.go\n [[config.Add]]("http", map[string]any{\n- "default": "gin",\n+ "default": [["fiber"]],' + }, + { + title: 'Real databases in tests', + says: 'Postgres or Redis in Docker, from inside a test.', + code: 'database, err := [[facades.Testing]]().\n\t[[Docker]]().[[Database]]("postgres")\ncache, err := [[facades.Testing]]().\n\t[[Docker]]().[[Cache]]("redis")' + }, + { + title: 'AI SDK', + says: 'Agents and tools for OpenAI, Anthropic and Gemini.', + facade: 'AI', + code: 'conversation, err := [[facades.AI]]().\n\t[[Agent]](&agents.SupportAgent{})\nif err != nil {\n\treturn err\n}' + }, + { + title: 'Telemetry', + says: 'OpenTelemetry traces, metrics and logs.', + facade: 'Telemetry', + code: '# .env\nOTEL_TRACES_EXPORTER=[[otlptrace]]\nOTEL_METRICS_EXPORTER=[[otlpmetric]]\nOTEL_LOGS_EXPORTER=[[otlplog]]' + }, + { + title: 'One binary', + says: 'Upload the binary and your .env. No runtime to install.', + code: '$ go run . artisan [[build]] --static\n# upload\n.env\n./goravel' + } +] + +export const PIECES: { key: PieceKey; facades: string[] }[] = [ + { key: 'http', facades: ['Route', 'Http', 'Session', 'Grpc', 'RateLimiter', 'View'] }, + { key: 'app', facades: ['Validation', 'Auth', 'Gate', 'Hash', 'Crypt', 'Lang', 'AI'] }, + { key: 'core', facades: ['App', 'Artisan', 'Config', 'Process', 'Log', 'Testing'] }, + { key: 'data', facades: ['Orm', 'DB', 'Schema', 'Seeder', 'Cache', 'Storage'] }, + { key: 'async', facades: ['Queue', 'Event', 'Schedule', 'Mail', 'Telemetry'] } +] + +export const LITE: { title: string; lead: string; base: string[]; steps: LiteStep[] } = { + title: 'Start with the core.', + lead: 'Goravel Lite ships only the essentials. Add the rest when you need them.', + base: ['App', 'Artisan', 'Config', 'Process'], + steps: [ + { cmd: 'goravel new blog', pick: 'Goravel Lite - Only includes essential facades', add: [] }, + { cmd: 'go run . artisan package:install Route', add: ['Route'] }, + { cmd: 'go run . artisan package:install Orm', add: ['Orm'] }, + { cmd: 'go run . artisan package:install Queue', add: ['Queue'] }, + { cmd: 'go run . artisan package:install Validation', add: ['Validation'] }, + { cmd: 'go run . artisan package:install --all', add: ['*'] } + ] +} + +interface Join { + title: string + link: string + says: string + wechat?: { label: string; src: string; alt: string } +} + +export const OPEN_SOURCE: { title: string; joins: Join[] } = { + title: 'Open source.', + joins: [ + { title: 'Star on GitHub', link: LINKS.github, says: 'MIT licensed' }, + { + title: 'Join Discord', + link: LINKS.discord, + says: 'Questions and discussion', + wechat: { label: 'WeChat group', src: '/wechat.jpg', alt: 'WeChat group QR code' } + }, + { title: 'Contribute', link: '/prologue/contributions.html', says: 'Features earn a T‑shirt' }, + { + title: 'Sponsor', + link: LINKS.openCollective, + says: 'Open Collective', + wechat: { label: 'Support with WeChat', src: '/reward-wechat.jpg', alt: 'WeChat reward QR code' } + } + ] +} + +export const CORE_TEAM = ['hwbrzzl', 'krishankumar01', 'DevHaoZi', 'almas-x'] + +export const CONTRIBUTORS = [ + 'hwbrzzl', 'krishankumar01', 'DevHaoZi', 'almas-x', 'merouanekhalili', 'hongyukeji', 'sidshrivastav', + 'Juneezee', 'dragoonchang', 'dhanusaputra', 'mauri870', 'Marian0', 'ahmed3mar', 'flc1125', + 'zzpwestlife', 'juantarrel', 'Kamandlou', 'livghit', 'jeff87218', 'shayan-yousefi', 'zxdstyle', + 'milwad-dev', 'mdanialr', 'KlassnayaAfrodita', 'YlanzinhoY', 'gouguoyin', 'dzham', 'praem90', + 'vendion', 'tzsk', 'ycb1986', 'BadJacky', 'NiteshSingh17', 'alfanzain', 'oprudkyi', 'zoryamba', + 'oguzhankrcb', 'ChisThanh', 'wyicwx', 'LinboLen', 'president-tuychiyev', 'eddyjj92', + 'codedsultan' +] + +export const FOOTER = [ + { + title: 'Documentation', + items: [ + ['Installation', '/getting-started/installation.html'], + ['Routing', '/the-basics/routing.html'], + ['ORM', '/orm/getting-started.html'], + ['Queues', '/digging-deeper/queues.html'], + ['Testing', '/testing/getting-started.html'] + ] + }, + { + title: 'Project', + items: [ + ['Release Notes', '/prologue/releases.html'], + ['Upgrading To v1.18', '/upgrade/v1.18.html'], + ['Compare With Laravel', '/prologue/compare-with-laravel.html'], + ['Contribution Guide', '/prologue/contributions.html'], + ['Privacy Policy', '/prologue/privacy.html'] + ] + } +] diff --git a/.vitepress/theme/home/github.data.ts b/.vitepress/theme/home/github.data.ts new file mode 100644 index 000000000..e65f6a77e --- /dev/null +++ b/.vitepress/theme/home/github.data.ts @@ -0,0 +1,32 @@ +import { defineLoader } from 'vitepress' + +export interface GitHubNumbers { + stars: number +} + +declare const data: GitHubNumbers +export { data } + +// used only when the build cannot reach GitHub +const SAVED: GitHubNumbers = { stars: 4835 } + +async function github(path: string): Promise { + const headers: Record = { Accept: 'application/vnd.github+json' } + if (process.env.GITHUB_TOKEN) headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}` + const res = await fetch(`https://api.github.com/${path}`, { headers, signal: AbortSignal.timeout(10_000) }) + if (!res.ok) throw new Error(`${path} answered ${res.status}`) + return res.json() as Promise +} + +// read when the site is built; the page shows these until the visitor's browser has live ones +export default defineLoader({ + async load(): Promise { + try { + const repo = await github<{ stargazers_count: number }>('repos/goravel/goravel') + return { stars: repo.stargazers_count } + } catch (e) { + console.warn(`GitHub numbers unavailable, using the saved ones: ${(e as Error).message}`) + return SAVED + } + } +}) diff --git a/.vitepress/theme/home/home.css b/.vitepress/theme/home/home.css new file mode 100644 index 000000000..49b9cb697 --- /dev/null +++ b/.vitepress/theme/home/home.css @@ -0,0 +1,538 @@ +/* full-width rules bleed to the screen edge, or to a column's rule where one sets --g-bleed-* */ +.g-home { + container-type: inline-size; + /* the page margin, which grows past 96px so the content stays 1248px wide on a wide screen */ + --g-margin: max(96px, (100cqw - 1248px) / 2); + --g-bleed-left: var(--g-margin); + --g-bleed-right: var(--g-margin); + --g-secpad: 56px; + --g-grey: #5b6770; + color: var(--g-ink); + background: var(--g-white); +} + +@media (max-width: 1280px) { + .g-home { + --g-margin: 48px; + } +} + +@media (max-width: 900px) { + .g-home { + --g-margin: 24px; + } +} + +.g-home .g-wrap { + padding: 0 var(--g-margin); +} + +/* ------------------------------------------------------------------ type */ +.g-home .g-display { + font-size: 84px; + line-height: 82px; + font-weight: 700; + font-stretch: 112%; + letter-spacing: -0.045em; + text-wrap: balance; +} + +.g-home .g-display .light { + font-weight: 450; +} + +.g-home .g-h2 { + font-size: 48px; + line-height: 52px; + font-weight: 700; + font-stretch: 108%; + letter-spacing: -0.04em; + text-wrap: balance; +} + +.g-home .g-h3 { + font-size: 28px; + line-height: 34px; + font-weight: 650; + letter-spacing: -0.025em; +} + +.g-home .g-lead { + max-width: 560px; + font-size: 18px; + line-height: 30px; + color: var(--g-grey); +} + +.g-home .g-body { + font-size: 16px; + line-height: 26px; +} + +.g-home .g-small { + font-size: 15px; + line-height: 24px; +} + +.g-home .g-label, +.g-home .g-meta { + font-size: 12.5px; + line-height: 16px; +} + +.g-home .g-meta { + font-family: var(--vp-font-family-mono); + letter-spacing: 0.02em; + color: var(--g-grey); +} + +.g-home .muted { color: var(--g-grey); } +.g-home .cyan { color: var(--g-cyan-text); } +.g-home .ink { color: var(--g-ink); } + +@media (max-width: 1280px) { + .g-home .g-display { + font-size: 64px; + line-height: 64px; + } + + .g-home .g-h2 { + font-size: 38px; + line-height: 42px; + } +} + +@media (max-width: 900px) { + .g-home .g-display { + font-size: 44px; + line-height: 46px; + } + + .g-home .g-h2 { + font-size: 30px; + line-height: 34px; + } +} + +/* ------------------------------------------------------------------ controls */ +.g-home .g-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 14px; + height: 50px; + padding: 0 24px; + border: 1px solid transparent; + border-radius: 3px; + background: var(--g-cyan-text); + font-size: 16px; + font-weight: 600; + white-space: nowrap; + color: var(--g-white); + transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease; +} + +.g-home .g-button:not(.is-outline):hover { + border-color: var(--g-cyan-text); + background: var(--g-white); + color: var(--g-cyan-text); +} + +.g-home .g-button.is-outline { + border-color: var(--g-line); + background: var(--g-white); + font-weight: 500; + color: var(--g-ink); +} + +.g-home .g-button.is-outline:hover { + border-color: var(--g-ink); + background: var(--g-white); + color: var(--g-ink); +} + +.g-arrow { + flex-shrink: 0; + fill: none; + stroke: currentColor; + stroke-width: 1.6; + stroke-linecap: square; + transition: transform 0.22s cubic-bezier(0.22, 0.61, 0.36, 1); +} + +.g-button:hover .g-arrow { + transform: translateX(4px); +} + +.g-home .g-link { + font-size: 15px; + font-weight: 500; + color: var(--g-ink); + text-decoration: underline 1px var(--g-line); + text-underline-offset: 6px; + transition: color 0.15s ease, text-decoration-color 0.15s ease; +} + +.g-home .g-link:hover { + color: var(--g-cyan-text); + text-decoration-color: var(--g-cyan); +} + +.g-community { + padding-top: 88px; + padding-bottom: 88px; + border-top: 1px solid var(--g-line); + scroll-snap-align: start; +} + +@media (max-width: 900px) { + + .g-community { + padding-top: 64px; + padding-bottom: 64px; + } +} + +.g-sec-head { + max-width: 720px; +} + +.g-sec-head .g-lead { + margin-top: 16px; +} + +.g-actions { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 20px 36px; + margin-top: 40px; +} + +/* ------------------------------------------------------------------ tabs */ +.g-tabs { + display: flex; + flex-wrap: wrap; + gap: 2px 28px; + margin-top: 36px; + border-bottom: 1px solid var(--g-line); +} + +.g-tab { + position: relative; + padding: 0 0 14px; + font-size: 16px; + font-weight: 500; + color: var(--g-grey); + transition: color 0.15s ease; +} + +.g-tab:hover, +.g-tab.is-active { + color: var(--g-ink); +} + +.g-tab::after { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: -1px; + height: 2px; + background: var(--g-cyan); + transform: scaleX(0); + transform-origin: left; + transition: transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1); +} + +.g-tab.is-active::after { + transform: scaleX(1); +} + +@media (max-width: 900px) { + .g-tabs { + gap: 2px 20px; + margin-top: 32px; + } + + .g-tab { + font-size: 15px; + } +} + +@media (max-width: 900px) { + + .g-actions { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 12px; + } + + .g-home .g-button { + width: 100%; + } +} + +/* ------------------------------------------------------------------ code */ +.g-file-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 16px; + padding-bottom: 12px; + border-bottom: 1px solid var(--g-line); +} + +.g-code { + overflow-x: auto; + padding: 18px 0 0; + font-family: var(--vp-font-family-mono); + font-size: 13px; + line-height: 26px; + tab-size: 2; +} + +/* the tint of a lit line reaches past the text, so the bleed sits on the block and not on the line, + where it would widen the block and raise a scrollbar */ +.g-code:not(.is-plain) { + margin: 0 -14px; +} + +.g-code .ln { + position: relative; + display: block; + padding: 0 14px; + white-space: pre; + color: var(--g-grey); + transition: background-color 0.25s ease, color 0.25s ease; +} + +.g-code.is-plain .ln { + padding: 0; +} + +.g-code .ln .no { + display: inline-block; + width: 24px; + margin-right: 18px; + text-align: right; + color: var(--g-line); + user-select: none; +} + +.g-code .ln.is-lit, +.g-code .ln.is-pair { + background: var(--g-cyan-tint); + color: var(--g-ink); +} + +.g-code .ln.is-lit .no { + color: var(--g-cyan); +} + +.g-code .call { + color: var(--g-cyan-text); +} + +.g-swap { + animation: g-swap 0.26s ease both; +} + +@keyframes g-swap { + from { + opacity: 0; + transform: translateY(4px); + } +} + +.g-count { + display: flex; + align-items: baseline; + gap: 14px; +} + +.g-count .n { + font-size: 56px; + line-height: 52px; + font-weight: 600; + letter-spacing: -0.045em; + font-variant-numeric: tabular-nums; +} + +.g-count .muted { + font-size: 28px; + letter-spacing: -0.03em; +} + +/* ------------------------------------------------------------------ the mark */ +.g-mark { + display: block; + max-width: 100%; + height: auto; + overflow: visible; +} + +/* the mark is drawn at four sizes; lines keep their pixel width */ +.g-mark-lattice, +.g-face, +.g-leader, +.g-track { + vector-effect: non-scaling-stroke; +} + +.g-mark-lattice, +.g-leader, +.g-track { + fill: none; +} + +.g-mark-lattice { + stroke: var(--g-line); + opacity: 0.9; +} + +/* a piece Lite has not installed waits outside the mark as a dashed outline */ +.g-face.is-ghost { + stroke-dasharray: 3 4; +} + +.g-leader { + stroke: var(--g-construct); + stroke-width: 0.75; + stroke-dasharray: 2 3; +} + +/* ------------------------------------------------------------------ footer */ +.g-footer { + padding-top: 48px; + padding-bottom: 28px; + border-top: 1px solid var(--g-line); +} + +.g-footer-cols { + display: grid; + grid-template-columns: minmax(0, 6fr); + grid-auto-flow: column; + grid-auto-columns: minmax(0, 2fr); + column-gap: 24px; +} + +.g-footer-brand { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 14px; +} + +.g-footer-brand img { + width: auto; + height: 24px; +} + +.g-footer-brand p { + max-width: 300px; +} + +.g-footer-col { + display: flex; + flex-direction: column; + gap: 6px; +} + +.g-footer-col a { + color: var(--g-grey); + transition: color 0.15s ease; +} + +.g-footer-col a:hover { + color: var(--g-cyan-text); +} + +.g-footer-bar { + display: flex; + justify-content: space-between; + gap: 24px; + margin-top: 40px; + padding-top: 16px; + border-top: 1px solid var(--g-line); +} + +.g-footer-bar a:hover { + color: var(--g-cyan-text); +} + +@media (max-width: 900px) { + .g-footer-cols { + grid-auto-flow: row; + grid-template-columns: repeat(2, minmax(0, 1fr)); + row-gap: 32px; + } + + .g-footer-brand { + grid-column: 1 / -1; + } + + .g-community-foot, + .g-footer-bar { + flex-direction: column; + gap: 14px; + } +} + +.g-home :focus-visible { + outline: 2px solid var(--g-cyan); + outline-offset: 3px; +} + +@media (prefers-reduced-motion: reduce) { + .g-home .g-swap { + animation: none; + } +} + +.home-sr { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip-path: inset(50%); +} + +.home-sec { + --g-secpad: 112px; + padding: var(--g-secpad) 0; + border-top: 1px solid var(--g-line); +} + +.g-code .ln.is-note { + color: var(--g-grey); +} + +@media (max-width: 1280px) { + .home-sec { + --g-secpad: 80px; + } +} + +@media (max-width: 900px) { + .home-sec { + --g-secpad: 64px; + } +} + +.Layout:has(.g-home) .VPFooter { + display: none !important; +} + +/* ------------------------------------------------------------------ rules that bleed */ +/* last, so these paddings win over the shorthands above */ +.g-tabs, +.g-file-head, +.g-community, +.g-footer, +.g-footer-bar { + margin-left: calc(var(--g-bleed-left) * -1); + margin-right: calc(var(--g-bleed-right) * -1); + padding-left: var(--g-bleed-left); + padding-right: var(--g-bleed-right); +} diff --git a/.vitepress/theme/home/mark.data.ts b/.vitepress/theme/home/mark.data.ts new file mode 100644 index 000000000..db2f626d2 --- /dev/null +++ b/.vitepress/theme/home/mark.data.ts @@ -0,0 +1,38 @@ +import { readFile } from 'node:fs/promises' +import { fileURLToPath } from 'node:url' +import { defineLoader } from 'vitepress' +import { svgPathProperties } from 'svg-path-properties' +import { PIECES } from './config' + +export interface Mark { + pieces: { fill: string; d: string; at: { x: number; y: number } }[] +} + +declare const data: Mark +export { data } + +const logo = fileURLToPath(new URL('../../../public/logo.svg', import.meta.url)) +const round = (n: number) => Math.round(n * 10) / 10 + +function bounds(d: string) { + const path = new svgPathProperties(d) + const points = Array.from({ length: 48 }, (_, i) => path.getPointAtLength((path.getTotalLength() * i) / 48)) + const [x, y] = [points.map((p) => p.x), points.map((p) => p.y)] + return { x: round((Math.min(...x) + Math.max(...x)) / 2), y: round((Math.min(...y) + Math.max(...y)) / 2) } +} + +export default defineLoader({ + watch: [logo], + async load([file]): Promise { + const svg = await readFile(file ?? logo, 'utf8') + const fills = new Map([...svg.matchAll(/\.(s\d+)\s*\{\s*fill:\s*(#[0-9a-f]+)/gi)].map((m) => [m[1], m[2]])) + const pieces = [...svg.matchAll(/class="(s\d+)"\s+d="([^"]+)"/gi)].map((m) => ({ + fill: fills.get(m[1])!, + d: m[2], + at: bounds(m[2]) + })) + if (pieces.length !== PIECES.length || pieces.some((p) => !p.fill)) + throw new Error(`logo.svg: expected ${PIECES.length} filled pieces, found ${pieces.length}`) + return { pieces } + } +}) diff --git a/.vitepress/theme/home/releases.data.ts b/.vitepress/theme/home/releases.data.ts new file mode 100644 index 000000000..cdeb539ea --- /dev/null +++ b/.vitepress/theme/home/releases.data.ts @@ -0,0 +1,39 @@ +import { readFile } from 'node:fs/promises' +import { fileURLToPath } from 'node:url' +import { defineLoader } from 'vitepress' + +export interface Release { + version: string + go: string + from: string + until: string + fromText: string + untilText: string + planned: boolean +} + +declare const data: { releases: Release[]; now: string } +export { data } + +const file = fileURLToPath(new URL('../../../en/prologue/releases.md', import.meta.url)) +const QUARTER: Record = { Q1: '01-01', Q2: '04-01', Q3: '07-01', Q4: '10-01' } + +function day(text: string) { + const quarter = text.match(/^(Q[1-4]), (\d{4})$/) + if (quarter) return `${quarter[2]}-${QUARTER[quarter[1]]}` + const date = new Date(`${text} UTC`) + if (Number.isNaN(date.getTime())) throw new Error(`releases.md: "${text}" is neither a date nor a quarter like "Q1, 2027"`) + return date.toISOString().slice(0, 10) +} + +export default defineLoader({ + watch: [file], + async load() { + const rows = (await readFile(file, 'utf8')).split('\n').filter((line) => /^\|\s*\d/.test(line)) + const releases = rows.map((row) => { + const [version, go, from, until] = row.split('|').slice(1, 5).map((cell) => cell.trim()) + return { version, go, from: day(from), until: day(until), fromText: from, untilText: until, planned: from.startsWith('Q') } + }) + return { releases, now: new Date().toISOString().slice(0, 10) } + } +}) diff --git a/.vitepress/theme/home/useTicker.ts b/.vitepress/theme/home/useTicker.ts new file mode 100644 index 000000000..dc8f2685a --- /dev/null +++ b/.vitepress/theme/home/useTicker.ts @@ -0,0 +1,37 @@ +import { ref, watchEffect } from 'vue' +import { + useDocumentVisibility, + useEventListener, + useIntersectionObserver, + useIntervalFn, + usePreferredReducedMotion +} from '@vueuse/core' + +export function useTicker(ms: number, threshold = 0.3) { + const ticks = ref(0) + const root = ref(null) + const inView = ref(false) + const focused = ref(false) + const visibility = useDocumentVisibility() + const motion = usePreferredReducedMotion() + const wait = ref(700) + + const { pause, resume } = useIntervalFn( + () => { + ticks.value++ + wait.value = ms + }, + wait, + { immediate: false } + ) + + useIntersectionObserver(root, ([entry]) => (inView.value = entry.isIntersecting), { threshold }) + useEventListener(root, 'focusin', () => (focused.value = !!root.value?.querySelector(':focus-visible'))) + useEventListener(root, 'focusout', () => (focused.value = false)) + + watchEffect(() => + inView.value && !focused.value && visibility.value === 'visible' && motion.value !== 'reduce' ? resume() : pause() + ) + + return { ticks, root } +} diff --git a/.vitepress/theme/i18n.ts b/.vitepress/theme/i18n.ts new file mode 100644 index 000000000..cd445db4f --- /dev/null +++ b/.vitepress/theme/i18n.ts @@ -0,0 +1,171 @@ +import { computed } from 'vue' +import { useData, useRoute } from 'vitepress' +import { useLangs } from 'vitepress/dist/client/theme-default/composables/langs.js' + +type Dict = Record + +const zh_CN: Dict = { + Route: '路由', + Middleware: '中间件', + Controller: '控制器', + Service: '服务', + Response: '响应', + Routing: '路由', + Validation: '验证', + Queues: '队列', + Events: '事件', + Scheduling: '调度', + Cache: '缓存', + Testing: '测试', + 'HTTP layer': 'HTTP 层', + 'Application layer': '应用层', + 'Core layer': '核心层', + 'Data layer': '数据层', + 'Async layer': '异步层', + 'Familiar structure.': '熟悉的结构。', + 'Native Go.': '原生的 Go。', + 'Routing, an ORM, validation, queues, events and cache, in one framework.': + '路由、ORM、验证、队列、事件与缓存,尽在一个框架之中。', + 'Get started': '快速开始', + 'Compare with Laravel': '与 Laravel 对比', + 'Start with the core.': '从核心开始。', + 'facades installed': '个门面已安装', + 'Open source.': '开源。', + 'WeChat group': '微信群', + 'Support with WeChat': '微信赞赏', + 'A Go framework with the structure of Laravel.': '拥有 Laravel 结构的 Go 框架。', + Concepts: '概念', + 'Install steps': '安装步骤', + 'WeChat group QR code': '微信群二维码', + 'WeChat reward QR code': '微信赞赏二维码', + 'GitHub stars': 'GitHub 星标', + contributors: '贡献者', + forks: '复刻', + Documentation: '文档', + Project: '项目', + Community: '社区', + Installation: '安装', + ORM: 'ORM', + 'Release Notes': '发行说明', + 'Upgrading To v1.18': '升级到 v1.18', + 'Compare With Laravel': '与 Laravel 对比', + 'Contribution Guide': '贡献指南', + 'Privacy Policy': '隐私政策', + Contribute: '参与贡献', + 'This page does not exist.': '页面不存在。', + 'It may have moved in a newer version of the docs, or the address may be wrong.': '它可能已在新版文档中移动,或者地址有误。', + 'Go to the documentation': '前往文档', + 'Try these': '试试这些', + 'Upgrading To v1.18 From v1.17': '从 v1.17 升级到 v1.18', + 'Excellent Packages': '优秀扩展包', + Methods: '方法', + Filter: '筛选', + 'Filter methods': '筛选方法', + 'Familiar facades, familiar method names': '熟悉的门面,熟悉的方法名', + 'The same file layout, artisan included': '相同的目录结构,自带 artisan', + 'Laravel, line for line.': '与 Laravel 逐行对应。', + 'facades. One framework.': '个门面,一个框架。', + 'One process': '一个进程', + 'HTTP, gRPC, queue, scheduler and telemetry start together.': 'HTTP、gRPC、队列、调度与遥测一同启动。', + 'Gin or Fiber': 'Gin 或 Fiber', + 'Real databases in tests': '用真实数据库测试', + 'OpenTelemetry traces, metrics and logs.': 'OpenTelemetry 链路、指标与日志。', + 'One binary': '一个二进制文件', + 'Upload the binary and your .env. No runtime to install.': '上传二进制文件和 .env 即可,无需安装运行时。', + 'Runs on gin. Install fiber, change one line.': '默认使用 gin。安装 fiber,改一行配置即可切换。', + 'Postgres or Redis in Docker, from inside a test.': '在测试中通过 Docker 启动 Postgres 或 Redis。', + 'Agents and tools for OpenAI, Anthropic and Gemini.': '支持 OpenAI、Anthropic 与 Gemini 的智能体和工具。', + 'Goravel Lite ships only the essentials. Add the rest when you need them.': 'Goravel Lite 只包含必要的门面,其余按需安装。', + new: '新', + Copy: '复制', + Copied: '已复制', + Releases: '版本发布', + release: '发布', + 'bug fixes': '缺陷修复', + planned: '计划中', + ended: '已结束', + today: '今天', + 'Core team': '核心团队', + 'more contributors': '位其他贡献者', + 'Star on GitHub': '在 GitHub 上 Star', + 'MIT licensed': 'MIT 许可', + 'Join Discord': '加入 Discord', + 'Questions and discussion': '提问与讨论', + Sponsor: '赞助', + 'Features earn a T‑shirt': '贡献功能可获得 T 恤' +} + +const uz_UZ: Dict = { + Route: 'Marshrut', + Middleware: 'Oraliq dastur', + Controller: 'Kontroller', + Service: 'Xizmat', + Response: 'Javob', + Routing: 'Marshrutlash', + Validation: 'Validatsiya', + Queues: 'Navbatlar', + Events: 'Hodisalar', + Scheduling: 'Rejalashtirish', + Cache: 'Kesh', + Testing: 'Test', + 'HTTP layer': 'HTTP qatlami', + 'Application layer': 'Ilova qatlami', + 'Core layer': 'Yadro qatlami', + 'Data layer': "Ma'lumotlar qatlami", + 'Async layer': 'Asinxron qatlami', + 'Familiar structure.': 'Tanish tuzilma.', + 'Native Go.': 'Sof Go.', + 'Routing, an ORM, validation, queues, events and cache, in one framework.': + "Marshrutlash, ORM, validatsiya, navbatlar, hodisalar va kesh, barchasi bitta freymvorkda.", + 'Get started': 'Tezda boshlash', + 'Compare with Laravel': 'Laravel bilan solishtirish', + 'Start with the core.': 'Yadrodan boshlang.', + 'facades installed': "ta fasad o'rnatilgan", + 'Open source.': 'Ochiq manba.', + 'WeChat group': 'WeChat guruhi', + 'Support with WeChat': "WeChat orqali qo'llab-quvvatlash", + 'A Go framework with the structure of Laravel.': 'Laravel tuzilmasiga ega Go freymvorki.', + Concepts: 'Tushunchalar', + 'Install steps': "O'rnatish bosqichlari", + 'WeChat group QR code': 'WeChat guruhi QR kodi', + 'WeChat reward QR code': "WeChat qo'llab-quvvatlash QR kodi", + 'GitHub stars': 'GitHub yulduzlari', + contributors: "hissa qo'shuvchilar", + forks: 'forklar', + Documentation: 'Hujjatlar', + Project: 'Loyiha', + Community: 'Hamjamiyat', + Installation: "O'rnatish", + ORM: 'ORM', + 'Release Notes': 'Chiqarish eslatmalari', + 'Upgrading To v1.18': 'v1.18 ga yangilash', + 'Compare With Laravel': 'Laravel bilan solishtirish', + 'Contribution Guide': "Hissa qo'shish bo'yicha qo'llanma", + 'Privacy Policy': 'Maxfiylik siyosati', + Contribute: "Hissa qo'shish" +} + +const DICTS: Record = { zh_CN, uz_UZ } + +export function useI18n() { + const { site, localeIndex } = useData() + const route = useRoute() + const { localeLinks, currentLang } = useLangs({ correspondingLink: true }) + const dict = computed(() => DICTS[localeIndex.value] ?? {}) + + const tr = (en: string) => dict.value[en] ?? en + + // a docs path in the current language; links that leave the site pass through + const link = (path: string) => (localeIndex.value === 'root' || !path.startsWith('/') ? path : `/${localeIndex.value}${path}`) + + // every language, each linking to this page in that language + const languages = computed(() => + Object.values(site.value.locales).map(({ label }) => ({ + text: label!, + link: localeLinks.value.find((l) => l.text === label)?.link ?? route.path, + selected: label === currentLang.value.label + })) + ) + + return { tr, link, languages, currentLang } +} diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts index 977614ece..98646db3b 100644 --- a/.vitepress/theme/index.ts +++ b/.vitepress/theme/index.ts @@ -1,18 +1,27 @@ import TwoslashFloatingVue from '@shikijs/vitepress-twoslash/client' -import Theme from 'vitepress/theme' +import Theme from 'vitepress/theme-without-fonts' +import Layout from './Layout.vue' +import Brand from './components/Brand.vue' import giscusTalk from 'vitepress-plugin-comment-with-giscus' import { useData, useRoute } from 'vitepress' -import { toRefs } from 'vue' +import { defineAsyncComponent, toRefs } from 'vue' import '@shikijs/vitepress-twoslash/style.css' import 'virtual:group-icons.css' import 'vitepress-markdown-timeline/dist/theme/index.css' import type { EnhanceAppContext } from 'vitepress' import './styles.css' +import './goravel.css' +import './shell.css' +import './home/home.css' export default { extends: Theme, + Layout, enhanceApp({ app }: EnhanceAppContext) { app.use(TwoslashFloatingVue) + app.component('Brand', Brand) + // only the three homepages use it, so doc pages do not download it + app.component('goravel-home', defineAsyncComponent(() => import('./home/Home.vue'))) }, setup() { // Get frontmatter and route @@ -28,12 +37,9 @@ export default { mapping: 'pathname', inputPosition: 'top', lang: 'en', - // i18n setting (Note: This configuration will override the default language set by lang) - // Configured as an object with key-value pairs inside: - // [your i18n configuration name]: [corresponds to the language pack name in Giscus] locales: { 'zh-CN': 'zh-CN', - en: 'en' + 'en-US': 'en' }, strict: '0', reactionsEnabled: '1', @@ -47,9 +53,6 @@ export default { route }, // Whether to activate the comment area on all pages. - // The default is true, which means enabled, this parameter can be ignored; - // If it is false, it means it is not enabled. - // You can use `comment: true` preface to enable it separately on the page. true ) } diff --git a/.vitepress/theme/shell.css b/.vitepress/theme/shell.css new file mode 100644 index 000000000..274c5055c --- /dev/null +++ b/.vitepress/theme/shell.css @@ -0,0 +1,617 @@ +/* The default theme scopes its styles, so layout overrides here need !important. */ + +/* ------------------------------------------------------------------ the frame */ +/* past 1440px the site stays 1440px wide and centred, and its borders run top to bottom, + so every full-width rule ends on them. The nav, the sidebar and the menu panel are fixed, + so they are placed inside the frame by hand. */ +@media (min-width: 1441px) { + :root { + --g-frame-x: calc(max(0px, (100% - var(--g-frame)) / 2) + 1px); + } + + .Layout { + max-width: var(--g-frame); + margin: 0 auto; + border-right: 1px solid var(--g-line); + border-left: 1px solid var(--g-line); + } + + .VPNav { + right: var(--g-frame-x); + left: var(--g-frame-x) !important; + width: auto !important; + } + + .VPSidebar { + left: var(--g-frame-x) !important; + } +} + +@media (min-width: 960px) { + .VPContent.has-sidebar { + padding-left: var(--vp-sidebar-width) !important; + padding-right: 0 !important; + } + + .VPDoc { + padding: 0 !important; + } + + .VPDoc .container { + max-width: none !important; + margin: 0 !important; + justify-content: flex-start !important; + } + + .VPDoc .container > .content { + flex-grow: 0; + flex-shrink: 0; + width: var(--g-col) !important; + max-width: none !important; + padding: 0 var(--g-rail) 0 var(--g-gutter) !important; + border-right: 1px solid var(--g-line); + } + + .VPDoc .content-container { + max-width: none !important; + margin: 0 !important; + padding: 36px 0 72px !important; + } + + .VPDoc .container > .aside { + flex-grow: 0; + flex-shrink: 0; + width: calc(100% - var(--g-col)) !important; + min-width: 0 !important; + max-width: none !important; + padding: 0 !important; + } + + .VPDoc .aside-curtain { + display: none !important; + } +} + +@media (min-width: 960px) and (max-width: 1279px) { + .VPDoc .container > .content { + width: 100% !important; + border-right: 0; + } +} + +@media (min-width: 1280px) and (max-width: 1599px) { + .VPDoc .container > .content { + width: calc(100% - var(--g-aside)) !important; + } + + .VPDoc .container > .aside { + width: var(--g-aside) !important; + } +} + +@media (min-width: 1280px) { + .VPDoc:not(.has-aside) .container > .content { + width: 100% !important; + border-right: 0; + } + + .VPDoc:not(.has-aside) .vp-doc p { + max-width: 720px; + } +} + +@media (max-width: 959px) { + .VPDoc { + padding-left: 24px !important; + padding-right: 24px !important; + } + + .VPDoc .container, + .VPDoc .container > .content { + width: 100% !important; + max-width: none !important; + margin: 0 !important; + } + + .VPDoc .content-container { + max-width: none !important; + margin: 0 !important; + padding: 24px 0 64px !important; + } +} + +/* ------------------------------------------------------------------ sidebar */ +/* rows run to both edges of the sidebar; the insets are where their text starts */ +.VPSidebar { + --inset-left: var(--g-shell-inset); + --inset-right: 24px; + padding: calc(var(--vp-nav-height) + 28px) var(--inset-right) 96px var(--inset-left) !important; + border-right: 1px solid var(--g-line); +} + +/* above 1440px the theme widens the sidebar to centre its layout; this one stays on the left */ +@media (min-width: 960px) { + .VPSidebar { + width: var(--vp-sidebar-width) !important; + } +} + +@media (max-width: 959px) { + .VPSidebar { + --inset-left: 20px; + --inset-right: 20px; + padding-top: 24px !important; + } +} + +.VPSidebar > .curtain { + display: none !important; +} + +.VPSidebar .group { + padding: 0 !important; + border-top: 0 !important; +} + +.VPSidebar .group + .group { + margin-top: 4px; +} + +.VPSidebarItem.level-0 { + padding-bottom: 0 !important; +} + +.VPSidebarItem.level-0 > .item, +.VPSidebarItem.level-1 > .item { + width: auto !important; + margin: 0 calc(var(--inset-right) * -1) 0 calc(var(--inset-left) * -1) !important; + padding: 8px var(--inset-right) 8px var(--inset-left) !important; + border: 0 !important; + line-height: 20px; + transition: background-color 0.15s ease; +} + +.VPSidebarItem.level-1 > .item { + padding-top: 6px !important; + padding-bottom: 6px !important; +} + +.VPSidebarItem.level-0 > .item:hover, +.VPSidebarItem.level-1 > .item:hover { + background: var(--g-soft); +} + +.VPSidebarItem .indicator { + display: none !important; +} + +.VPSidebarItem .text { + padding: 0 !important; + line-height: 20px; +} + +.VPSidebarItem.level-1 .link .text { + font-weight: 400; +} + +.VPSidebarItem.level-1 > .item:hover .text { + color: var(--g-ink); +} + +.VPSidebarItem .caret { + width: 20px !important; + height: 20px !important; + margin-right: -4px; + opacity: 0.6; + transition: opacity 0.15s ease; +} + +.VPSidebarItem .item:hover .caret { + opacity: 1; +} + +.VPSidebarItem .caret-icon { + width: 16px; + height: 16px; +} + +.VPSidebarItem .items { + margin: 2px 0 12px !important; + padding-left: 0 !important; + border-left: 0 !important; +} + +.VPSidebarItem.is-active > .item .text { + color: var(--g-cyan-text) !important; +} + +.VPSidebarItem.level-1.is-active > .item::before { + position: absolute; + left: calc(var(--inset-left) - 17px); + top: 13px; + background: var(--g-cyan); +} + +/* ------------------------------------------------------------------ outline */ +@media (min-width: 1280px) { + .VPDoc .aside-container { + position: sticky !important; + top: calc(var(--vp-nav-height) + 36px) !important; + width: auto !important; + height: auto !important; + max-height: calc(100vh - var(--vp-nav-height) - 64px); + padding: 0 !important; + } + + .VPDoc .aside-content { + min-height: 0; + padding-bottom: 24px; + } +} + +.VPDocAsideOutline { + margin-bottom: 36px; + padding: 0 var(--g-shell-inset) 0 var(--g-rail) !important; + border: 0 !important; +} + +.VPDocAsideOutline .content { + padding-left: 0; + border-left: 0; +} + +.VPDocAsideOutline .outline-marker { + display: none; +} + +/* the method index's heading is drawn the same way */ +.VPDocAsideOutline .outline-title, +.goravel-methods .outline-title { + display: flex; + align-items: center; + gap: 8px; + margin: 0 calc(var(--g-shell-inset) * -1) 14px calc(var(--g-rail) * -1); + padding: 0 var(--g-shell-inset) 12px var(--g-rail); + border-bottom: 1px solid var(--g-line); +} + +.VPDocAsideOutline .outline-title::before, +.goravel-methods .outline-title::before { + background: var(--g-construct); +} + +.VPDocOutlineItem .outline-link { + position: relative; + padding: 5px 0 5px 12px; + font-size: 13px; + line-height: 20px; + font-weight: 400; +} + +.VPDocOutlineItem .outline-link:hover, +.VPDocOutlineItem .outline-link.active { + color: var(--g-ink); +} + +.VPDocOutlineItem .outline-link.active { + font-weight: 500; +} + +.VPDocOutlineItem .outline-link.active::before { + position: absolute; + left: 0; + top: 11px; + background: var(--g-cyan); +} + +.VPDocOutlineItem.nested { + padding-left: 12px; +} + +.VPLocalNav { + border-bottom: 1px solid var(--g-line) !important; +} + +.VPLocalNav.empty { + display: none !important; +} + +@media (min-width: 960px) { + .VPLocalNav { + padding-left: calc(var(--vp-sidebar-width) + var(--g-gutter)) !important; + } +} + +.VPLocalNav .menu, +.VPLocalNav .VPLocalNavOutlineDropdown button { + font-size: 13px; + color: var(--g-grey); +} + +.VPLocalNavOutlineDropdown .items { + border: 1px solid var(--g-line) !important; + border-radius: 2px !important; + box-shadow: 0 10px 28px rgba(16, 24, 32, 0.1) !important; +} + +/* ------------------------------------------------------------------ search */ +/* the theme resets Algolia's variables on every DocSearch node, so they are set at that level */ +:root [class*='DocSearch'] { + --docsearch-container-background: rgba(16, 24, 32, 0.32); + --docsearch-modal-background: var(--g-white); + --docsearch-modal-shadow: 0 16px 48px rgba(16, 24, 32, 0.12); + --docsearch-searchbox-shadow: none; + --docsearch-searchbox-focus-background: var(--g-white); + --docsearch-highlight-color: var(--g-cyan-text); + --docsearch-hit-background: var(--g-white); + --docsearch-hit-color: var(--g-ink); + --docsearch-hit-active-color: var(--g-ink); + --docsearch-hit-shadow: none; + --docsearch-footer-background: var(--g-white); + --docsearch-footer-height: 48px; + --docsearch-footer-shadow: inset 0 1px 0 var(--g-line); +} + +.DocSearch-Modal { + margin-top: 88px; + border: 1px solid var(--g-line); + border-radius: 2px; +} + +.DocSearch-SearchBar { + padding: 0; + border-bottom: 1px solid var(--g-line); +} + +.DocSearch-Form { + height: 60px; + padding: 0 20px; + border: 0; + border-radius: 0; +} + +.DocSearch-MagnifierLabel { + color: var(--g-grey); +} + +.DocSearch-Input { + padding-left: 12px; + font-size: 17px; +} + +.DocSearch-Reset { + border-radius: 2px; +} + +.DocSearch-Commands-Key { + border-radius: 2px; + background: var(--g-soft); + box-shadow: none; +} + +.DocSearch-Dropdown { + padding: 8px 0; +} + +.DocSearch-Hit-source { + padding: 12px 20px 6px; + font-family: var(--vp-font-family-mono); + font-size: 12px; + font-weight: 500; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--g-grey); +} + +.DocSearch-Hit a { + padding: 0 20px; + border-radius: 0; +} + +.DocSearch-Hit[aria-selected='true'] a { + background: var(--g-soft); +} + +.DocSearch-Hit-title { + font-size: 14.5px; + font-weight: 500; +} + +.DocSearch-Hit-path { + font-size: 12.5px; +} + +.DocSearch-Hit-action svg { + width: 16px; + height: 16px; +} + +.DocSearch-Footer { + border-radius: 0; +} + +.DocSearch-Commands, +.DocSearch-Logo, +.DocSearch-Label { + font-size: 12px; + color: var(--g-grey); +} + +.DocSearch-Commands, +.DocSearch-Logo { + opacity: 0.7; +} + +@media (max-width: 768px) { + .DocSearch-Modal { + margin-top: 0; + border: 0; + border-radius: 0; + } + + .DocSearch-SearchBar { + padding: 0 16px; + } + + .DocSearch-Form { + height: 56px; + padding: 0; + } + + .DocSearch-MagnifierLabel svg { + width: 18px; + height: 18px; + } + + .DocSearch-Input { + padding-left: 10px; + font-size: 16px; + } + + .DocSearch-Cancel { + margin-left: 12px; + font-size: 15px; + } +} + +/* ------------------------------------------------------------------ the phone menu */ +.VPNavScreen { + padding: 0 !important; +} + +.VPNavScreen .container { + max-width: none !important; + margin: 0 !important; + padding: 24px 24px 96px !important; +} + +.VPNavScreenMenuLink, +.VPNavScreenMenuGroup .button { + padding: 10px 0 !important; + border-bottom: 0 !important; + font-size: 16px !important; + font-weight: 500 !important; + color: var(--g-ink) !important; +} + +.VPNavScreenMenuGroup { + border-bottom: 0 !important; +} + +.VPNavScreenMenuGroupSection { + padding: 8px 0 10px; +} + +.VPNavScreenMenuGroupSection .title { + display: flex; + align-items: center; + gap: 9px; + margin-bottom: 2px; + line-height: 24px; + color: var(--g-cyan-text); +} + +.VPNavScreen .VPNavScreenMenuGroupLink { + margin-left: 0; + padding: 7px 0; + font-size: 16px; + line-height: 24px; +} + +.VPNavScreenAppearance { + display: none !important; +} + +.VPNavScreenTranslations { + margin-top: 28px !important; + padding: 0 !important; + border: 0 !important; +} + +/* -7px lines the icon, not its 34px target, up with the rows above */ +.VPNavScreen .container .VPSocialLinks { + justify-content: flex-start; + margin: 20px 0 0 -7px; +} + +.VPNavScreen .VPSocialLink { + width: var(--g-control) !important; + height: var(--g-control) !important; + border-radius: 2px; +} + +.VPNavScreen .VPSocialLink:hover { + background: var(--g-soft); +} + +.g-menu-row { + display: flex; + align-items: center; + gap: 12px; + white-space: nowrap; +} + +.g-menu-icon { + flex-shrink: 0; + width: 20px; + height: 20px; + color: var(--g-grey); + transition: color 0.15s ease; +} + +a:hover .g-menu-icon { + color: var(--g-cyan-text); +} + +.g-menu-icon.is-devchalk { + border-radius: 4px; + background: url('/devchalk-mark.png') center / cover; +} + +/* ------------------------------------------------------------------ footer */ +.VPFooter { + padding: 20px var(--g-shell-inset) !important; +} + +.VPFooter .container { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 4px 10px; + max-width: none; + margin: 0; + text-align: left; +} + +.VPFooter .message, +.VPFooter .copyright { + font-family: var(--vp-font-family-mono); + font-size: 12px !important; + line-height: 18px !important; + letter-spacing: 0.02em; +} + +.VPFooter .copyright::before { + content: '·'; + margin-right: 10px; + color: var(--g-line); +} + +@media (max-width: 959px) { + .VPFooter { + padding: 20px 24px !important; + } + + .VPFooter .copyright::before { + content: none; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + ::before, + ::after { + transition-duration: 0s !important; + animation-duration: 0s !important; + } +} diff --git a/.vitepress/theme/styles.css b/.vitepress/theme/styles.css index 037382d93..e217c686f 100644 --- a/.vitepress/theme/styles.css +++ b/.vitepress/theme/styles.css @@ -1,66 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap'); @import 'tailwindcss'; - -:root { - --vp-nav-logo-height: 36px; - --vp-home-hero-name-color: transparent; - --vp-home-hero-name-background: -webkit-linear-gradient( - 120deg, - #bd34fe 10%, - #00a0e5 - ); - /* --vp-home-hero-image-background-image: linear-gradient(135deg, #bbe2fe 10%, #bfe2fc 100%); - --vp-home-hero-image-filter: blur(50px); */ - --vp-button-brand-bg: #00a0e5; -} - -.VPHero .VPImage { - filter: drop-shadow(-2px 4px 6px rgba(0, 0, 0, 0.2)); - padding: 18px; -} - -.VPHome .heading { - align-items: center; -} - -.VPHome .heading .name { - max-width: 100%; - margin-bottom: 20px; - font-size: 70px; -} - -.VPHome .heading .text { - max-width: 100%; - font-size: 45px; - text-align: center; -} - -.VPHome .tagline { - text-align: center; - align-items: center; - max-width: 100%; -} - -@media (max-width: 768px) { - .VPHome .heading .name { - font-size: 50px; - } - - .VPHome .heading .text { - font-size: 30px; - } - - .VPHome .tagline { - font-size: 16px; - } -} - -.VPHome .actions { - justify-content: center; -} - -.icon { - font-family: - 'Noto Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', - 'Apple Color Emoji', emoji; -} +/* icons as classes, such as icon-[simple-icons--discord], from the installed Iconify sets */ +@plugin '@iconify/tailwind4'; +@source '../config'; diff --git a/en/ai/sdk.md b/en/ai/sdk.md index b65653ac4..aad332613 100644 --- a/en/ai/sdk.md +++ b/en/ai/sdk.md @@ -1,7 +1,5 @@ # AI SDK -[[toc]] - ## Introduction The AI SDK provides a unified API for interacting with AI providers in Goravel applications. It introduces an `AI` facade, stateful conversations, agent classes, provider/model options, prompt attachments, streaming responses, image generation, audio generation, and transcription. diff --git a/en/architecture-concepts/facades.md b/en/architecture-concepts/facades.md index 314227456..1ce32bff3 100644 --- a/en/architecture-concepts/facades.md +++ b/en/architecture-concepts/facades.md @@ -1,7 +1,5 @@ # Facades -[[toc]] - ## Introduction `facades` provide a "static" interface for the core functionality of the application and provide a more flexible, more elegant, and easy-to-test syntax. All `facades` of Goravel are defined under the `app/facades` folder: @@ -14,7 +12,7 @@ facades.Config().GetString("app.host") ## How Facades Work -Each service provider registers its corresponding bindings in the service container, then the service container providers vairous `Make*` functions to build the binding instances. The `facades` in the `app/facades` folder call these `Make*` functions to get the instances from the service container. Let's use the `Route` facade as an example: +Each service provider registers its corresponding bindings in the service container, then the service container provides various `Make*` functions to build the binding instances. The `facades` in the `app/facades` folder call these `Make*` functions to get the instances from the service container. Let's use the `Route` facade as an example: 1. The `Route` service provider registers the `binding.Route` binding in the service container: @@ -45,7 +43,9 @@ func Route() route.Route { } ``` -> Given that the `facades` is exposed to the application, you can also create your own `facades` or override the existing `facades` in the `app/facades` folder. +::: tip +Because `facades` are exposed to the application, you can create your own `facades` or override the existing ones in the `app/facades` folder. +::: ## Install/Uninstall Facades @@ -65,4 +65,6 @@ func Route() route.Route { ./artisan package:uninstall Route ``` -> Notice: if you are using the `./artisan package:install` command to choose the `facades` manually, you need to press `x` to select the facades you want to install, then press `Enter` to confirm. `facades` are not selected if you directly press `Enter`. +::: tip +If you are using the `./artisan package:install` command to choose the `facades` manually, you need to press `x` to select the facades you want to install, then press `Enter` to confirm. `facades` are not selected if you directly press `Enter`. +::: diff --git a/en/architecture-concepts/request-lifecycle.md b/en/architecture-concepts/request-lifecycle.md index 5f3b90be5..878fce7ab 100644 --- a/en/architecture-concepts/request-lifecycle.md +++ b/en/architecture-concepts/request-lifecycle.md @@ -1,7 +1,5 @@ # Request Lifecycle -[[toc]] - ## Introduction Using any tool in the real world feels more intuitive when you know how it works. This document aims to give you a clear, high-level look at how Goravel functions. Don’t worry if you don’t get every term right away—just aim for a basic sense of how things work, and your expertise will grow as you explore the rest of the docs. diff --git a/en/architecture-concepts/service-container.md b/en/architecture-concepts/service-container.md index 8bbed269d..972be7919 100644 --- a/en/architecture-concepts/service-container.md +++ b/en/architecture-concepts/service-container.md @@ -1,7 +1,5 @@ # Service Container -[[toc]] - ## Introduction The Goravel service container is a powerful tool for managing class dependencies and performing dependency injection. It contains all the modules of Goravel, and allows you to bind your own services to container and resolve them when needed. The service container provides powerful support for third-party packages around Goravel. diff --git a/en/architecture-concepts/service-providers.md b/en/architecture-concepts/service-providers.md index 9fb3bde8b..499679320 100644 --- a/en/architecture-concepts/service-providers.md +++ b/en/architecture-concepts/service-providers.md @@ -1,7 +1,5 @@ # Service Providers -[[toc]] - ## Introduction The most important thing in the kernel boot operation is to load the `ServiceProvider`. All `ServiceProvider` under the application are configured in the `bootstrap/providers.go` file. diff --git a/en/database/getting-started.md b/en/database/getting-started.md index 898ed2c44..3036e51ec 100644 --- a/en/database/getting-started.md +++ b/en/database/getting-started.md @@ -1,7 +1,5 @@ # Getting Started -[[toc]] - ## Introduction Almost all applications need to interact with databases, so Goravel provides a very simple and easy-to-use database interaction. Developers can use native SQL, query builder, and [Orm](../orm/getting-started) to interact with databases. Currently, Goravel provides official support for the following four databases: @@ -75,7 +73,9 @@ var product Product err := facades.DB().Select(&product, "SELECT * FROM products WHERE id = ?", 1) ``` -> Note: Different database drivers require different placeholders. For example, the `?` placeholder is used for MySQL, while the `@` placeholder is used for PostgreSQL. +::: warning +Different database drivers require different placeholders. For example, the `?` placeholder is used for MySQL, while the `@` placeholder is used for PostgreSQL. +::: ### Insert diff --git a/en/database/migrations.md b/en/database/migrations.md index 562c6050d..f19764981 100644 --- a/en/database/migrations.md +++ b/en/database/migrations.md @@ -1,7 +1,5 @@ # Migrations -[[toc]] - ## Introduction When multiple people collaborate to develop applications, it's crucial to have a standardized database structure for synchronization. Without this, there could be chaos as everyone's individual data won't match up. Database migration is the solution to this problem. The database structure is version-controlled to ensure its consistency within all developers. @@ -53,14 +51,14 @@ func Boot() contractsfoundation.Application { Use `create_users_table` to automatically generate a table containing the infrastructure of `users`: -``` +```text ^create_(\w+)_table$ ^create_(\w+)$ ``` Use `add_avatar_to_users_table` to automatically generate a structure for adding fields to the `users` table: -``` +```text _(to|from|in)_(\w+)_table$ _(to|from|in)_(\w+)$ ``` diff --git a/en/database/queries.md b/en/database/queries.md index 87343a12b..3b095a622 100644 --- a/en/database/queries.md +++ b/en/database/queries.md @@ -1,7 +1,5 @@ # Query Builder -[[toc]] - ## Introduction The database query builder provides a convenient interface to create and execute database queries. It can be used to perform most database operations in your application and works with all supported database systems. @@ -130,7 +128,9 @@ err := facades.DB().Table("products").Chunk(2, func(rows []db.Row) error { }) ``` -> Note: When modifying records in the Chunk callback, it may result in records not being included in the chunked results. +::: warning +When modifying records in the Chunk callback, it may result in records not being included in the chunked results. +::: ### Cursor diff --git a/en/database/seeding.md b/en/database/seeding.md index 8531ee9bf..93a3ac54c 100644 --- a/en/database/seeding.md +++ b/en/database/seeding.md @@ -1,7 +1,5 @@ # Database: Seeding -[[toc]] - ## Introduction Goravel includes the ability to seed your database with data using seed struct. All seed structs are stored in the `database/seeders` directory. By default, a `DatabaseSeeder` struct is defined for you. diff --git a/en/digging-deeper/artisan-console.md b/en/digging-deeper/artisan-console.md index f28f78897..299899b55 100644 --- a/en/digging-deeper/artisan-console.md +++ b/en/digging-deeper/artisan-console.md @@ -1,7 +1,5 @@ # Artisan Console -[[toc]] - ## Introduction Artisan is the CLI tool that comes with Goravel for interacting with the command line. You can access it using `facades.Artisan()`. This tool has several useful commands that can assist you in the development of your application. Utilize the following command to view all available commands. @@ -92,7 +90,9 @@ The return value determines the filtering behavior: - **Return `[]string{}`** — all commands are dropped. - **Return entries** — only commands whose signature matches an entry are kept. -> Note: The filter applies to all commands including those added via `WithCommands`, so the user cannot bypass the filter by adding commands manually. +::: info +The filter applies to all commands including those added via `WithCommands`, so the user cannot bypass the filter by adding commands manually. +::: ### Command Structure @@ -167,7 +167,7 @@ func (receiver *SendEmails) Extend() command.Extend { } ``` -Supported agrument types : `ArgumentFloat32`, `ArgumentFloat64`, `ArgumentInt`, `ArgumentInt8`, `ArgumentInt16`, `ArgumentInt32`, `ArgumentInt64`, `ArgumentString`, `ArgumentUint`, `ArgumentUint8`, `ArgumentUint16`, `ArgumentUint32`, `ArgumentUint64`, `ArgumentTimestamp`, `ArgumentFloat32Slice`, `ArgumentFloat64Slice`, `ArgumentIntSlice`, `ArgumentInt8Slice`, `ArgumentInt16Slice`, `ArgumentInt32Slice`, `ArgumentInt64Slice`, `ArgumentStringSlice`, `ArgumentUintSlice`, `ArgumentUint8Slice`, `ArgumentUint16Slice`, `ArgumentUint32Slice`, `ArgumentUint64Slice`, `ArgumentTimestampSlice` +Supported argument types: `ArgumentFloat32`, `ArgumentFloat64`, `ArgumentInt`, `ArgumentInt8`, `ArgumentInt16`, `ArgumentInt32`, `ArgumentInt64`, `ArgumentString`, `ArgumentUint`, `ArgumentUint8`, `ArgumentUint16`, `ArgumentUint32`, `ArgumentUint64`, `ArgumentTimestamp`, `ArgumentFloat32Slice`, `ArgumentFloat64Slice`, `ArgumentIntSlice`, `ArgumentInt8Slice`, `ArgumentInt16Slice`, `ArgumentInt32Slice`, `ArgumentInt64Slice`, `ArgumentStringSlice`, `ArgumentUintSlice`, `ArgumentUint8Slice`, `ArgumentUint16Slice`, `ArgumentUint32Slice`, `ArgumentUint64Slice`, `ArgumentTimestampSlice` Argument types with single value support next fields: @@ -636,9 +636,11 @@ func (receiver *ConsoleMakeCommand) Extend() command.Extend { Sometimes you may wish to execute an Artisan command outside of the CLI, you can use the `Call` method on the `facades.Artisan()` to operate this. ```go -facades.Route().Get("/", func(c *gin.Context) { +facades.Route().Get("/", func(ctx http.Context) http.Response { facades.Artisan().Call("emails") facades.Artisan().Call("emails --lang Chinese name") // With arguments and options + + return ctx.Response().Success().String("done") }) ``` diff --git a/en/digging-deeper/cache.md b/en/digging-deeper/cache.md index 4c6bd8890..adf466972 100644 --- a/en/digging-deeper/cache.md +++ b/en/digging-deeper/cache.md @@ -1,7 +1,5 @@ # Cache -[[toc]] - ## Introduction Goravel provides an expandable cache module that can be operated using `facades.Cache()`. Goravel comes with a `memory` driver, for other drivers, please check the corresponding independent extension packages: @@ -14,6 +12,15 @@ Goravel provides an expandable cache module that can be operated using `facades. Make all custom configurations in `config/cache.go`. +### Cache Key Prefix + +The `prefix` option is added in front of every key, so applications sharing one cache store do not collide. With the prefix `goravel_cache`, the key `users` is stored as `goravel_cache:users`. An empty prefix stores the key as is. + +```go +// config/cache.go +"prefix": config.GetString("APP_NAME", "goravel") + "_cache", +``` + ## Cache Usage ### Inject Context diff --git a/en/digging-deeper/collections.md b/en/digging-deeper/collections.md index 3f3c86aba..19f44fd82 100644 --- a/en/digging-deeper/collections.md +++ b/en/digging-deeper/collections.md @@ -1,7 +1,5 @@ # Collections -[[toc]] - ## Introduction Goravel provides a fluent collection API through the `github.com/goravel/framework/support/collect` package. Collections make it convenient to filter, transform, aggregate, and inspect slice data with chainable methods. diff --git a/en/digging-deeper/color.md b/en/digging-deeper/color.md index b048ea7c7..8105abc75 100644 --- a/en/digging-deeper/color.md +++ b/en/digging-deeper/color.md @@ -1,7 +1,5 @@ # Color -[[toc]] - ## Introduction The `color` package provides a set of functions to colorize the output of the terminal using [PTerm](https://github.com/pterm/pterm) library. diff --git a/en/digging-deeper/event.md b/en/digging-deeper/event.md index 35ba3f365..3b3a57a7a 100644 --- a/en/digging-deeper/event.md +++ b/en/digging-deeper/event.md @@ -1,7 +1,5 @@ # Events -[[toc]] - ## Introduction Goravel's events provide a simple observer pattern implementation, allowing you to subscribe and listen to various events that occur within your application. Event classes are typically stored in the `app/events` directory, while their listeners are stored in `app/listeners`. Don't worry if you don't see these directories in your application as they will be created for you as you generate events and listeners using Artisan console commands. diff --git a/en/digging-deeper/filesystem.md b/en/digging-deeper/filesystem.md index 465ba7196..38b20adeb 100644 --- a/en/digging-deeper/filesystem.md +++ b/en/digging-deeper/filesystem.md @@ -1,7 +1,5 @@ # File Storage -[[toc]] - ## Introduction The Goravel provides simple drivers for working with local filesystems, Amazon S3, Aliyun OSS, Tencent COS, Minio and Cloudinary. Even better, switching between these storage options between your local development machine and production server is amazingly simple as the API remains the same for each system. Goravel comes with a `local` driver, for other drivers, please check the corresponding independent extension package: @@ -17,7 +15,9 @@ The Goravel provides simple drivers for working with local filesystems, Amazon S Goravel's filesystem configuration file is located at `config/filesystems.go`. Within this file, you may configure all of your filesystem "disks", each disk represents a particular storage driver and storage location. -> You may configure as many disks as you like and may even have multiple disks that use the same driver. +::: tip +You may configure as many disks as you like and may even have multiple disks that use the same driver. +::: ### The Local Driver @@ -87,7 +87,9 @@ You may use the `Url` method to get the URL for a given file. If you are using t url := facades.Storage().Url("file.jpg") ``` -> When using the `local` driver, the return value of `Url` is not URL encoded. For this reason, we recommend always storing your files using names that will create valid URLs. +::: warning +When using the `local` driver, the return value of `Url` is not URL encoded. For this reason, we recommend always storing your files using names that will create valid URLs. +::: #### Temporary URLs @@ -212,7 +214,9 @@ file, err := filesystem.NewFile("./logo.png") path := facades.Storage().PutFileAs("photos", file, "name") ``` -> If the file name specified by `StoreAs` and `PutFileAs` doesn't have a suffix, the suffix is automatically added based on the MIME of the file; otherwise, the specified file name is used directly. +::: info +If the file name passed to `StoreAs` or `PutFileAs` has no suffix, one is added based on the file's MIME type. Otherwise the name is used as given. +::: ### Specifying A Disk @@ -337,4 +341,6 @@ type Driver interface { } ``` -> Note: Since the configuration has not been loaded when the custom driver is registered, so please use `facades.Config().Env()` to obtain the configuration in the custom driver. +::: warning +Since the configuration has not been loaded when the custom driver is registered, so please use `facades.Config().Env()` to obtain the configuration in the custom driver. +::: diff --git a/en/digging-deeper/helpers.md b/en/digging-deeper/helpers.md index cccbd5f7a..92be9ccc7 100644 --- a/en/digging-deeper/helpers.md +++ b/en/digging-deeper/helpers.md @@ -1,7 +1,5 @@ # Helpers -[[toc]] - ## Available Methods ### Paths diff --git a/en/digging-deeper/http-client.md b/en/digging-deeper/http-client.md index fc9cc5358..45cec0c59 100644 --- a/en/digging-deeper/http-client.md +++ b/en/digging-deeper/http-client.md @@ -1,7 +1,5 @@ # HTTP Client -[[toc]] - ## Introduction In software development, there are many instances when you need to call an API to fetch data— @@ -163,11 +161,11 @@ response, err := facades.Http(). Get("https://api.example.com") ``` -For convenience, you can use `AcceptJson` to quickly specify that you expect the API response to be in `application/json` format: +For convenience, you can use `AcceptJSON` to quickly specify that you expect the API response to be in `application/json` format: ```go response, err := facades.Http(). - AcceptJson(). + AcceptJSON(). Get("https://api.example.com/data") ``` @@ -259,7 +257,7 @@ type User struct { func main() { var user User - response, err := facades.Http().AcceptJson().Get("https://jsonplaceholder.typicode.com/users/1") + response, err := facades.Http().AcceptJSON().Get("https://jsonplaceholder.typicode.com/users/1") if err != nil { fmt.Println("Error making request:", err) return diff --git a/en/digging-deeper/localization.md b/en/digging-deeper/localization.md index 53b8a335e..e6891fc20 100644 --- a/en/digging-deeper/localization.md +++ b/en/digging-deeper/localization.md @@ -1,14 +1,12 @@ # Localization -[[toc]] - ## Introduction Goravel's localization features provide a convenient way to retrieve strings in various languages, making it easy to support multiple languages in your application. Language strings are stored in files in the `lang` directory, and Goravel supports two ways to organize language files: Each language has its own file: -``` +```text /lang en.json cn.json @@ -16,7 +14,7 @@ Each language has its own file: Or, when there are too many translations, they can be categorized: -``` +```text /lang /en user.json @@ -40,7 +38,7 @@ facades.Route().Get("/", func(ctx http.Context) http.Response { You can configure a "fallback locale" that will be used when the current language does not contain the given translation string. Like the default language, the fallback language is also configured in the `config/app.go` configuration file. -``` +```go "fallback_locale": "en", ``` @@ -48,7 +46,7 @@ You can configure a "fallback locale" that will be used when the current languag You can use the `CurrentLocale` and `IsLocale` methods to determine the current `locale` or check if the `locale` is a given value. -``` +```go locale := facades.App().CurrentLocale(ctx) if facades.App().IsLocale(ctx, "en") {} ``` @@ -73,7 +71,7 @@ You can use the `facades.Lang(ctx).Get()` method to retrieve translation strings For example: -``` +```json // lang/en.json { "name": "It's your name", @@ -143,7 +141,7 @@ facades.Lang(ctx).Choice("messages.apples", 10) You can also define placeholder attributes in pluralization strings. By passing an array as the third parameter to the `facades.Lang(ctx).Choice()` method, you can replace these placeholders: -``` +```go "minutes_ago": "{1} :value minute ago|[2,*] :value minutes ago", facades.Lang(ctx).Choice("time.minutes_ago", 5, translation.Option{ @@ -159,7 +157,7 @@ When using embed loading, the language files will be compiled into the binary fi In the same directory as the language files, create a `fs.go` file: -``` +```text /lang en.json cn.json diff --git a/en/digging-deeper/mail.md b/en/digging-deeper/mail.md index ca78e930c..b245133d4 100644 --- a/en/digging-deeper/mail.md +++ b/en/digging-deeper/mail.md @@ -1,7 +1,5 @@ # Mail -[[toc]] - ## Introduction Goravel can use `facades.Mail()` to easily send mail locally. diff --git a/en/digging-deeper/package-development.md b/en/digging-deeper/package-development.md index d1885a133..d7f7608b8 100644 --- a/en/digging-deeper/package-development.md +++ b/en/digging-deeper/package-development.md @@ -1,7 +1,5 @@ # Package Development -[[toc]] - ## Introduction Packages are the primary way of adding functionality to Goravel. These packages may contain routes, controllers, and configurations that are specifically designed to enhance a Goravel application. This guide focuses on developing Goravel-specific packages. diff --git a/en/digging-deeper/pluralization.md b/en/digging-deeper/pluralization.md index 4908abcfb..91500dd4d 100644 --- a/en/digging-deeper/pluralization.md +++ b/en/digging-deeper/pluralization.md @@ -1,7 +1,5 @@ # Pluralization -[[toc]] - ## Introduction Strings are important for any web application. Goravel provides simple utilities to convert words between singular diff --git a/en/digging-deeper/processes.md b/en/digging-deeper/processes.md index 4dc688d37..7fe479d7d 100644 --- a/en/digging-deeper/processes.md +++ b/en/digging-deeper/processes.md @@ -1,7 +1,5 @@ # Processes -[[toc]] - ## Introduction Goravel provides an expressive and elegant API around Go's standard `os/exec` package, allowing you to invoke external commands from your application seamlessly. By default, Go's process handling can be verbose; Goravel's `Process` facade simplifies this common task, offering a fluent interface for executing commands, handling output, and managing asynchronous processes. diff --git a/en/digging-deeper/queues.md b/en/digging-deeper/queues.md index 44ca4b28b..37535d4e2 100644 --- a/en/digging-deeper/queues.md +++ b/en/digging-deeper/queues.md @@ -1,7 +1,5 @@ # Queues -[[toc]] - ## Introduction When building your web application, there may be tasks, like parsing and storing an uploaded CSV file, that take too long to complete during a web request. Fortunately, Goravel offers a solution by allowing you to create queued jobs that can run in the background. This way, by moving time-intensive tasks to a queue, your application can respond to web requests much faster and provide a better user experience for your customers. To implement this feature, we use `facades.Queue()`. @@ -44,7 +42,7 @@ The official implementation of the `Redis` driver, you can refer to [Redis Drive After implementing the custom driver, you can add the configuration to `config/queue.go`: -``` +```go ... "connections": map[string]any{ "redis": map[string]any{ @@ -149,7 +147,7 @@ func (r *ProcessPodcast) ShouldRetry(err error, attempt int) (retryable bool, de ## Start Queue Server -The default queue worker will be run by the runner of queue seriver provider, if you want to start multiple queue workers with different configuration, you can create [a runner](../architecture-concepts/service-providers.md#runners) and add it to the `WithRunners` function in the `bootstrap/app.go` file: +The default queue worker will be run by the runner of queue service provider, if you want to start multiple queue workers with different configuration, you can create [a runner](../architecture-concepts/service-providers.md#runners) and add it to the `WithRunners` function in the `bootstrap/app.go` file: ```go func Boot() contractsfoundation.Application { diff --git a/en/digging-deeper/strings.md b/en/digging-deeper/strings.md index dc8d7fafd..639233e5e 100644 --- a/en/digging-deeper/strings.md +++ b/en/digging-deeper/strings.md @@ -1,7 +1,5 @@ # Strings -[[toc]] - ## Introduction Goravel provides a fluent string manipulation library that allows you to easily manipulate strings. Fluent Strings allows you to combine multiple string operations through method chaining, where most of the methods returns an instance of `support/str.String`, letting you chain additional methods. To get the final string value after applying the chained operations, you can call the `String` method, which returns the underlying `string` value. diff --git a/en/digging-deeper/task-scheduling.md b/en/digging-deeper/task-scheduling.md index 1c8dbbfe1..25d459104 100644 --- a/en/digging-deeper/task-scheduling.md +++ b/en/digging-deeper/task-scheduling.md @@ -1,7 +1,5 @@ # Task Scheduling -[[toc]] - ## Introduction In the past, you might need to create a cron configuration entry for each task that needed scheduling on your server. However, this approach can quickly become a pain as your task schedule is not in source control, and you have to SSH into your server to view or add/edit cron entries. @@ -41,12 +39,12 @@ When `app.debug` is `true`, the console will print all logs. Otherwise, only `er ### Schedule Frequency Options -We've already seen a few examples of how you may configure a task to run at specified intervals. However, there are many more task schedule frequencies avaibable to assign to tasks: +We've already seen a few examples of how you may configure a task to run at specified intervals. However, there are many more task schedule frequencies available to assign to tasks: -| 方法 | 描述 | +| Method | Description | | ------------------------ | --------------------------------------------------- | -| `.Cron("* * * * *")` | Custom Crone schedule (minutes) | -| `.Cron("* * * * * *")` | Custom Crone schedule (seconds) | +| `.Cron("* * * * *")` | Custom Cron schedule (minutes) | +| `.Cron("* * * * * *")` | Custom Cron schedule (seconds) | | `.EverySecond()` | Run the task every second | | `.EveryTwoSeconds()` | Run the task every two seconds | | `.EveryFiveSeconds()` | Run the task every five seconds | @@ -89,7 +87,7 @@ We've already seen a few examples of how you may configure a task to run at spec By default, scheduled tasks will continue to run even if a previous instance is still running. To prevent this, use the following methods: -| 方法 | 描述 | +| Method | Description | | ------------------------ | ---------------------- | | `.SkipIfStillRunning()` | Skip if still running | | `.DelayIfStillRunning()` | Delay if still running | @@ -101,7 +99,9 @@ facades.Schedule().Command("send:emails name").EveryMinute().DelayIfStillRunning ### Running Tasks On One Server -> To utilize this feature, your application must be using the memcached, dynamodb, or redis cache driver as the default cache driver. In addition, all servers must be communicating with the same central cache server. +::: warning +This feature takes a lock in the default cache, so every server must share that cache. Use a shared driver such as [redis](./cache.md) as the default cache driver. The `memory` driver will not work, because each server has its own. +::: If your application's scheduler runs on multiple servers, you can ensure that a scheduled job is executed on only one of them. For example, let's say you have a scheduled task that generates a new report every Friday night. If the task scheduler runs on three worker servers, the scheduled task will run on all three servers and create the report three times. This is not ideal! diff --git a/en/digging-deeper/telemetry.md b/en/digging-deeper/telemetry.md index 7ccd88faa..a637d9a58 100644 --- a/en/digging-deeper/telemetry.md +++ b/en/digging-deeper/telemetry.md @@ -1,7 +1,5 @@ # Telemetry -[[toc]] - ## Introduction Goravel provides an observability module built on top of [OpenTelemetry](https://opentelemetry.io) that can be operated using `facades.Telemetry()`. It allows you to collect traces, metrics, and logs from your application and export them to any OTLP-compatible backend, such as Jaeger, Prometheus, Grafana, or Datadog. diff --git a/en/getting-started/compile.md b/en/getting-started/compile.md index c05e8ac72..1c6f95a1f 100644 --- a/en/getting-started/compile.md +++ b/en/getting-started/compile.md @@ -1,7 +1,5 @@ # Compile -[[toc]] - ## Compile command The Goravel project can be compiled with the following command: @@ -47,7 +45,7 @@ go build . The Following files and folders need to be uploaded to the server during deployment: -``` +```text .env ./main // Compile the resulting binary file ./public // if exists @@ -67,13 +65,13 @@ go build --ldflags "-extldflags -static" -o main . Compilation is differentiated by platform, you need to select a matching compilation method according to the deployment situation. ```shell -// Compile Linux environment +# Compile Linux environment CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build . -// Compile Windows environment +# Compile Windows environment CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build . -// Compile Mac environment +# Compile Mac environment CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build . ``` @@ -126,7 +124,9 @@ docker-compose build docker-compose up ``` -> Note: If you need external access, you need to change APP_HOST to 0.0.0.0 +::: tip +If you need external access, you need to change APP_HOST to 0.0.0.0 +::: ## Set timezone @@ -134,13 +134,13 @@ When the `app.timezone` configuration is not `UTC`, you need to set the timezone 1. Add timezone settings in Dockerfile -``` +```dockerfile RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone ``` 2. Set timezone during compilation -``` +```shell go build -tags timetzdata . ``` diff --git a/en/getting-started/configuration.md b/en/getting-started/configuration.md index 2320996f6..7c71aacad 100644 --- a/en/getting-started/configuration.md +++ b/en/getting-started/configuration.md @@ -1,7 +1,5 @@ # Configuration -[[toc]] - ## Introduction All configuration files of the Goravel framework are stored in the `config` directory. You can view specific instructions and configure them flexibly according to project needs. @@ -12,7 +10,9 @@ Running applications in different environments usually requires different config Therefore, the framework provides the `.env.example` file in the root directory. You need to copy this file, rename it to `.env` before you start development, and modify the configuration items in the `.env` file according to your project needs. -Note that the `.env` file should not be added to version control, because when multiple people collaborate, different developers may use different configurations, and different deployment environment configurations are different. +::: warning +The `.env` file should not be added to version control, because when multiple people collaborate, different developers may use different configurations, and different deployment environment configurations are different. +::: In addition, if an intruder gains access to your code repository, there will be a risk of exposing sensitive configuration. If you want to add a new configuration item, you can add it to the `.env.example` file to synchronize the configuration of all developers. diff --git a/en/getting-started/directory-structure.md b/en/getting-started/directory-structure.md index f7e1065de..3e756c290 100644 --- a/en/getting-started/directory-structure.md +++ b/en/getting-started/directory-structure.md @@ -1,14 +1,12 @@ # Directory Structure -[[toc]] - ## Introduction The default file structure can make you better start project advancement, and you can also add new folders freely, but do not modify the default folders. ## Folder Tree -``` +```text goravel/ ├── app/ # Core application logic │ ├── ai/ # AI agents and tools diff --git a/en/getting-started/installation.md b/en/getting-started/installation.md index d97aee581..5b66cf553 100644 --- a/en/getting-started/installation.md +++ b/en/getting-started/installation.md @@ -1,10 +1,8 @@ # Installation -[[toc]] - ## Server Requirements -- Golang >= 1.23 +- Golang >= 1.25 ## Installation @@ -13,13 +11,15 @@ Initialize the installer according to the [documentation](https://github.com/goravel/installer), and then initialize a new Goravel project using the following command: ```shell -// Install the latest version of the goravel installer +# Install the latest version of the goravel installer go install github.com/goravel/installer/goravel@latest -// Enter the directory where you want to install the project +# Enter the directory where you want to install the project goravel new blog ``` +The installer asks which template to use: the full framework, or [Goravel Lite](#goravel-goravel-lite) with only the essential facades. + ### Manual Installation #### goravel/goravel @@ -27,16 +27,16 @@ goravel new blog The complete framework with full features. ```shell -// Download framework +# Download framework git clone --depth=1 https://github.com/goravel/goravel.git && rm -rf goravel/.git* -// Install dependencies +# Install dependencies cd goravel && go mod tidy -// Create .env environment configuration file +# Create .env environment configuration file cp .env.example .env -// Generate application key +# Generate application key ./artisan key:generate ``` @@ -45,23 +45,24 @@ cp .env.example .env The lite framework with only essential features, suitable for building microservices or small applications. You can install additional facades as needed. ```shell -// Download framework +# Download framework git clone --depth=1 https://github.com/goravel/goravel-lite.git && rm -rf goravel-lite/.git* -s -// Install dependencies +# Install dependencies cd goravel-lite && go mod tidy -// Create .env environment configuration file +# Create .env environment configuration file cp .env.example .env -// Generate application key +# Generate application key ./artisan key:generate -// Install additional facades as needed, for example: +# Install additional facades as needed, for example: ./artisan package:install Cache ``` -> Please confirm your network if you encounter slow download dependencies. +::: tip +If dependencies download slowly, check your network connection. +::: ## Start Services @@ -87,19 +88,17 @@ APP_ENV=production APP_DEBUG=true go run . Install [air-verse/air](https://github.com/air-verse/air), Goravel has a built-in configuration file that can be used directly: -``` +```shell air ``` -#### 🧰 After Installing Air +#### After Installing Air Once you have successfully installed Air, you need to make sure it can be executed properly within your environment. Depending on your setup, Air might not be automatically available as a command. Here are two simple ways to ensure it runs correctly: ---- - -#### 🪄 Option 1: Using a Helper Script (`air.sh`) +#### Option 1: Using a Helper Script (`air.sh`) If Air is installed but not recognized as a terminal command, you can create a small helper script that locates and runs it automatically. @@ -134,7 +133,7 @@ $GO_BIN This ensures Air runs even if your `$PATH` does not include Go binaries. -#### 💡 Option 2: Add Go Bin To PATH (Mac/Linux) +#### Option 2: Add Go Bin To PATH (Mac/Linux) If you prefer to run Air directly without a script, you can add Go bin directory to your PATH. @@ -151,8 +150,7 @@ After this setup, you can start your project simply by running: air ``` -#### ✅ Tip - +::: tip To verify that Air is installed and accessible, run: ```bash @@ -160,6 +158,7 @@ which air ``` If it doesn't return a valid path (for example `/Users/yourname/go/bin/air`), it means the helper script or the path hasn't been configured yet. +::: ## Configuration @@ -190,7 +189,7 @@ You may want to add the production environment env file to version control, but ```shell ./artisan env:encrypt -// Specify the file name and key +# Specify the file name and key ./artisan env:encrypt --name .env.safe --key BgcELROHL8sAV568T7Fiki7krjLHOkUc ``` @@ -199,6 +198,6 @@ Then use the `env:decrypt` command to decrypt the env file in the production env ```shell GORAVEL_ENV_ENCRYPTION_KEY=BgcELROHL8sAV568T7Fiki7krjLHOkUc ./artisan env:decrypt -// or +# or ./artisan env:decrypt --name .env.safe --key BgcELROHL8sAV568T7Fiki7krjLHOkUc ``` diff --git a/en/getting-started/packages.md b/en/getting-started/packages.md index ef4e9f347..3228db1e6 100644 --- a/en/getting-started/packages.md +++ b/en/getting-started/packages.md @@ -1,8 +1,12 @@ +--- +aside: false +--- + # Excellent Extend Packages -You can find extended packages for Goravel here, and you can also create a PR for [goravel/docs](https://github.com/goravel/docs) to commit your owner package, please improve the test coverage of your package as much as possible. +Here you can find packages that extend Goravel. To add your own, open a PR against [goravel/docs](https://github.com/goravel/docs). Please keep your package's test coverage as high as you can. -| Package | Description | Test Coverage* | +| Package | Description | Test Coverage | | --------------------------------------------------------------------------------- | --------------------------------------------- | ------------- | | [goravel/gin](https://github.com/goravel/gin) | The Gin driver for `facades.Route()` | 83.1% | | [goravel/fiber](https://github.com/goravel/fiber) | The Fiber driver for `facades.Route()` | 81.0% | @@ -17,22 +21,25 @@ You can find extended packages for Goravel here, and you can also create a PR fo | [goravel/anthropic](https://github.com/goravel/anthropic) | An Anthropic driver for `facades.AI()` | 73.3% | | [goravel/mysql](https://github.com/goravel/mysql) | A MySQL database driver | 73.3% | | [goravel/sqlserver](https://github.com/goravel/sqlserver) | A Sqlserver database driver | 60.6% | -| [goravel/sqlite](https://github.com/goravel/sqlite) | A Sqlite database driver | 45.2% | | [goravel/gemini](https://github.com/goravel/gemini) | A Gemini driver for `facades.AI()` | 51.8% | +| [goravel/sqlite](https://github.com/goravel/sqlite) | A Sqlite database driver | 45.2% | | [portofolio-mager/goravel-mongodb](https://github.com/portofolio-mager/goravel-mongodb) | A MongoDB package | 16.9% | -| [hulutech-web/goravel-kit-cli](https://github.com/hulutech-web/goravel-kit-cli) | A goravel scaffold commandline tool | 15.2% | +| [hulutech-web/goravel-kit-cli](https://github.com/hulutech-web/goravel-kit-cli) | A Goravel scaffold command-line tool | 15.2% | | [hulutech-web/goravel-workflow](https://github.com/hulutech-web/goravel-workflow) | A workflow package | 4.4% | | [hulutech-web/goravel-crud](https://github.com/hulutech-web/goravel-crud) | A goravel crud package | 4.2% | | [hulutech-web/tinker](https://github.com/hulutech-web/tinker) | A goravel tinker package | 3.6% | | [hulutech-web/goravel-socket](https://github.com/hulutech-web/goravel-socket) | A webSocket package | 0% | -***Note**: The packages are ordered based on their test rate. +::: info +Packages are ordered by test coverage. +::: -💡 Tip: To help more developers discover your work, you can also add relevant topics to your repository. -Recommended topic: [`goravel-package`](https://github.com/topics/goravel-package) +::: tip Help developers find your package +Add the [`goravel-package`](https://github.com/topics/goravel-package) topic to your repository. -- On GitHub, navigate to the main page of the repository. -- In the top right corner of the page, to the right of "About", click gear icon (settings). -- Under "Topics", start to type the topic you want to add to your repository to display a dropdown menu of any matching topics. -- Click the topic you want to add or continue typing to create a new topic. For example: `goravel-package`, `goravel` and any other relevant keywords. -- Click `Save changes` — this will make your package more discoverable. +1. On GitHub, navigate to the main page of the repository. +2. In the top right corner of the page, to the right of "About", click gear icon (settings). +3. Under "Topics", start to type the topic you want to add to your repository to display a dropdown menu of any matching topics. +4. Click the topic you want to add or continue typing to create a new topic. For example: `goravel-package`, `goravel` and any other relevant keywords. +5. Click `Save changes` — this will make your package more discoverable. +::: diff --git a/en/index.md b/en/index.md index 684cf767a..507d86035 100644 --- a/en/index.md +++ b/en/index.md @@ -1,13 +1,12 @@ --- -layout: home -title: Goravel - Full-featured Golang Development Framework +title: Goravel - Familiar structure. Native Go. head: - [ 'meta', { name: description, - content: Goravel is a Golang development framework with complete functions and excellent scalability. As a starting scaffolding to help Gopher quickly build their own applications. + content: "Goravel is a full-featured web framework for Go with the structure of Laravel. Routing, ORM, queues, scheduling, mail, auth and testing in one framework." } ] - ['meta', { property: og:url, content: https://www.goravel.dev }] @@ -16,14 +15,14 @@ head: 'meta', { property: og:title, - content: Goravel - Full-featured Golang Development Framework + content: Goravel - Familiar structure. Native Go. } ] - [ 'meta', { property: og:description, - content: Goravel is a Golang development framework with complete functions and excellent scalability. As a starting scaffolding to help Gopher quickly build their own applications. + content: "Goravel is a full-featured web framework for Go with the structure of Laravel. Routing, ORM, queues, scheduling, mail, auth and testing in one framework." } ] - ['meta', { property: og:image, content: https://www.goravel.dev/meta.png }] @@ -34,152 +33,19 @@ head: 'meta', { name: twitter:title, - content: Goravel - The Golang Framework For Web Artisans + content: Goravel - Familiar structure. Native Go. } ] - [ 'meta', { name: twitter:description, - content: Goravel is a Golang development framework with complete functions and excellent scalability. As a starting scaffolding to help Gopher quickly build their own applications. + content: "Goravel is a full-featured web framework for Go with the structure of Laravel. Routing, ORM, queues, scheduling, mail, auth and testing in one framework." } ] - ['meta', { name: twitter:image, content: https://www.goravel.dev/meta.png }] -hero: - name: Goravel - text: Full-featured Golang Development Framework - tagline: Componentization, High-performance, easy-to-extend, PHPers' first choice. - # image: /logo.svg - actions: - - theme: brand - text: Quick Start - link: /getting-started/installation - - theme: alt - text: 🌟 Github Star - link: https://github.com/goravel/goravel - target: _blank -features: - - title: 🧰 Lite Or Full-featured - details: You can choose between a lightweight version with essential features or a full-featured version that includes ORM, HTTP, logging, caching, and other basic tools for all development. - - title: 💻 Componentization - details: Modular design, each module is independent and can be used separately, making development and maintenance more convenient. - - title: 🚀 High-performance - details: Built with Golang, integrating multiple excellent extensions to create fast and responsive applications. - - title: 📈 Easy-to-extend - details: The module provides multiple drivers, and can develop extension packages according to needs, suitable for applications of any scale, from small projects to large systems. - - title: 👥 Active community - details: Supported by an active community, they contribute to its development, documentation, and continuous support. - - title: 🔄 PHPers' first choice - details: The framework style is consistent with Laravel, allowing PHPer to create powerful Golang applications without learning a new framework. Tribute to Laravel! +layout: goravel-home +sidebar: false +aside: false --- - -
Contributors
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
Group
-
- -
- -
Scan QR code to join the Wechat group
-
- -
- - - - - -
Click me to join the Discord group
-
- -
-
- -
-
Reward
-
- -
- -
Scan QR code by Wechat
-
- -
- - -
-
-
- - diff --git a/en/orm/factories.md b/en/orm/factories.md index 8a19700bc..0dcd842b6 100644 --- a/en/orm/factories.md +++ b/en/orm/factories.md @@ -1,7 +1,5 @@ # Factories -[[toc]] - ## Introduction When testing your application or seeding your database, it might be necessary to insert a few records into your database beforehand. Instead of manually inputting values for each column, Goravel allows you to define a set of default attributes for each of your models by creating model factories. @@ -28,7 +26,7 @@ As you can see, in their most basic form, factories are structs that have a `Def To create a factory, run the `make:factory` Artisan command: -``` +```shell go run . artisan make:factory PostFactory ``` diff --git a/en/orm/getting-started.md b/en/orm/getting-started.md index 156b038ab..a6b2d9b98 100644 --- a/en/orm/getting-started.md +++ b/en/orm/getting-started.md @@ -1,7 +1,5 @@ # Getting Started -[[toc]] - ## Introduction Goravel provides a very simple and easy-to-use database interaction, developers can use `facades.Orm()` to operate. Please refer to [Configure Database](../database/getting-started) before starting. @@ -99,7 +97,7 @@ func (r *UserData) Scan(value any) (err error) { ```shell ./artisan make:model --table=users User -// If the Model already exists, you can use the -f option to force overwrite +# If the Model already exists, you can use the -f option to force overwrite ./artisan make:model --table=users -f User ``` @@ -256,7 +254,7 @@ facades.Orm().Query().WithoutGlobalScopes("name").Get(&users) | Functions | Action | | --------------------------- | ----------------------------------------------------------------------------- | -| Avg | [Avg](#Avarage) | +| Avg | [Avg](#aggregates) | | BeginTransaction | [Begin transaction](#transaction) | | Commit | [Commit transaction](#transaction) | | Context | [Inject Context](#inject-context) | @@ -277,13 +275,13 @@ facades.Orm().Query().WithoutGlobalScopes("name").Get(&users) | FirstOrFail | [Not Found Error](#not-found-error) | | ForceDelete | [Force delete](#delete) | | Get | [Query multiple lines](#query-multiple-lines) | -| Group | [Group](#group-by--having) | +| Group | [Group](#group-by-having) | | Having | [Having](#group-by-having) | | Join | [Join](#join) | | Limit | [Limit](#limit) | | LockForUpdate | [Pessimistic Locking](#pessimistic-locking) | -| Max | [Max](#Avarage) | -| Min | [Min](#Avarage) | +| Max | [Max](#aggregates) | +| Min | [Min](#aggregates) | | Model | [Specify a model](#specify-table-query) | | Offset | [Offset](#offset) | | Order | [Order](#order) | @@ -304,17 +302,17 @@ facades.Orm().Query().WithoutGlobalScopes("name").Get(&users) | Raw | [Execute native SQL](#execute-native-sql) | | Restore | [Restore](#restore) | | Rollback | [Rollback transaction](#transaction) | -| Save | [Update a existing model](#update-a-existing-model) | +| Save | [Update an existing model](#update-an-existing-model) | | SaveQuietly | [Saving a single model without events](#saving-a-single-model-without-events) | | Scan | [Scan struct](#execute-native-sql) | | Scopes | [Scopes](#scopes) | | Select | [Specify Fields](#specify-fields) | | SharedLock | [Pessimistic Locking](#pessimistic-locking) | -| Sum | [Sum](#Avarage) | +| Sum | [Sum](#aggregates) | | Table | [Specify a table](#specify-table-query) | | ToSql | [Get SQL](#get-sql) | | ToRawSql | [Get SQL](#get-sql) | -| Update | [Update a single column](#update-a-single-column) | +| Update | [Update columns](#update-columns) | | UpdateOrCreate | [Update or create](#update-or-create) | | Where | [Where](#where) | | WhereAll | [WhereAll](#where) | @@ -701,11 +699,13 @@ err := facades.Orm().Query().Model(&models.User{}).Create(&[]map[string]any{ }) ``` -> `created_at` and `updated_at` will be filled automatically. +::: info +`created_at` and `updated_at` are filled automatically. +::: ### Cursor -Can be used to significantly reduce your application's memory consumption when iterating through tens of thousands of Eloquent model records. Note, the `Cursor` method can be used with `With` at the same time, please use [Lazy Eager Loading](./relationships.md#lazy-eager-loading) to load relationship in the `for` logic. +Can be used to significantly reduce your application's memory consumption when iterating through tens of thousands of model records. Note, the `Cursor` method can be used with `With` at the same time, please use [Lazy Eager Loading](./relationships.md#lazy-eager-loading) to load relationship in the `for` logic. ```go cursor, err := facades.Orm().Query().Model(models.User{}).Cursor() @@ -746,7 +746,9 @@ facades.Orm().Query().Model(&models.User{}).Where("name", "tom").Update(map[stri // UPDATE `users` SET `updated_at`='2023-09-18 21:07:06.489',`name`='hello',`age`=18 WHERE `name` = 'tom'; ``` -> When updating with `struct`, Orm will only update non-zero fields. You might want to use `map` to update attributes or use `Select` to specify fields to update. Note that `struct` can only be `Model`, if you want to update with non `Model`, you need to use `.Table("users")`, however, the `updated_at` field cannot be updated automatically at this time. +::: warning Zero values are skipped +When updating with `struct`, Orm will only update non-zero fields. You might want to use `map` to update attributes or use `Select` to specify fields to update. Note that `struct` can only be `Model`, if you want to update with non `Model`, you need to use `.Table("users")`, however, the `updated_at` field cannot be updated automatically at this time. +::: #### Update JSON fields @@ -818,7 +820,8 @@ facades.Orm().Query().Select(orm.Associations).Delete(&user) facades.Orm().Query().Select("Account").Delete(&users) ``` -Note: The associations will be deleted only if the primary key of the record is not empty, and Orm uses these primary keys as conditions to delete associated records: +::: warning +The associations are deleted only if the primary key of the record is not empty, because Orm uses these primary keys as conditions to delete associated records: ```go // Delete user that name='goravel', but don't delete account of user @@ -830,6 +833,7 @@ facades.Orm().Query().Select("Account").Where("name", "goravel").Delete(&models. // Delete user that id = 1 and delete account of that user facades.Orm().Query().Select("Account").Delete(&models.User{ID: 1}) ``` +::: If execute batch delete without any conditions, ORM doesn't do that and returns an error. So you have to add some conditions, or use native SQL. @@ -975,14 +979,14 @@ var users []models.User facades.Orm().Query().Where("votes > ?", 100).LockForUpdate().Get(&users) ``` -### Avarage +### Aggregates ```go var sum int err := facades.Orm().Query().Model(models.User{}).Sum("id", &sum) var avg float64 -err := facades.Orm().Query().Model(models.User{}).Average("age", &avg) +err := facades.Orm().Query().Model(models.User{}).Avg("age", &avg) var max int err := facades.Orm().Query().Model(models.User{}).Max("age", &max) @@ -997,7 +1001,9 @@ Orm models dispatch several events, allowing you to hook into the following mome The `Retrieved` event will dispatch when an existing model is retrieved from the database. When a new model is saved for the first time, the `Creating` and `Created` events will dispatch. The `Updating` / `Updated` events will dispatch when an existing model is modified and the `Save` method is called. The `Saving` / `Saved` events will dispatch when a model is created or updated - even if the model's attributes have not been changed. Event names ending with `-ing` are dispatched before any changes to the model are persisted, while events ending with `-ed` are dispatched after the changes to the model are persisted. -Note: All events will only be triggered when operating a model. For example, if you want to trigger the `Updating` and `Updated` events when calling the `Update` method, you need to pass the existing model to the `Model` method: `facades.Orm().Query().Model(&user).Update("name", "Goravel")`. +::: warning +All events will only be triggered when operating a model. For example, if you want to trigger the `Updating` and `Updated` events when calling the `Update` method, you need to pass the existing model to the `Model` method: `facades.Orm().Query().Model(&user).Update("name", "Goravel")`. +::: To start listening to model events, define a `DispatchesEvents` method on your model. This property maps various points of the model's lifecycle to your own event classes. @@ -1057,13 +1063,15 @@ func (u *User) DispatchesEvents() map[contractsorm.EventType]func(contractsorm.E } ``` -> Note: Just register the events you need. Model events are not dispatched when doing batch operations through Orm. +::: warning +Just register the events you need. Model events are not dispatched when doing batch operations through Orm. +::: ### Observers #### Defining Observers -If you are listening to many events on a given model, you may use observers to group all of your listeners into a single class. Observer classes have method names that reflect the Eloquent events you wish to listen for. Each of these methods receives the affected model as their only argument. The `make:observer` Artisan command is the easiest way to create a new observer class: +If you are listening to many events on a given model, you may use observers to group all of your listeners into a single class. Observer classes have method names that reflect the model events you wish to listen for. Each of these methods receives the affected model as their only argument. The `make:observer` Artisan command is the easiest way to create a new observer class: ```shell ./artisan make:observer UserObserver @@ -1115,7 +1123,9 @@ func Boot() contractsfoundation.Application { } ``` -> Note: If you set `DispatchesEvents` and `Observer` at the same time, only `DispatchesEvents` will be applied. +::: warning +If you set `DispatchesEvents` and `Observer` at the same time, only `DispatchesEvents` will be applied. +::: #### Parameter in Observer diff --git a/en/orm/relationships.md b/en/orm/relationships.md index 7fc82f5c9..e34779f15 100644 --- a/en/orm/relationships.md +++ b/en/orm/relationships.md @@ -1,15 +1,13 @@ # Relationships -[[toc]] - ## Introduction It's common for database tables to be interconnected. For instance, a blog post may have many comments, or an order may be linked to the user who placed it. `Orm` simplifies managing and dealing with such relationships, and it can handle various common relationships: -- [One To One](#One-To-One) -- [One To Many](#One-To-Many) -- [Many To Many](#Many-To-Many) -- [Polymorphic](#Polymorphic) +- [One To One](#one-to-one) +- [One To Many](#one-to-many) +- [Many To Many](#many-to-many-relationships) +- [Polymorphic](#polymorphic) ## Defining Relationships @@ -130,7 +128,7 @@ To define this relationship, three database tables are needed: `users`, `roles`, Remember, since a role can belong to many users, we cannot simply place a `user_id` column on the `roles` table. This would mean that a role could only belong to a single user. In order to provide support for roles being assigned to multiple users, the `role_user` table is needed. We can summarize the relationship's table structure like so: -``` +```text users id - integer name - string @@ -198,7 +196,7 @@ type Role struct { Table structure: -``` +```text users id - integer name - string @@ -220,7 +218,7 @@ A polymorphic relationship allows the child model to belong to more than one typ A polymorphic relation is similar to a normal relation; however, the child model can belong to more than one type of model using a single association. For example, a blog `Post` and a `User` may share a polymorphic relation to an `Image` model. Using a polymorphic relation allows you to have a single table of unique images that may be associated with posts and users. First, let's examine the table structure: -``` +```text posts id - integer name - string diff --git a/en/prologue/compare-with-laravel.md b/en/prologue/compare-with-laravel.md index d50752d85..946d52eba 100644 --- a/en/prologue/compare-with-laravel.md +++ b/en/prologue/compare-with-laravel.md @@ -1,40 +1,44 @@ +--- +aside: false +--- + # Compare With Laravel -Goravel is heavily inspired by the Laravel framework, aiming to bring similar elegance and simplicity to Go developers. Here are some key comparisons between Goravel and Laravel to help you understand how Goravel aligns with Laravel's features: +Goravel follows the structure of Laravel, so the concepts, the facades and most method names carry over. The table below shows the same task in both frameworks. Where one of them does not have a feature, it says so. -| Feature | Goravel | Laravel | Code Example | -|------------------------|----------------------------------|----------------------------------|----------------------------------| -| [Artisan Console](https://www.goravel.dev/digging-deeper/artisan-console.html) | ✅ | ✅ | ./artisan key:generate
php artisan key:generate | -| [Authentication](https://www.goravel.dev/security/authentication.html) | ✅ | ✅ | facades.Auth(ctx).Login(&user)
Auth::login($user) | -| [Authorization](https://www.goravel.dev/security/authorization.html) | ✅ | ✅ | facades.Gate().Allows("update", user)
Gate::allows('update', $user) | -| [Cache](https://www.goravel.dev/digging-deeper/cache.html) | ✅ | ✅ | facades.Cache().Put("key", "value", time.Minute)
Cache::put('key', 'value', 60) | -| [Carbon](https://www.goravel.dev/digging-deeper/helpers.html) | ✅ | ✅ | carbon.Now().AddDays(1)
Carbon::now()->addDays(1) | -| [Config](https://www.goravel.dev/getting-started/configuration.html) | ✅ | ✅ | facades.Config().GetString("app.name")
config('app.name') | -| [Crypt](https://www.goravel.dev/security/encryption.html) | ✅ | ✅ | facades.Crypt().EncryptString("text")
Crypt::encryptString('text') | -| [DB](https://www.goravel.dev/database/getting-started.html) | ✅ | ✅ | facades.DB().Table("users").Get(&users)
DB::table('users')->get() | -| [Event](https://www.goravel.dev/digging-deeper/event.html) | ✅ | ✅ | facades.Event().Job(&events.Order{}).Dispatch()
Order::dispatch() | -| [Factory](https://www.goravel.dev/orm/factories.html) | ✅ | ✅ | facades.Orm().Factory().Make(&user)
User::factory()->make() | -| [FileStorage](https://www.goravel.dev/digging-deeper/filesystem.html) | ✅ | ✅ | facades.Storage().Put("file.txt", "content")
Storage::put('file.txt', 'content') | -| [Hash](https://www.goravel.dev/security/hashing.html) | ✅ | ✅ | facades.Hash().Make("password")
Hash::make('password') | -| [Http](https://www.goravel.dev/the-basics/routing.html) | ✅ | ✅ | facades.Route().Get("/", controller.Index)
Route::get('/', [Controller::class, 'index']) | -| [Http Client](https://www.goravel.dev/digging-deeper/http-client.html) | ✅ | ✅ | facades.Http().Get("https://api.com")
Http::get('https://api.com') | -| [Localization](https://www.goravel.dev/digging-deeper/localization.html) | ✅ | ✅ | facades.Lang(ctx).Get("messages.welcome")
__('messages.welcome') | -| [Logger](https://www.goravel.dev/the-basics/logging.html) | ✅ | ✅ | facades.Log().Info("message")
Log::info('message') | -| [Mail](https://www.goravel.dev/digging-deeper/mail.html) | ✅ | ✅ | facades.Mail().To("user@example.com").Send()
Mail::to('user@example.com')->send(new Order()) | -| [Mock](https://www.goravel.dev/testing/mock.html) | ✅ | ✅ | | -| [Migrate](https://www.goravel.dev/database/migrations.html) | ✅ | ✅ | ./artisan migrate
php artisan migrate | -| [Orm](https://www.goravel.dev/orm/getting-started.html) | ✅ | ✅ | facades.Orm().Query().Find(&user, 1)
User::find(1) | -| [Package Development](https://www.goravel.dev/digging-deeper/package-development.html) | ✅ | ✅ | | -| [Process](https://www.goravel.dev/digging-deeper/process.html) | ✅ | ✅ | facades.Process().Run("ls", "-la")
`Process::run('ls -la') | -| [Queue](https://www.goravel.dev/digging-deeper/queues.html) | ✅ | ✅ | facades.Queue().Job(&jobs.Process{}).Dispatch()
Process::dispatch() | -| [Rate Limiting](https://www.goravel.dev/digging-deeper/process.html) | ✅ | ✅ | facades.RateLimiter().For("global", ...)
RateLimiter::for('global', ...) | -| [Seeder](https://www.goravel.dev/database/seeding.html) | ✅ | ✅ | facades.Seeder().Call([]seeder.Seeder{&User{}})
$this->call([User::class]) | -| [Session](https://www.goravel.dev/the-basics/session.html) | ✅ | ✅ | ctx.Request().Session().Put("key", "value")
session(['key' => 'value']) | -| [Task Scheduling](https://www.goravel.dev/digging-deeper/task-scheduling.html) | ✅ | ✅ | facades.Schedule().Command("emails:send").Daily()
Schedule::command('emails:send')->daily() | -| [Testing](https://www.goravel.dev/testing/getting-started.html) | ✅ | ✅ | | -| [Validation](https://www.goravel.dev/the-basics/validation.html) | ✅ | ✅ | ctx.Request().ValidateRequest()
$request->validate() | -| [View](https://www.goravel.dev/the-basics/views.html) | ✅ | ✅ | ctx.Response().View().Make("welcome.tmpl")
view('welcome') | -| [Grpc](https://www.goravel.dev/the-basics/grpc.html) | ✅ | 🚧 | | -| Notifications | 🚧 | ✅ | | -| Broadcasting | 🚧 | ✅ | | -| Livewire | 🚧 | ✅ | | +| Feature | Laravel | Goravel | +| --- | --- | --- | +| [Artisan Console](../digging-deeper/artisan-console.md) | `php artisan key:generate` | `./artisan key:generate` | +| [Authentication](../security/authentication.md) | `Auth::login($user)` | `facades.Auth(ctx).Login(&user)` | +| [Authorization](../security/authorization.md) | `Gate::allows('update-post', $post)` | `facades.Gate().Allows("update-post", map[string]any{"post": post})` | +| [Cache](../digging-deeper/cache.md) | `Cache::put('key', 'value', 60)` | `facades.Cache().Put("key", "value", time.Minute)` | +| [Carbon](../digging-deeper/helpers.md) | `Carbon::now()->addDays(1)` | `carbon.Now().AddDays(1)` | +| [Config](../getting-started/configuration.md) | `config('app.name')` | `facades.Config().GetString("app.name")` | +| [Crypt](../security/encryption.md) | `Crypt::encryptString('text')` | `facades.Crypt().EncryptString("text")` | +| [DB](../database/getting-started.md) | `DB::table('users')->get()` | `facades.DB().Table("users").Get(&users)` | +| [Event](../digging-deeper/event.md) | `OrderShipped::dispatch()` | `facades.Event().Job(&events.OrderShipped{}, []event.Arg{}).Dispatch()` | +| [Factory](../orm/factories.md) | `User::factory()->make()` | `facades.Orm().Factory().Make(&user)` | +| [File Storage](../digging-deeper/filesystem.md) | `Storage::put('file.txt', 'content')` | `facades.Storage().Put("file.txt", "content")` | +| [Hash](../security/hashing.md) | `Hash::make('password')` | `facades.Hash().Make("password")` | +| [HTTP Client](../digging-deeper/http-client.md) | `Http::get('https://example.com')` | `facades.Http().Get("https://example.com")` | +| [Localization](../digging-deeper/localization.md) | `__('messages.welcome')` | `facades.Lang(ctx).Get("messages.welcome")` | +| [Logging](../the-basics/logging.md) | `Log::info('message')` | `facades.Log().Info("message")` | +| [Mail](../digging-deeper/mail.md) | `Mail::to('user@example.com')->send(new OrderShipped())` | `facades.Mail().To([]string{"user@example.com"}).Send()` | +| [Migrations](../database/migrations.md) | `php artisan migrate` | `./artisan migrate` | +| [Mock](../testing/mock.md) | `Cache::shouldReceive('get')` | `mock.Factory().Cache()` | +| [ORM](../orm/getting-started.md) | `User::find(1)` | `facades.Orm().Query().Find(&user, 1)` | +| [Package Development](../digging-deeper/package-development.md) | `$this->loadViewsFrom($path, 'courier')` | `facades.View().LoadViewsFrom("/path/to/package/views")` | +| [Process](../digging-deeper/processes.md) | `Process::run('ls -la')` | `facades.Process().Run("ls", "-la")` | +| [Queue](../digging-deeper/queues.md) | `SendEmail::dispatch()` | `facades.Queue().Job(&jobs.SendEmail{}, []queue.Arg{}).Dispatch()` | +| [Rate Limiting](../the-basics/routing.md#rate-limiting) | `RateLimiter::for('global', ...)` | `facades.RateLimiter().For("global", ...)` | +| [Routing](../the-basics/routing.md) | `Route::get('/', [Controller::class, 'index'])` | `facades.Route().Get("/", controller.Index)` | +| [Seeder](../database/seeding.md) | `$this->call([UserSeeder::class])` | `facades.Seeder().Call([]seeder.Seeder{&UserSeeder{}})` | +| [Session](../the-basics/session.md) | `session(['key' => 'value'])` | `ctx.Request().Session().Put("key", "value")` | +| [Task Scheduling](../digging-deeper/task-scheduling.md) | `Schedule::command('emails:send')->daily()` | `facades.Schedule().Command("emails:send").Daily()` | +| [Testing](../testing/getting-started.md) | `$this->get('/tasks')` | `s.Http(s.T()).Get("/tasks")` | +| [Validation](../the-basics/validation.md) | `$request->validate([...])` | `ctx.Request().ValidateRequest(&storePost)` | +| [View](../the-basics/views.md) | `view('welcome')` | `ctx.Response().View().Make("welcome.tmpl")` | +| [Grpc](../the-basics/grpc.md) | Not built in | `facades.Grpc().Connect("user")` | +| Notifications | `$user->notify(new InvoicePaid())` | Not yet | +| Broadcasting | `broadcast(new OrderShipped($order))` | Not yet | +| Livewire | `` | Not yet | diff --git a/en/prologue/contributions.md b/en/prologue/contributions.md index 6ab70afc6..4fa56e5a1 100644 --- a/en/prologue/contributions.md +++ b/en/prologue/contributions.md @@ -1,7 +1,5 @@ # Contribution Guide -[[toc]] - Goravel welcomes rich and diverse contributions from different talents, such as coding, translations, articles, tutorials, etc. After completing two features(5 `Good First Issue` == 1 `Feature`), you will be recognized as a core contributor. By completing one feature every three months, you can maintain this status. Let's make Goravel more efficient together! @@ -18,7 +16,7 @@ Let's make Goravel more efficient together!
- +
@@ -156,7 +154,7 @@ View all available Goravel agent skills: ```shell goravel skill:list -// Show skills with descriptions +# Show skills with descriptions goravel skill:list --detail ``` @@ -186,7 +184,9 @@ Overwrite existing skills with `--force`: goravel skill:install --force goravel-testing ``` -> **Note**: Existing skills are preserved unless `--force` is used. +::: info +Existing skills are preserved unless `--force` is used. +::: ## Code of Conduct diff --git a/en/security/authentication.md b/en/security/authentication.md index 080bfd127..69848206f 100644 --- a/en/security/authentication.md +++ b/en/security/authentication.md @@ -1,7 +1,5 @@ # Authentication -[[toc]] - ## Introduction Authentication is an indispensable feature in Web Applications, the `facades.Auth()` module of Goravel provides support for JWT and Session drivers, and you can customize the driver and user provider. @@ -69,7 +67,9 @@ Through `payload` you can get: 3. `ExpireAt`: Expire time; 4. `IssuedAt`: Issued time; -> If `err` isn't nil other than `ErrorTokenExpired`, the payload should be nil. +::: info +If `err` is anything other than `ErrorTokenExpired`, the payload is nil. +::: You can judge whether the Token is expired by err: @@ -80,7 +80,9 @@ You can judge whether the Token is expired by err: errors.Is(err, auth.ErrorTokenExpired) ``` -> The token can be parsed normally with or without the Bearer prefix. +::: tip +The token can be parsed with or without the `Bearer` prefix. +::: ## Get User @@ -114,7 +116,9 @@ err := facades.Auth(ctx).Guard("admin").Parse(token) err := facades.Auth(ctx).Guard("admin").User(&user) ``` -> When the default guard is not used, the `Guard` method must be called before calling the above methods. +::: warning +When you are not using the default guard, call the `Guard` method before any of the methods above. +::: JWT tokens are bound to the guard that generated them. If you parse a token with a different guard, Goravel returns `auth.ErrorGuardMismatch`: diff --git a/en/security/authorization.md b/en/security/authorization.md index a837477f0..eb151078a 100644 --- a/en/security/authorization.md +++ b/en/security/authorization.md @@ -1,12 +1,10 @@ # Authorization -[[toc]] - ## Introduction -Goravel offers built-in [authentication](./authentication.md) services and an easy-to-use authorization feature to manage user actions on resources. Even if a user is authenticated, they may not have the authority to modify or delete certain Eloquent models or database records. Goravel's authorization feature allows for a systematic way of managing these authorization checks. +Goravel offers built-in [authentication](./authentication.md) services and an easy-to-use authorization feature to manage user actions on resources. Even if a user is authenticated, they may not have the authority to modify or delete certain models or database records. Goravel's authorization feature allows for a systematic way of managing these authorization checks. -There are two ways to authorize actions in Goravel: [gates](#Gates) and [policies](#Policies). Imagine gates and policies as similar to routes and controllers. Gates are based on closures and provide a simple approach to authorization, whereas policies group logic around a specific resource, similar to controllers. This documentation will first cover gates and then delve into policies. +There are two ways to authorize actions in Goravel: [gates](#gates) and [policies](#policies). Imagine gates and policies as similar to routes and controllers. Gates are based on closures and provide a simple approach to authorization, whereas policies group logic around a specific resource, similar to controllers. This documentation will first cover gates and then delve into policies. It's not necessary to exclusively use gates or policies when building an application. Most applications will use a combination of both, which is perfectly acceptable! @@ -123,7 +121,9 @@ facades.Gate().After(func(ctx context.Context, ability string, arguments map[str }) ``` -> Notice: The return result of `After` will be applied only when `facades.Gate().Define` returns nil. +::: warning +The return result of `After` will be applied only when `facades.Gate().Define` returns nil. +::: ### Inject Context diff --git a/en/security/encryption.md b/en/security/encryption.md index 6675e72b4..1d000ba63 100644 --- a/en/security/encryption.md +++ b/en/security/encryption.md @@ -1,7 +1,5 @@ # Encryption -[[toc]] - ## Introduction Goravel's encryption services provide a simple, convenient interface for encrypting and decrypting text via OpenSSL using AES-256 encryption. All of Goravel's encrypted values are signed using a message authentication code (GMAC) so that their underlying value can not be modified or tampered with once encrypted. diff --git a/en/security/hashing.md b/en/security/hashing.md index 2d6a38608..28e0a728e 100644 --- a/en/security/hashing.md +++ b/en/security/hashing.md @@ -1,7 +1,5 @@ # Hashing -[[toc]] - ## Introduction The Goravel `facades.Hash()` provides secure Argon2id and Bcrypt hashing for storing user passwords. If you are using one of the Goravel application starter kits, Argon2id will be used for registration and authentication by default. diff --git a/en/testing/getting-started.md b/en/testing/getting-started.md index b7df31076..5704efd8b 100644 --- a/en/testing/getting-started.md +++ b/en/testing/getting-started.md @@ -1,7 +1,5 @@ # Getting Started -[[toc]] - ## Introduction The testing function of Goravel relies on Golang's official test component, extending unit testing to support integration testing and improve application robustness. @@ -12,7 +10,7 @@ The testing function of Goravel relies on Golang's official test component, exte By default, the `.env` file in the root directory is used to inject configuration information during testing. If you want to use different `.env` files for different packages, you can create a `.env` file in the package directory, and the test will read this file first. -``` +```text - /app - /config - ... @@ -136,7 +134,9 @@ func (s *ExampleTestSuite) TestIndex() { When using `go test`, multiple packages are tested in parallel. As a result, refreshing the database or cache in a test case using a local database or cache can potentially affect other parallel test cases. To address this, Goravel offers Docker-based testing. With Docker, a database or cache image can be created and used independently across different packages. -> Due to the limited support of the Docker image for the windows system, currently, the Docker test can only be run in non-windows environments. +::: warning +Docker images have limited support on Windows, so Docker tests currently run only in non-Windows environments. +::: #### Initiate Docker @@ -292,4 +292,6 @@ func TestMain(m *testing.M) { } ``` -> For more usage of the TestMain method, see [Official Documentation](https://pkg.go.dev/testing#hdr-Main). +::: tip +For more on the `TestMain` method, see the [official documentation](https://pkg.go.dev/testing#hdr-Main). +::: diff --git a/en/testing/http-tests.md b/en/testing/http-tests.md index 74eb8df01..785e47b27 100644 --- a/en/testing/http-tests.md +++ b/en/testing/http-tests.md @@ -1,7 +1,5 @@ # HTTP Tests -[[toc]] - ## Introduction When building web applications, you'll often need to test if your HTTP requests work correctly from start to finish. Goravel's testing tools make this straightforward - you can simulate requests and verify responses without setting up complex test environments. diff --git a/en/testing/mock.md b/en/testing/mock.md index a8c321e76..e72b920c5 100644 --- a/en/testing/mock.md +++ b/en/testing/mock.md @@ -1,7 +1,5 @@ # Mock -[[toc]] - ## Description All functions of Goravel are implemented using `facades`, and all `facades` are made up of interfaces. So with the mock function from [stretchr/testify](http://github.com/stretchr/testify), Goravel can deliver an exceptional testing experience. diff --git a/en/the-basics/controllers.md b/en/the-basics/controllers.md index 5d6a99859..967493ce3 100644 --- a/en/the-basics/controllers.md +++ b/en/the-basics/controllers.md @@ -1,7 +1,5 @@ # Controllers -[[toc]] - ## Introduction Instead of defining all request processing logic in the form of a closure in a separate route, a controller can be used for integration. The controllers are stored in the `app/http/controllers` directory. @@ -61,7 +59,7 @@ func Api() { ## Resource Controllers -If you think of each Eloquent model in your application as a "resource", it is typical to perform the same sets of actions against each resource in your application. For example, imagine your application contains a `Photo` model and a `Movie` model. It is likely that users can create, read, update, or delete these resources. +If you think of each model in your application as a "resource", it is typical to perform the same sets of actions against each resource in your application. For example, imagine your application contains a `Photo` model and a `Movie` model. It is likely that users can create, read, update, or delete these resources. Because of this common use case, Goravel resource routing assigns the typical create, read, update, and delete ("CRUD") routes to a controller with a single line of code. To get started, we can use the `make:controller` Artisan command's `--resource` option to quickly create a controller to handle these actions: diff --git a/en/the-basics/grpc.md b/en/the-basics/grpc.md index 29f05274d..7146604a5 100644 --- a/en/the-basics/grpc.md +++ b/en/the-basics/grpc.md @@ -1,7 +1,5 @@ # Grpc -[[toc]] - ## Introduction Grpc module can be operated by `facades.Grpc()`. Goravel provides an elegant way to build and consume gRPC services, supporting both server and client sides. diff --git a/en/the-basics/logging.md b/en/the-basics/logging.md index 223561484..2b3bbe5f9 100644 --- a/en/the-basics/logging.md +++ b/en/the-basics/logging.md @@ -1,7 +1,5 @@ # Logging -[[toc]] - ## Introduction In order to understand the running status of the application, Goravel provides a powerful log service that can record log messages and system errors to a file or other channels through `facades.Log()`. diff --git a/en/the-basics/middleware.md b/en/the-basics/middleware.md index 5e1b0429a..e1be6ade1 100644 --- a/en/the-basics/middleware.md +++ b/en/the-basics/middleware.md @@ -1,7 +1,5 @@ # Middleware -[[toc]] - ## Introduction Middleware provide a convenient mechanism for inspecting and filtering HTTP requests entering your application. @@ -30,10 +28,10 @@ func (a *Auth) Signature() string { ### Create Middleware By Command -``` +```shell ./artisan make:middleware Auth -// Support nested folders +# Support nested folders ./artisan make:middleware user/Auth ``` @@ -101,7 +99,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **Note**: Middleware exclusion uses the `Signature()` method to identify middlewares. Make sure each middleware returns a unique signature for `WithoutMiddleware` to work correctly. The built-in framework middlewares already provide unique signatures. +::: warning +Middleware exclusion uses the `Signature()` method to identify middlewares. Make sure each middleware returns a unique signature for `WithoutMiddleware` to work correctly. The built-in framework middlewares already provide unique signatures. +::: ## Abort Request diff --git a/en/the-basics/request.md b/en/the-basics/request.md index c638037c1..d82000af9 100644 --- a/en/the-basics/request.md +++ b/en/the-basics/request.md @@ -1,7 +1,5 @@ # HTTP Requests -[[toc]] - ## Introduction The `contracts/http/Request` method of Goravel can interact with the current HTTP request processed by the application, and get the input and files submitted together. @@ -113,7 +111,9 @@ names := ctx.Request().QueryMap("names") queries := ctx.Request().Queries() ``` -> Note: Only one-dimensional Json data can be obtained, otherwise it will return empty. +::: warning +Only one-dimensional Json data can be obtained, otherwise it will return empty. +::: ### Retrieving An Input Value diff --git a/en/the-basics/response.md b/en/the-basics/response.md index 0987f6cb7..ef709bc5d 100644 --- a/en/the-basics/response.md +++ b/en/the-basics/response.md @@ -1,7 +1,5 @@ # HTTP Response -[[toc]] - ## Introduction You can use `ctx.Response()` for HTTP response in the Controller. diff --git a/en/the-basics/routing.md b/en/the-basics/routing.md index 7e8b129ea..bced08918 100644 --- a/en/the-basics/routing.md +++ b/en/the-basics/routing.md @@ -1,7 +1,5 @@ # Routing -[[toc]] - ## Introduction The Goravel routing module can be operated by `facades.Route()`. @@ -46,7 +44,7 @@ Use the `route:list` command to view routes list: | ---------- | ------------------------------------- | | Group | [Group Routing](#group-routing) | | Prefix | [Routing Prefix](#routing-prefix) | -| ServeHTTP | [Testing Routing](#testing-routing) | +| ServeHTTP | [HTTP Tests](../testing/http-tests.md) | | Get | [Basic Routing](#basic-routing) | | Post | [Basic Routing](#basic-routing) | | Put | [Basic Routing](#basic-routing) | @@ -185,7 +183,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **Note**: Middleware exclusion uses the `Signature()` method to identify middlewares. Make sure each middleware returns a unique signature for `WithoutMiddleware` to work correctly. The built-in framework middlewares already provide unique signatures. +::: warning +Middleware exclusion uses the `Signature()` method to identify middlewares. Make sure each middleware returns a unique signature for `WithoutMiddleware` to work correctly. The built-in framework middlewares already provide unique signatures. +::: ## Get All Routes @@ -316,4 +316,6 @@ facades.Route().Middleware(middleware.Throttle("global")).Get("/", func(ctx http Goravel has CORS enabled by default, the configuration can be modified in `config/cors.go`. -> For more information on CORS and CORS headers, please consult the [MDN web documentation on CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers). +::: tip +For more on CORS and its headers, see the [MDN web documentation on CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers). +::: diff --git a/en/the-basics/session.md b/en/the-basics/session.md index 171779884..29362302f 100644 --- a/en/the-basics/session.md +++ b/en/the-basics/session.md @@ -1,7 +1,5 @@ # Session -[[toc]] - ## Introduction Session enables you to store user information across multiple requests, providing a stateful experience within the inherently stateless HTTP protocol. This user information is stored persistently on the server side. Goravel offers a unified interface for interacting with various persistent storage drivers. diff --git a/en/the-basics/validation.md b/en/the-basics/validation.md index 631338165..274a9d51e 100644 --- a/en/the-basics/validation.md +++ b/en/the-basics/validation.md @@ -1,7 +1,5 @@ # Validation -[[toc]] - ## Introduction Goravel provides several different approaches to validate your application's incoming data. It is most common to use the `Validate` method available on all incoming HTTP requests. Goravel includes a wide variety of convenient validation rules. @@ -147,7 +145,9 @@ func (r *PostController) Store(ctx http.Context) { Check more rules in the [Available Validation Rules](#available-validation-rules) section. -> Note that since `form` passed values ​​are of `string` type by default, all fields in request should also be of `string` type, otherwise please use `JSON` to pass values. +::: warning +Since `form` passed values ​​are of `string` type by default, all fields in request should also be of `string` type, otherwise please use `JSON` to pass values. +::: ### Authorizing Form Requests diff --git a/en/the-basics/views.md b/en/the-basics/views.md index 125071131..803b109f8 100644 --- a/en/the-basics/views.md +++ b/en/the-basics/views.md @@ -1,7 +1,5 @@ # Views -[[toc]] - ## Introduction Of course, it's not practical to return entire HTML document strings directly from your routes and controllers. Thankfully, views provide a convenient way to place all of our HTML in separate files. Views separate your controller / application logic from your presentation logic and are stored in the `resources/views` directory. @@ -10,7 +8,7 @@ Of course, it's not practical to return entire HTML document strings directly fr When using the Goravel default template `html/template`, you can create views by adding a file with the `.tmpl` extension in the application `resources/views` directory. -``` +```html // resources/views/welcome.tmpl {{ define "welcome.tmpl" }} @@ -61,7 +59,7 @@ ctx.Response().View().First([]string{"custom/admin.tmpl", "admin.tmpl"}, map[str If you need to determine if a view exists, you can use the `facades.View()` method. It checks `resources/views/` as well as any directories registered with `LoadViewsFrom`: ```go -if facades.View().Exist("welcome.tmpl") { +if facades.View().Exists("welcome.tmpl") { // ... } ``` @@ -79,7 +77,7 @@ func (r *ServiceProvider) Boot(app foundation.Application) { When a view is rendered, the application's `resources/views` directory takes priority — users can override any package view by creating a file with the same name in `resources/views`. If the view is not found there, the registered package view directories are searched in registration order as fallbacks. -The `Exist` method also checks registered package view paths in addition to `resources/views/`. +The `Exists` method also checks registered package view paths in addition to `resources/views/`. ## Passing Data To Views diff --git a/en/upgrade/history.md b/en/upgrade/history.md index 6138c1c5e..8e3bb6721 100644 --- a/en/upgrade/history.md +++ b/en/upgrade/history.md @@ -1,3 +1,7 @@ +--- +aside: false +--- + # History Upgrade - [Upgrading To v1.16 From v1.15](v1.16.md) diff --git a/en/upgrade/v1.1.md b/en/upgrade/v1.1.md index 9cfb5960f..caf6324a1 100644 --- a/en/upgrade/v1.1.md +++ b/en/upgrade/v1.1.md @@ -1,7 +1,5 @@ # Upgrading To v1.1 From v1.0 -[[toc]] - ## High Impact Changes - [Updating Dependencies](#updating-dependencies) diff --git a/en/upgrade/v1.10.md b/en/upgrade/v1.10.md index c5921b34e..704a83fb3 100644 --- a/en/upgrade/v1.10.md +++ b/en/upgrade/v1.10.md @@ -1,7 +1,5 @@ # Upgrading To v1.10 From v1.9 -[[toc]] - ## Exciting New Features 🎉 - [Add facades.Crypt(1.10.0)](#encryption) diff --git a/en/upgrade/v1.11.md b/en/upgrade/v1.11.md index 4fccac394..dd3c331d1 100644 --- a/en/upgrade/v1.11.md +++ b/en/upgrade/v1.11.md @@ -1,7 +1,5 @@ # Upgrading To v1.11 From v1.10 -[[toc]] - ## v1.11.3 ### Bug Fixes 🐛 diff --git a/en/upgrade/v1.17.md b/en/upgrade/v1.17.md index 7849dd470..66b2c0867 100644 --- a/en/upgrade/v1.17.md +++ b/en/upgrade/v1.17.md @@ -19,7 +19,7 @@ - [Add CSRF token middleware](#add-csrf-token-middleware) - [Command supports configure Arguments](#command-supports-configure-arguments) - [make:migration supports create migration via model](#make-migration-supports-create-migration-via-model) -- [Optimize gRPC client connections](#optimize-grpc-connections) +- [Optimize gRPC client connections](#optimize-grpc-client-connections) - [Log supports print json format](#log-supports-print-json-format) - [Http supports multiple clients](#http-supports-multiple-clients) - [Validation supports pass context](#validation-supports-pass-context) @@ -64,30 +64,30 @@ goravel/example project from v1.16 to v1.17 PR can be used as an upgrade referen ```shell go get github.com/goravel/framework@latest -// If using gin +# If using gin go get github.com/goravel/gin@latest -// If using fiber +# If using fiber go get github.com/goravel/fiber@latest -// If using redis +# If using redis go get github.com/goravel/redis@latest -// If using S3 +# If using S3 go get github.com/goravel/s3@latest -// If using Oss +# If using Oss go get github.com/goravel/oss@latest -// If using Cos +# If using Cos go get github.com/goravel/cos@latest -// If using Minio +# If using Minio go get github.com/goravel/minio@latest go mod tidy -// If using installer +# If using installer goravel upgrade ``` diff --git a/en/upgrade/v1.18.md b/en/upgrade/v1.18.md index 46239520b..88337c2ca 100644 --- a/en/upgrade/v1.18.md +++ b/en/upgrade/v1.18.md @@ -349,7 +349,9 @@ Example test diff: +s.Equal("{\"message\":{\"name\":{\"required\":\"The name field is required.\"}}}", content) ``` -> **Note**: Wildcard rules (e.g., `scores.*`, `tags.*`) now consistently appear in error output even when no input is provided. Add assertions for these if your tests check the full error response body. +::: warning +Wildcard rules (e.g., `scores.*`, `tags.*`) now consistently appear in error output even when no input is provided. Add assertions for these if your tests check the full error response body. +::: ### 6c. Rename custom rules that conflict with built-in rules @@ -518,7 +520,7 @@ go run . artisan lang:publish --force After publishing, edit `lang/en/validation.json` to customize default error messages. Create additional language directories (e.g., `lang/zh/validation.json`) for other locales. Custom rule messages now support `:value` and `:optionN` placeholders. -[View Document](../the-basics/validation.md#translation--localization) +[View Document](../the-basics/validation.md#translation-localization) ### Maintenance mode commands @@ -620,7 +622,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **Note**: Middleware exclusion uses the `Signature()` method to identify middlewares. Make sure each middleware returns a unique signature for `WithoutMiddleware` to work correctly. The built-in framework middlewares already provide unique signatures. +::: warning +Middleware exclusion uses the `Signature()` method to identify middlewares. Make sure each middleware returns a unique signature for `WithoutMiddleware` to work correctly. The built-in framework middlewares already provide unique signatures. +::: [View Document](../the-basics/routing.md#without-middleware) @@ -779,7 +783,9 @@ func (r *ServiceProvider) Boot(app foundation.Application) { [View Document](../the-basics/views.md#registering-views-from-packages) -> **Note**: If you want to use this feature in the fiber driver, please check [Fiber driver template configuration replaced with DefaultTemplate](#fiber-driver-template-configuration-replaced-with-defaulttemplate). +::: tip +If you want to use this feature in the fiber driver, please check [Fiber driver template configuration replaced with DefaultTemplate](#fiber-driver-template-configuration-replaced-with-defaulttemplate). +::: ### Package setup supports import aliases @@ -913,7 +919,7 @@ type Middleware interface { This change provides each middleware with a stable identity via the `Signature()` method, enabling `WithoutMiddleware` to reliably exclude specific middleware by signature comparison. All built-in framework middlewares (`Cors`, `Timeout`, `Throttle`, `VerifyCsrfToken`, etc.) have been updated to return structs that implement this interface. -Custom middleware must be updated to implement the new interface. See the [upgrade guide](#_2-migrate-middleware-from-func-to-interface) for migration steps. +Custom middleware must be updated to implement the new interface. See the [upgrade guide](#upgrade-guide) for migration steps. [View Document](../the-basics/middleware.md) diff --git a/en/upgrade/v1.4.md b/en/upgrade/v1.4.md index dc5783c12..728ff02f6 100644 --- a/en/upgrade/v1.4.md +++ b/en/upgrade/v1.4.md @@ -1,7 +1,5 @@ # Upgrading To v1.4 From v1.3 -[[toc]] - ## High Impact Changes - [Optimize Grpc Module](#optimize-grpc-module) diff --git a/en/upgrade/v1.5.md b/en/upgrade/v1.5.md index 397202647..78c62ba7b 100644 --- a/en/upgrade/v1.5.md +++ b/en/upgrade/v1.5.md @@ -1,7 +1,5 @@ # Upgrading To v1.5 From v1.4 -[[toc]] - ## High Impact Changes - [Add File Storage Module](#add-file-storage-module) diff --git a/en/upgrade/v1.6.md b/en/upgrade/v1.6.md index fc8f438aa..eb9925a4b 100644 --- a/en/upgrade/v1.6.md +++ b/en/upgrade/v1.6.md @@ -1,7 +1,5 @@ # Upgrading To v1.6 From v1.5 -[[toc]] - ## High Impact Changes - [Add Authorization Module](#add-authorization-module) diff --git a/en/upgrade/v1.7.md b/en/upgrade/v1.7.md index f63e363f1..d2d05685f 100644 --- a/en/upgrade/v1.7.md +++ b/en/upgrade/v1.7.md @@ -1,7 +1,5 @@ # Upgrading To v1.7 From v1.6 -[[toc]] - ## High Impact Changes - [Add Validation Module(v1.7.0)](#add-validation-module) diff --git a/en/upgrade/v1.8.md b/en/upgrade/v1.8.md index 6dc538871..2cd0b404d 100644 --- a/en/upgrade/v1.8.md +++ b/en/upgrade/v1.8.md @@ -1,7 +1,5 @@ # Upgrading To v1.8 From v1.7 -[[toc]] - ## Exciting New Features 🎉 - [Add model association for Orm(1.8.0)](#add-model-association-for-orm) diff --git a/en/upgrade/v1.9.md b/en/upgrade/v1.9.md index 91160c11e..44597bb75 100644 --- a/en/upgrade/v1.9.md +++ b/en/upgrade/v1.9.md @@ -1,7 +1,5 @@ # Upgrading To v1.9 From v1.8 -[[toc]] - ## Enhancements 🚀 - [Add database read-write separation(1.9.0)](#add-database-read-write-separation) diff --git a/package.json b/package.json index 61192d1a5..72a32b03a 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "MIT", "dependencies": { "@tailwindcss/vite": "^4.1.11", + "motion-v": "^2.4.4", "tailwindcss": "^4.1.11", "vitepress-markdown-timeline": "^1.2.2", "vitepress-plugin-comment-with-giscus": "^1.1.15", @@ -14,12 +15,22 @@ "vue": "^3.5.13" }, "devDependencies": { + "@iconify-json/lucide": "^1.2.133", + "@iconify-json/simple-icons": "^1.2.96", + "@iconify/tailwind4": "^1.2.3", "@nolebase/vitepress-plugin-enhanced-mark": "^2.15.1", "@nolebase/vitepress-plugin-enhanced-readabilities": "^2.15.1", + "@shikijs/transformers": "^3.2.1", "@shikijs/vitepress-twoslash": "^3.2.1", "@types/node": "^22.14.0", + "@vueuse/core": "^12.8.2", + "markdown-it-deflist": "^4.0.0", + "markdown-it-footnote": "^4.0.0", + "markdown-it-sup": "^2.0.0", + "markdown-it-task-lists": "^2.1.1", "prettier": "^3.6.2", "sass": "^1.89.2", + "svg-path-properties": "^2.1.0", "vitepress": "2.0.0-alpha.4" }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a089a4e45..1ca3a3cc1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,11 +5,15 @@ settings: excludeLinksFromLockfile: false importers: + .: dependencies: '@tailwindcss/vite': specifier: ^4.1.11 version: 4.1.11(vite@6.2.5(@types/node@22.14.0)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(sass@1.89.2)) + motion-v: + specifier: ^2.4.4 + version: 2.4.4(@vueuse/core@12.8.2(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) tailwindcss: specifier: ^4.1.11 version: 4.1.11 @@ -26,217 +30,173 @@ importers: specifier: ^3.5.13 version: 3.5.13(typescript@5.8.3) devDependencies: + '@iconify-json/lucide': + specifier: ^1.2.133 + version: 1.2.133 + '@iconify-json/simple-icons': + specifier: ^1.2.96 + version: 1.2.96 + '@iconify/tailwind4': + specifier: ^1.2.3 + version: 1.2.3(tailwindcss@4.1.11) '@nolebase/vitepress-plugin-enhanced-mark': specifier: ^2.15.1 version: 2.15.1(vitepress@2.0.0-alpha.4(@algolia/client-search@5.23.2)(@types/node@22.14.0)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(postcss@8.5.6)(sass@1.89.2)(search-insights@2.17.3)(typescript@5.8.3)) '@nolebase/vitepress-plugin-enhanced-readabilities': specifier: ^2.15.1 version: 2.15.1(typescript@5.8.3)(vitepress@2.0.0-alpha.4(@algolia/client-search@5.23.2)(@types/node@22.14.0)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(postcss@8.5.6)(sass@1.89.2)(search-insights@2.17.3)(typescript@5.8.3)) + '@shikijs/transformers': + specifier: ^3.2.1 + version: 3.2.1 '@shikijs/vitepress-twoslash': specifier: ^3.2.1 version: 3.2.1(typescript@5.8.3) '@types/node': specifier: ^22.14.0 version: 22.14.0 + '@vueuse/core': + specifier: ^12.8.2 + version: 12.8.2(typescript@5.8.3) + markdown-it-deflist: + specifier: ^4.0.0 + version: 4.0.0 + markdown-it-footnote: + specifier: ^4.0.0 + version: 4.0.0 + markdown-it-sup: + specifier: ^2.0.0 + version: 2.0.0 + markdown-it-task-lists: + specifier: ^2.1.1 + version: 2.1.1 prettier: specifier: ^3.6.2 version: 3.6.2 sass: specifier: ^1.89.2 version: 1.89.2 + svg-path-properties: + specifier: ^2.1.0 + version: 2.1.0 vitepress: specifier: 2.0.0-alpha.4 version: 2.0.0-alpha.4(@algolia/client-search@5.23.2)(@types/node@22.14.0)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(postcss@8.5.6)(sass@1.89.2)(search-insights@2.17.3)(typescript@5.8.3) packages: + '@algolia/autocomplete-core@1.17.9': - resolution: - { - integrity: sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ== - } + resolution: {integrity: sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==} '@algolia/autocomplete-plugin-algolia-insights@1.17.9': - resolution: - { - integrity: sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ== - } + resolution: {integrity: sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==} peerDependencies: search-insights: '>= 1 < 3' '@algolia/autocomplete-preset-algolia@1.17.9': - resolution: - { - integrity: sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ== - } + resolution: {integrity: sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==} peerDependencies: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' '@algolia/autocomplete-shared@1.17.9': - resolution: - { - integrity: sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ== - } + resolution: {integrity: sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==} peerDependencies: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' '@algolia/client-abtesting@5.23.2': - resolution: - { - integrity: sha512-EudQGeYEzviwqPH8WoqP5VTQssE/PW6sEdL0zzOyKt2bWnWoUp5Rnm67sCbxYDR44JpUchbkul0PfWrSYsBPjQ== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-EudQGeYEzviwqPH8WoqP5VTQssE/PW6sEdL0zzOyKt2bWnWoUp5Rnm67sCbxYDR44JpUchbkul0PfWrSYsBPjQ==} + engines: {node: '>= 14.0.0'} '@algolia/client-analytics@5.23.2': - resolution: - { - integrity: sha512-zmJrkZqWFu+ft+VRcttZZJhw5ElkhBtOArRzQOu9sRnrSSodBOdPRhAfvu8tG93Hv67wh5qQaTBwLxM58AxuMg== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-zmJrkZqWFu+ft+VRcttZZJhw5ElkhBtOArRzQOu9sRnrSSodBOdPRhAfvu8tG93Hv67wh5qQaTBwLxM58AxuMg==} + engines: {node: '>= 14.0.0'} '@algolia/client-common@5.23.2': - resolution: - { - integrity: sha512-xaE6o4BMdqYBe0iB7JjX6G9/Qeqx6TSs9T4d6VJ0JHPsEyklSwIbKRiomPeYD7vzt2P4t45Io6QBhifOUP+0qg== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-xaE6o4BMdqYBe0iB7JjX6G9/Qeqx6TSs9T4d6VJ0JHPsEyklSwIbKRiomPeYD7vzt2P4t45Io6QBhifOUP+0qg==} + engines: {node: '>= 14.0.0'} '@algolia/client-insights@5.23.2': - resolution: - { - integrity: sha512-F85hpMszbr5ZGt8gFdl7WOugELRF4z3R1nD9n3t7PZ/2alV7IR75UQY8/jMQDwij/lrnVaKbLeIvKKy6K7ncZw== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-F85hpMszbr5ZGt8gFdl7WOugELRF4z3R1nD9n3t7PZ/2alV7IR75UQY8/jMQDwij/lrnVaKbLeIvKKy6K7ncZw==} + engines: {node: '>= 14.0.0'} '@algolia/client-personalization@5.23.2': - resolution: - { - integrity: sha512-TuGaGKiQvQqFNR4c3Vdl+JBe6dkEPmRzVyIdWLrurOPEmFmVCKRxtSnLr0TVFl6de/JfDAXuchvtvLHFxv9P2A== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-TuGaGKiQvQqFNR4c3Vdl+JBe6dkEPmRzVyIdWLrurOPEmFmVCKRxtSnLr0TVFl6de/JfDAXuchvtvLHFxv9P2A==} + engines: {node: '>= 14.0.0'} '@algolia/client-query-suggestions@5.23.2': - resolution: - { - integrity: sha512-fg2tZf7Sf51Icjfrea0dnfbfwlJ7kXMcRsWSJN3DZhEi/Y4mMmK9L0Cq8sby6HDzxy5T8xEWNWC3TMx5FvrJ6w== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-fg2tZf7Sf51Icjfrea0dnfbfwlJ7kXMcRsWSJN3DZhEi/Y4mMmK9L0Cq8sby6HDzxy5T8xEWNWC3TMx5FvrJ6w==} + engines: {node: '>= 14.0.0'} '@algolia/client-search@5.23.2': - resolution: - { - integrity: sha512-XiTjt0qgsJk9OqvDpMwTgUaPAYNSQcMILRfSYiorgiyc71yYM7Lq1vRSVxhB0m51mrViWj4rIR6kSiJRXebqvQ== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-XiTjt0qgsJk9OqvDpMwTgUaPAYNSQcMILRfSYiorgiyc71yYM7Lq1vRSVxhB0m51mrViWj4rIR6kSiJRXebqvQ==} + engines: {node: '>= 14.0.0'} '@algolia/ingestion@1.23.2': - resolution: - { - integrity: sha512-7ClIghvUFZTomBipD8Kor9Z5llcAM3lHUBG3VFOvUsOxOJcaMMONlBXyoFDfI1na+u14lVaGehY2oIEfY1eB0w== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-7ClIghvUFZTomBipD8Kor9Z5llcAM3lHUBG3VFOvUsOxOJcaMMONlBXyoFDfI1na+u14lVaGehY2oIEfY1eB0w==} + engines: {node: '>= 14.0.0'} '@algolia/monitoring@1.23.2': - resolution: - { - integrity: sha512-kF7KKd0iIIlaD70flFS+8+DNxRvIzrG9A22iWG5LDX225Kl6pITroq+qIUweqqyyoqJBYuIXKZGDGtnahEwQxw== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-kF7KKd0iIIlaD70flFS+8+DNxRvIzrG9A22iWG5LDX225Kl6pITroq+qIUweqqyyoqJBYuIXKZGDGtnahEwQxw==} + engines: {node: '>= 14.0.0'} '@algolia/recommend@5.23.2': - resolution: - { - integrity: sha512-nAgS2O5ww8J4fgW6GAiybAdr0uH7MV74srPdx51cPJRpQBEge4WnYBaOWx1/a53qI0xwNtQudnEyBGUzsSYaAw== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-nAgS2O5ww8J4fgW6GAiybAdr0uH7MV74srPdx51cPJRpQBEge4WnYBaOWx1/a53qI0xwNtQudnEyBGUzsSYaAw==} + engines: {node: '>= 14.0.0'} '@algolia/requester-browser-xhr@5.23.2': - resolution: - { - integrity: sha512-yw6IzgQcwr4cZuoQCEoQui9G0rhVRGCyhPhW+gmrXe6oVr4qB50FV6mWGLA170+iqGVjPn/DVuOhExjBzcViTQ== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-yw6IzgQcwr4cZuoQCEoQui9G0rhVRGCyhPhW+gmrXe6oVr4qB50FV6mWGLA170+iqGVjPn/DVuOhExjBzcViTQ==} + engines: {node: '>= 14.0.0'} '@algolia/requester-fetch@5.23.2': - resolution: - { - integrity: sha512-8rmSybTwIqmGx3P0qkOEUkkyeIewglaKq6yUnxnVkBJbd4USfIZsw9cME1YUEHeZI7aOhTQg9QteUHSKXclF5A== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-8rmSybTwIqmGx3P0qkOEUkkyeIewglaKq6yUnxnVkBJbd4USfIZsw9cME1YUEHeZI7aOhTQg9QteUHSKXclF5A==} + engines: {node: '>= 14.0.0'} '@algolia/requester-node-http@5.23.2': - resolution: - { - integrity: sha512-IHpUiW3d3oVE5tCYqQN7X71/EbXI7f8WxU85eWW1UYEWEknqW3csdGctyIW7+qMHFfxeDymI1Wln/gGHHIXLIw== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-IHpUiW3d3oVE5tCYqQN7X71/EbXI7f8WxU85eWW1UYEWEknqW3csdGctyIW7+qMHFfxeDymI1Wln/gGHHIXLIw==} + engines: {node: '>= 14.0.0'} '@ampproject/remapping@2.3.0': - resolution: - { - integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} '@antfu/install-pkg@1.0.0': - resolution: - { - integrity: sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw== - } + resolution: {integrity: sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==} + + '@antfu/install-pkg@2.1.0': + resolution: {integrity: sha512-sdg9NxU3zR4Mnawfbc/x6GB5Wf17WYud5qOuEuxXjaKpYpMkISSJEjItGebXJ2bQ4DIcly4NYH23mtkGJjvKUw==} '@antfu/utils@8.1.1': - resolution: - { - integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ== - } + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} '@babel/helper-string-parser@7.25.9': - resolution: - { - integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} '@babel/helper-validator-identifier@7.25.9': - resolution: - { - integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} '@babel/parser@7.27.0': - resolution: - { - integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} + engines: {node: '>=6.0.0'} hasBin: true '@babel/types@7.27.0': - resolution: - { - integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg== - } - engines: { node: '>=6.9.0' } + resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} + engines: {node: '>=6.9.0'} + + '@cyberalien/svg-utils@1.2.19': + resolution: {integrity: sha512-paDJoDu+LhuH5Ma1q0BDqBpg6d16Xk22cZZrlg/s/J9oB8KgnnpU/snaEETJu2G1pwYcWQINUz6WUqu0Wm9k6A==} '@docsearch/css@3.9.0': - resolution: - { - integrity: sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA== - } + resolution: {integrity: sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==} '@docsearch/js@3.9.0': - resolution: - { - integrity: sha512-4bKHcye6EkLgRE8ze0vcdshmEqxeiJM77M0JXjef7lrYZfSlMunrDOCqyLjiZyo1+c0BhUqA2QpFartIjuHIjw== - } + resolution: {integrity: sha512-4bKHcye6EkLgRE8ze0vcdshmEqxeiJM77M0JXjef7lrYZfSlMunrDOCqyLjiZyo1+c0BhUqA2QpFartIjuHIjw==} '@docsearch/react@3.9.0': - resolution: - { - integrity: sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ== - } + resolution: {integrity: sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ==} peerDependencies: '@types/react': '>= 16.8.0 < 20.0.0' react: '>= 16.8.0 < 20.0.0' @@ -253,811 +213,519 @@ packages: optional: true '@esbuild/aix-ppc64@0.25.2': - resolution: - { - integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] '@esbuild/android-arm64@0.25.2': - resolution: - { - integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} + engines: {node: '>=18'} cpu: [arm64] os: [android] '@esbuild/android-arm@0.25.2': - resolution: - { - integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} + engines: {node: '>=18'} cpu: [arm] os: [android] '@esbuild/android-x64@0.25.2': - resolution: - { - integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} + engines: {node: '>=18'} cpu: [x64] os: [android] '@esbuild/darwin-arm64@0.25.2': - resolution: - { - integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.25.2': - resolution: - { - integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] '@esbuild/freebsd-arm64@0.25.2': - resolution: - { - integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.25.2': - resolution: - { - integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] '@esbuild/linux-arm64@0.25.2': - resolution: - { - integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.25.2': - resolution: - { - integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} + engines: {node: '>=18'} cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.25.2': - resolution: - { - integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.25.2': - resolution: - { - integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.25.2': - resolution: - { - integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.25.2': - resolution: - { - integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.25.2': - resolution: - { - integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.25.2': - resolution: - { - integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.25.2': - resolution: - { - integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} + engines: {node: '>=18'} cpu: [x64] os: [linux] '@esbuild/netbsd-arm64@0.25.2': - resolution: - { - integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} + engines: {node: '>=18'} cpu: [arm64] os: [netbsd] '@esbuild/netbsd-x64@0.25.2': - resolution: - { - integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] '@esbuild/openbsd-arm64@0.25.2': - resolution: - { - integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} + engines: {node: '>=18'} cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.25.2': - resolution: - { - integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] '@esbuild/sunos-x64@0.25.2': - resolution: - { - integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] '@esbuild/win32-arm64@0.25.2': - resolution: - { - integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.25.2': - resolution: - { - integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.25.2': - resolution: - { - integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} + engines: {node: '>=18'} cpu: [x64] os: [win32] '@floating-ui/core@1.6.9': - resolution: - { - integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw== - } + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} '@floating-ui/dom@1.1.1': - resolution: - { - integrity: sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw== - } + resolution: {integrity: sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==} '@floating-ui/utils@0.2.9': - resolution: - { - integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== - } + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} '@giscus/vue@2.4.0': - resolution: - { - integrity: sha512-QOxKHgsMT91myyQagP2v20YYAei1ByZuc3qcaYxbHx4AwOeyVrybDIuRFwG9YDv6OraC86jYnU4Ixd37ddC/0A== - } + resolution: {integrity: sha512-QOxKHgsMT91myyQagP2v20YYAei1ByZuc3qcaYxbHx4AwOeyVrybDIuRFwG9YDv6OraC86jYnU4Ixd37ddC/0A==} peerDependencies: vue: '>=3.2.0' - '@iconify-json/carbon@1.2.8': - resolution: - { - integrity: sha512-6xh4YiFBz6qoSnB3XMe23WvjTJroDFXB17J1MbiT7nATFe+70+em1acRXr8hgP/gYpwFMHFc4IvjA/IPTPnTzg== - } + '@iconify-json/carbon@1.2.27': + resolution: {integrity: sha512-tufpkYXBDlXqczQEZo6QgvfwBd5aIK36gt+pHOI66eK4KOO8oh7CIHDZ4JsiSnOyjqRbApVHzXv4Nz8NO0GPFQ==} '@iconify-json/icon-park-outline@1.2.2': - resolution: - { - integrity: sha512-7VkMWOZTIMNkC9+oAL4I5kVlVC5Pq3nQpruZ4E3cLyKaeV95gaUrEilUkvGW71fgsFYCBWAmOZ3KpM4ux0j0zA== - } + resolution: {integrity: sha512-7VkMWOZTIMNkC9+oAL4I5kVlVC5Pq3nQpruZ4E3cLyKaeV95gaUrEilUkvGW71fgsFYCBWAmOZ3KpM4ux0j0zA==} '@iconify-json/logos@1.2.4': - resolution: - { - integrity: sha512-XC4If5D/hbaZvUkTV8iaZuGlQCyG6CNOlaAaJaGa13V5QMYwYjgtKk3vPP8wz3wtTVNVEVk3LRx1fOJz+YnSMw== - } + resolution: {integrity: sha512-XC4If5D/hbaZvUkTV8iaZuGlQCyG6CNOlaAaJaGa13V5QMYwYjgtKk3vPP8wz3wtTVNVEVk3LRx1fOJz+YnSMw==} + + '@iconify-json/lucide@1.2.133': + resolution: {integrity: sha512-zBlWJFHgLI53EMoTXyvIpjZslL5+/voWXNnhxDK6M+VoveFIYxYDgLGJr4lnAkQOscKmRoUfdxqhMZI6VYF32g==} '@iconify-json/octicon@1.2.5': - resolution: - { - integrity: sha512-FVFjjmAC1R1Feis9k+COO3WvL3yumk0E7RxNvOEGT9K8CDp05k3Qg2lLlynBzZrSfuT1DhReJUUXFAj60ZHkpA== - } + resolution: {integrity: sha512-FVFjjmAC1R1Feis9k+COO3WvL3yumk0E7RxNvOEGT9K8CDp05k3Qg2lLlynBzZrSfuT1DhReJUUXFAj60ZHkpA==} - '@iconify-json/simple-icons@1.2.30': - resolution: - { - integrity: sha512-KiVViMvnohpS5Q9WMP+4ksOhF3Dnq73Ba9hxBhUIIhp1r6RJ6edMZ8QGKZcFZp/B0/PZC4jAIhXcKKq73WZckQ== - } + '@iconify-json/simple-icons@1.2.96': + resolution: {integrity: sha512-/FmCYo/H5rIywTLV/P6OYsr0rg/31vuc8jYq0QnkOZl6m7PWIs+h5oAnSTT2cqRhOsMaKqbXcdkka6tnZ1WiUA==} '@iconify-json/vscode-icons@1.2.18': - resolution: - { - integrity: sha512-TFkzbQb6X87xf4OyPQc9TFYEz0Qlw6tfIqtOPS81U1cbfQgYSuEGoAdvqiO9wEVms6bzVOyDfwYG/IysA7Wl9A== - } + resolution: {integrity: sha512-TFkzbQb6X87xf4OyPQc9TFYEz0Qlw6tfIqtOPS81U1cbfQgYSuEGoAdvqiO9wEVms6bzVOyDfwYG/IysA7Wl9A==} + + '@iconify/tailwind4@1.2.3': + resolution: {integrity: sha512-z8SKiMHRASJKF/IY//87MF88lcB7ulxh8vlhQXXLWsBkNtOh6ese9R41MyGpQeqXdRvQVt+/fX2glQtHFjQ+MA==} + peerDependencies: + tailwindcss: '>= 4.0.0' + + '@iconify/tools@5.0.14': + resolution: {integrity: sha512-wJ4ZE3/HZh2iBqLwG+8FOMHe7CMJAJqwSXZSpPwMdj1gZM3Z4t2hbQMVw4Vm45oQ985qn0g89PUIcDEdKTheBA==} '@iconify/types@2.0.0': - resolution: - { - integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg== - } + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} '@iconify/utils@2.3.0': - resolution: - { - integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA== - } + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + + '@iconify/utils@3.1.7': + resolution: {integrity: sha512-JZHlwdID+dy+lTgbYC8NEC4zeugqeYsc6jewvzb4c58kHauJn+X7rNwQjxz5p2qSjqaEeQoLkCIQ9v/H4PK0/w==} '@isaacs/fs-minipass@4.0.1': - resolution: - { - integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== - } - engines: { node: '>=18.0.0' } + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} '@jridgewell/gen-mapping@0.3.12': - resolution: - { - integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== - } + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} '@jridgewell/resolve-uri@3.1.2': - resolution: - { - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - } - engines: { node: '>=6.0.0' } + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} '@jridgewell/sourcemap-codec@1.5.0': - resolution: - { - integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - } + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} '@jridgewell/trace-mapping@0.3.29': - resolution: - { - integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== - } + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} '@lit-labs/ssr-dom-shim@1.3.0': - resolution: - { - integrity: sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ== - } + resolution: {integrity: sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ==} '@lit/reactive-element@2.0.4': - resolution: - { - integrity: sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ== - } + resolution: {integrity: sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==} '@nolebase/ui@2.15.1': - resolution: - { - integrity: sha512-IiKX2HQ8Ey7M3Nd27GZdoTrURTIq6DtkGOXc6mxrZV2REbMTYqYlby1Xwx6sfyOcSsDD7Ge62PlZze/yVIZsWg== - } + resolution: {integrity: sha512-IiKX2HQ8Ey7M3Nd27GZdoTrURTIq6DtkGOXc6mxrZV2REbMTYqYlby1Xwx6sfyOcSsDD7Ge62PlZze/yVIZsWg==} peerDependencies: vitepress: ^1.5.0 || ^2.0.0-alpha.1 '@nolebase/vitepress-plugin-enhanced-mark@2.15.1': - resolution: - { - integrity: sha512-IJYVbgzpIIXlYfT8RGZw2s6C43gddpL4GMKzE+a3K1UAxjBQ+OpH6lfWr+qn3RSxQxmyTXirTRcnj20ZZau3lg== - } + resolution: {integrity: sha512-IJYVbgzpIIXlYfT8RGZw2s6C43gddpL4GMKzE+a3K1UAxjBQ+OpH6lfWr+qn3RSxQxmyTXirTRcnj20ZZau3lg==} peerDependencies: vitepress: ^1.5.0 || ^2.0.0-alpha.1 '@nolebase/vitepress-plugin-enhanced-readabilities@2.15.1': - resolution: - { - integrity: sha512-M02A54mM8nQch8jyuzHOYJGvn/fr5Ihz2a82TnzZNbVDrrKXEKAOf9LmcidLUVPwG/Z0hE5dQA8y0EEZHgd5TA== - } + resolution: {integrity: sha512-M02A54mM8nQch8jyuzHOYJGvn/fr5Ihz2a82TnzZNbVDrrKXEKAOf9LmcidLUVPwG/Z0hE5dQA8y0EEZHgd5TA==} peerDependencies: vitepress: ^1.5.0 || ^2.0.0-alpha.1 '@parcel/watcher-android-arm64@2.5.1': - resolution: - { - integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] '@parcel/watcher-darwin-arm64@2.5.1': - resolution: - { - integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] '@parcel/watcher-darwin-x64@2.5.1': - resolution: - { - integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] '@parcel/watcher-freebsd-x64@2.5.1': - resolution: - { - integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: - { - integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: - { - integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: - { - integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: - { - integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: - { - integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: - { - integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] '@parcel/watcher-win32-arm64@2.5.1': - resolution: - { - integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] '@parcel/watcher-win32-ia32@2.5.1': - resolution: - { - integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] '@parcel/watcher-win32-x64@2.5.1': - resolution: - { - integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] '@parcel/watcher@2.5.1': - resolution: - { - integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== - } - engines: { node: '>= 10.0.0' } + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} '@rollup/rollup-android-arm-eabi@4.39.0': - resolution: - { - integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA== - } + resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==} cpu: [arm] os: [android] '@rollup/rollup-android-arm64@4.39.0': - resolution: - { - integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ== - } + resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} cpu: [arm64] os: [android] '@rollup/rollup-darwin-arm64@4.39.0': - resolution: - { - integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q== - } + resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} cpu: [arm64] os: [darwin] '@rollup/rollup-darwin-x64@4.39.0': - resolution: - { - integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ== - } + resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} cpu: [x64] os: [darwin] '@rollup/rollup-freebsd-arm64@4.39.0': - resolution: - { - integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ== - } + resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} cpu: [arm64] os: [freebsd] '@rollup/rollup-freebsd-x64@4.39.0': - resolution: - { - integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q== - } + resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} cpu: [x64] os: [freebsd] '@rollup/rollup-linux-arm-gnueabihf@4.39.0': - resolution: - { - integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g== - } + resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} cpu: [arm] os: [linux] '@rollup/rollup-linux-arm-musleabihf@4.39.0': - resolution: - { - integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw== - } + resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} cpu: [arm] os: [linux] '@rollup/rollup-linux-arm64-gnu@4.39.0': - resolution: - { - integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ== - } + resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} cpu: [arm64] os: [linux] '@rollup/rollup-linux-arm64-musl@4.39.0': - resolution: - { - integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA== - } + resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} cpu: [arm64] os: [linux] '@rollup/rollup-linux-loongarch64-gnu@4.39.0': - resolution: - { - integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw== - } + resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} cpu: [loong64] os: [linux] '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': - resolution: - { - integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ== - } + resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} cpu: [ppc64] os: [linux] '@rollup/rollup-linux-riscv64-gnu@4.39.0': - resolution: - { - integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ== - } + resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} cpu: [riscv64] os: [linux] '@rollup/rollup-linux-riscv64-musl@4.39.0': - resolution: - { - integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA== - } + resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} cpu: [riscv64] os: [linux] '@rollup/rollup-linux-s390x-gnu@4.39.0': - resolution: - { - integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA== - } + resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} cpu: [s390x] os: [linux] '@rollup/rollup-linux-x64-gnu@4.39.0': - resolution: - { - integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA== - } + resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} cpu: [x64] os: [linux] '@rollup/rollup-linux-x64-musl@4.39.0': - resolution: - { - integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg== - } + resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} cpu: [x64] os: [linux] '@rollup/rollup-win32-arm64-msvc@4.39.0': - resolution: - { - integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ== - } + resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} cpu: [arm64] os: [win32] '@rollup/rollup-win32-ia32-msvc@4.39.0': - resolution: - { - integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ== - } + resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} cpu: [ia32] os: [win32] '@rollup/rollup-win32-x64-msvc@4.39.0': - resolution: - { - integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug== - } + resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} cpu: [x64] os: [win32] '@shikijs/core@3.2.1': - resolution: - { - integrity: sha512-FhsdxMWYu/C11sFisEp7FMGBtX/OSSbnXZDMBhGuUDBNTdsoZlMSgQv5f90rwvzWAdWIW6VobD+G3IrazxA6dQ== - } + resolution: {integrity: sha512-FhsdxMWYu/C11sFisEp7FMGBtX/OSSbnXZDMBhGuUDBNTdsoZlMSgQv5f90rwvzWAdWIW6VobD+G3IrazxA6dQ==} '@shikijs/engine-javascript@3.2.1': - resolution: - { - integrity: sha512-eMdcUzN3FMQYxOmRf2rmU8frikzoSHbQDFH2hIuXsrMO+IBOCI9BeeRkCiBkcLDHeRKbOCtYMJK3D6U32ooU9Q== - } + resolution: {integrity: sha512-eMdcUzN3FMQYxOmRf2rmU8frikzoSHbQDFH2hIuXsrMO+IBOCI9BeeRkCiBkcLDHeRKbOCtYMJK3D6U32ooU9Q==} '@shikijs/engine-oniguruma@3.2.1': - resolution: - { - integrity: sha512-wZZAkayEn6qu2+YjenEoFqj0OyQI64EWsNR6/71d1EkG4sxEOFooowKivsWPpaWNBu3sxAG+zPz5kzBL/SsreQ== - } + resolution: {integrity: sha512-wZZAkayEn6qu2+YjenEoFqj0OyQI64EWsNR6/71d1EkG4sxEOFooowKivsWPpaWNBu3sxAG+zPz5kzBL/SsreQ==} '@shikijs/langs@3.2.1': - resolution: - { - integrity: sha512-If0iDHYRSGbihiA8+7uRsgb1er1Yj11pwpX1c6HLYnizDsKAw5iaT3JXj5ZpaimXSWky/IhxTm7C6nkiYVym+A== - } + resolution: {integrity: sha512-If0iDHYRSGbihiA8+7uRsgb1er1Yj11pwpX1c6HLYnizDsKAw5iaT3JXj5ZpaimXSWky/IhxTm7C6nkiYVym+A==} '@shikijs/themes@3.2.1': - resolution: - { - integrity: sha512-k5DKJUT8IldBvAm8WcrDT5+7GA7se6lLksR+2E3SvyqGTyFMzU2F9Gb7rmD+t+Pga1MKrYFxDIeyWjMZWM6uBQ== - } + resolution: {integrity: sha512-k5DKJUT8IldBvAm8WcrDT5+7GA7se6lLksR+2E3SvyqGTyFMzU2F9Gb7rmD+t+Pga1MKrYFxDIeyWjMZWM6uBQ==} '@shikijs/transformers@3.2.1': - resolution: - { - integrity: sha512-oIT40p8LOPV/6XLnUrVPeRtJtbu0Mpl+BjGFuMXw870eX9zTSQlidg7CsksFDVyUiSAOC/CH1RQm+ldZp0/6eQ== - } + resolution: {integrity: sha512-oIT40p8LOPV/6XLnUrVPeRtJtbu0Mpl+BjGFuMXw870eX9zTSQlidg7CsksFDVyUiSAOC/CH1RQm+ldZp0/6eQ==} '@shikijs/twoslash@3.2.1': - resolution: - { - integrity: sha512-2ZiL9xXY8JRXHG5BdJXE9KoIeSsyH9/yK+YTN90/SUIKkq7Nf5dWqXp5wJ6+4SL0FQO8mq2HUutwqU+gamOgOA== - } + resolution: {integrity: sha512-2ZiL9xXY8JRXHG5BdJXE9KoIeSsyH9/yK+YTN90/SUIKkq7Nf5dWqXp5wJ6+4SL0FQO8mq2HUutwqU+gamOgOA==} peerDependencies: typescript: '>=5.5.0' '@shikijs/types@3.2.1': - resolution: - { - integrity: sha512-/NTWAk4KE2M8uac0RhOsIhYQf4pdU0OywQuYDGIGAJ6Mjunxl2cGiuLkvu4HLCMn+OTTLRWkjZITp+aYJv60yA== - } + resolution: {integrity: sha512-/NTWAk4KE2M8uac0RhOsIhYQf4pdU0OywQuYDGIGAJ6Mjunxl2cGiuLkvu4HLCMn+OTTLRWkjZITp+aYJv60yA==} '@shikijs/vitepress-twoslash@3.2.1': - resolution: - { - integrity: sha512-lQNmw3v9gBFYdxfCW5upcDwfQu8BTJz4D4VPN72XElBA6gW82PKNmzZDoHhVcEmgm/cRQpPjpiY6CYChtv/AEw== - } + resolution: {integrity: sha512-lQNmw3v9gBFYdxfCW5upcDwfQu8BTJz4D4VPN72XElBA6gW82PKNmzZDoHhVcEmgm/cRQpPjpiY6CYChtv/AEw==} '@shikijs/vscode-textmate@10.0.2': - resolution: - { - integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg== - } + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} '@tailwindcss/node@4.1.11': - resolution: - { - integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q== - } + resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} '@tailwindcss/oxide-android-arm64@4.1.11': - resolution: - { - integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} + engines: {node: '>= 10'} cpu: [arm64] os: [android] '@tailwindcss/oxide-darwin-arm64@4.1.11': - resolution: - { - integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [darwin] '@tailwindcss/oxide-darwin-x64@4.1.11': - resolution: - { - integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} + engines: {node: '>= 10'} cpu: [x64] os: [darwin] '@tailwindcss/oxide-freebsd-x64@4.1.11': - resolution: - { - integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} + engines: {node: '>= 10'} cpu: [x64] os: [freebsd] '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': - resolution: - { - integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} + engines: {node: '>= 10'} cpu: [arm] os: [linux] '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': - resolution: - { - integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] '@tailwindcss/oxide-linux-arm64-musl@4.1.11': - resolution: - { - integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] '@tailwindcss/oxide-linux-x64-gnu@4.1.11': - resolution: - { - integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] '@tailwindcss/oxide-linux-x64-musl@4.1.11': - resolution: - { - integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] '@tailwindcss/oxide-wasm32-wasi@4.1.11': - resolution: - { - integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g== - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} + engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: - '@napi-rs/wasm-runtime' @@ -1068,181 +736,103 @@ packages: - tslib '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': - resolution: - { - integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] '@tailwindcss/oxide-win32-x64-msvc@4.1.11': - resolution: - { - integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] '@tailwindcss/oxide@4.1.11': - resolution: - { - integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg== - } - engines: { node: '>= 10' } + resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} + engines: {node: '>= 10'} '@tailwindcss/vite@4.1.11': - resolution: - { - integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw== - } + resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 '@types/debug@4.1.12': - resolution: - { - integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== - } + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} '@types/estree@1.0.7': - resolution: - { - integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== - } + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} '@types/hast@3.0.4': - resolution: - { - integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== - } + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} '@types/mdast@4.0.4': - resolution: - { - integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== - } + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} '@types/ms@2.1.0': - resolution: - { - integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== - } + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} '@types/node@22.14.0': - resolution: - { - integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA== - } + resolution: {integrity: sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==} '@types/trusted-types@2.0.7': - resolution: - { - integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== - } + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} '@types/unist@3.0.3': - resolution: - { - integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== - } + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} '@types/web-bluetooth@0.0.21': - resolution: - { - integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA== - } + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} '@typescript/vfs@1.6.1': - resolution: - { - integrity: sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA== - } + resolution: {integrity: sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==} peerDependencies: typescript: '*' '@ungap/structured-clone@1.3.0': - resolution: - { - integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== - } + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} '@vitejs/plugin-vue@5.2.3': - resolution: - { - integrity: sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg== - } - engines: { node: ^18.0.0 || >=20.0.0 } + resolution: {integrity: sha512-IYSLEQj4LgZZuoVpdSUCw3dIynTWQgPlaRP6iAvMle4My0HdYwr5g5wQAfwOeHQBmYwEkqF70nRpSilr6PoUDg==} + engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 '@volar/language-core@2.4.12': - resolution: - { - integrity: sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA== - } + resolution: {integrity: sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA==} '@volar/source-map@2.4.12': - resolution: - { - integrity: sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw== - } + resolution: {integrity: sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw==} '@vue/compiler-core@3.5.13': - resolution: - { - integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q== - } + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} '@vue/compiler-dom@3.5.13': - resolution: - { - integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA== - } + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} '@vue/compiler-sfc@3.5.13': - resolution: - { - integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ== - } + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} '@vue/compiler-ssr@3.5.13': - resolution: - { - integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA== - } + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} '@vue/compiler-vue2@2.7.16': - resolution: - { - integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A== - } + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} '@vue/devtools-api@7.7.2': - resolution: - { - integrity: sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA== - } + resolution: {integrity: sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==} '@vue/devtools-kit@7.7.2': - resolution: - { - integrity: sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ== - } + resolution: {integrity: sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==} '@vue/devtools-shared@7.7.2': - resolution: - { - integrity: sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA== - } + resolution: {integrity: sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==} '@vue/language-core@2.2.4': - resolution: - { - integrity: sha512-eGGdw7eWUwdIn9Fy/irJ7uavCGfgemuHQABgJ/hU1UgZFnbTg9VWeXvHQdhY+2SPQZWJqWXvRWIg67t4iWEa+Q== - } + resolution: {integrity: sha512-eGGdw7eWUwdIn9Fy/irJ7uavCGfgemuHQABgJ/hU1UgZFnbTg9VWeXvHQdhY+2SPQZWJqWXvRWIg67t4iWEa+Q==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -1250,48 +840,27 @@ packages: optional: true '@vue/reactivity@3.5.13': - resolution: - { - integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg== - } + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} '@vue/runtime-core@3.5.13': - resolution: - { - integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw== - } + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} '@vue/runtime-dom@3.5.13': - resolution: - { - integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog== - } + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} '@vue/server-renderer@3.5.13': - resolution: - { - integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA== - } + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} peerDependencies: vue: 3.5.13 '@vue/shared@3.5.13': - resolution: - { - integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ== - } + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} '@vueuse/core@12.8.2': - resolution: - { - integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ== - } + resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} '@vueuse/integrations@12.8.2': - resolution: - { - integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g== - } + resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==} peerDependencies: async-validator: ^4 axios: ^1 @@ -1332,156 +901,110 @@ packages: optional: true '@vueuse/metadata@12.8.2': - resolution: - { - integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A== - } + resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} '@vueuse/shared@12.8.2': - resolution: - { - integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w== - } + resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} acorn@8.14.1: - resolution: - { - integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== - } - engines: { node: '>=0.4.0' } + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} hasBin: true algoliasearch@5.23.2: - resolution: - { - integrity: sha512-IhKP22Czzg8Y9HaF6aIb5aAHK2HBj4VAzLLnKEPUnxqDwxpryH9sXbm0NkeY7Cby9GlF81wF+AG/VulKDFBphg== - } - engines: { node: '>= 14.0.0' } + resolution: {integrity: sha512-IhKP22Czzg8Y9HaF6aIb5aAHK2HBj4VAzLLnKEPUnxqDwxpryH9sXbm0NkeY7Cby9GlF81wF+AG/VulKDFBphg==} + engines: {node: '>= 14.0.0'} alien-signals@1.0.13: - resolution: - { - integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg== - } + resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - } + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} birpc@0.2.19: - resolution: - { - integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ== - } + resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} brace-expansion@2.0.1: - resolution: - { - integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - } + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} braces@3.0.3: - resolution: - { - integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} ccount@2.0.1: - resolution: - { - integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== - } + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} character-entities-html4@2.1.0: - resolution: - { - integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== - } + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} character-entities-legacy@3.0.0: - resolution: - { - integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== - } + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} character-entities@2.0.2: - resolution: - { - integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== - } + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} chokidar@4.0.3: - resolution: - { - integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== - } - engines: { node: '>= 14.16.0' } + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} chownr@3.0.0: - resolution: - { - integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} comma-separated-tokens@2.0.3: - resolution: - { - integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== - } + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} confbox@0.1.8: - resolution: - { - integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== - } + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} confbox@0.2.2: - resolution: - { - integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== - } + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} copy-anything@2.0.6: - resolution: - { - integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw== - } + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} copy-anything@3.0.5: - resolution: - { - integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w== - } - engines: { node: '>=12.13' } + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + engines: {node: '>= 6'} + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} csstype@3.1.3: - resolution: - { - integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - } + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} dayjs@1.11.13: - resolution: - { - integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== - } + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} de-indent@1.0.2: - resolution: - { - integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== - } + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} debug@4.4.0: - resolution: - { - integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - } - engines: { node: '>=6.0' } + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: @@ -1489,105 +1012,76 @@ packages: optional: true decode-named-character-reference@1.1.0: - resolution: - { - integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w== - } + resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} dequal@2.0.3: - resolution: - { - integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} detect-libc@1.0.3: - resolution: - { - integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== - } - engines: { node: '>=0.10' } + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} hasBin: true detect-libc@2.0.4: - resolution: - { - integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} devlop@1.1.0: - resolution: - { - integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== - } + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} emoji-regex-xs@1.0.0: - resolution: - { - integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg== - } + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} enhanced-resolve@5.18.2: - resolution: - { - integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ== - } - engines: { node: '>=10.13.0' } + resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} + engines: {node: '>=10.13.0'} entities@4.5.0: - resolution: - { - integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - } - engines: { node: '>=0.12' } + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} errno@0.1.8: - resolution: - { - integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - } + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true esbuild@0.25.2: - resolution: - { - integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} + engines: {node: '>=18'} hasBin: true escape-string-regexp@5.0.0: - resolution: - { - integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== - } - engines: { node: '>=12' } + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} estree-walker@2.0.2: - resolution: - { - integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - } + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} exsolve@1.0.4: - resolution: - { - integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw== - } + resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} + + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} fill-range@7.1.1: - resolution: - { - integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - } - engines: { node: '>=8' } + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} floating-vue@5.2.2: - resolution: - { - integrity: sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg== - } + resolution: {integrity: sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg==} peerDependencies: '@nuxt/kit': ^3.2.0 vue: ^3.2.0 @@ -1596,965 +1090,601 @@ packages: optional: true focus-trap@7.6.4: - resolution: - { - integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw== - } + resolution: {integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==} + + framer-motion@13.4.0: + resolution: {integrity: sha512-HCpqKM9BTu6UYKtj0u6J1QNxojnnirNcghcSDZ+SkpiL3myxvtsgXPS3ZGEELC2eSma7YiA937rAEXtRyydSXQ==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true fsevents@2.3.3: - resolution: - { - integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] giscus@1.6.0: - resolution: - { - integrity: sha512-Zrsi8r4t1LVW950keaWcsURuZUQwUaMKjvJgTCY125vkW6OiEBkatE7ScJDbpqKHdZwb///7FVC21SE3iFK3PQ== - } + resolution: {integrity: sha512-Zrsi8r4t1LVW950keaWcsURuZUQwUaMKjvJgTCY125vkW6OiEBkatE7ScJDbpqKHdZwb///7FVC21SE3iFK3PQ==} globals@15.15.0: - resolution: - { - integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} graceful-fs@4.2.11: - resolution: - { - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - } + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} hast-util-to-html@9.0.5: - resolution: - { - integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw== - } + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} hast-util-whitespace@3.0.0: - resolution: - { - integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== - } + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} he@1.2.0: - resolution: - { - integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - } + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hey-listen@1.0.8: + resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + hookable@5.5.3: - resolution: - { - integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ== - } + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} html-void-elements@3.0.0: - resolution: - { - integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg== - } + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} iconv-lite@0.6.3: - resolution: - { - integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} image-size@0.5.5: - resolution: - { - integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} hasBin: true immutable@5.1.3: - resolution: - { - integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg== - } + resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} is-glob@4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} is-number@7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - } - engines: { node: '>=0.12.0' } + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} is-what@3.14.1: - resolution: - { - integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA== - } + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} is-what@4.1.16: - resolution: - { - integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A== - } - engines: { node: '>=12.13' } + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} jiti@2.4.2: - resolution: - { - integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== - } + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true kolorist@1.8.0: - resolution: - { - integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== - } + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} less@4.3.0: - resolution: - { - integrity: sha512-X9RyH9fvemArzfdP8Pi3irr7lor2Ok4rOttDXBhlwDg+wKQsXOXgHWduAJE1EsF7JJx0w0bcO6BC6tCKKYnXKA== - } - engines: { node: '>=14' } + resolution: {integrity: sha512-X9RyH9fvemArzfdP8Pi3irr7lor2Ok4rOttDXBhlwDg+wKQsXOXgHWduAJE1EsF7JJx0w0bcO6BC6tCKKYnXKA==} + engines: {node: '>=14'} hasBin: true lightningcss-darwin-arm64@1.30.1: - resolution: - { - integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] lightningcss-darwin-x64@1.30.1: - resolution: - { - integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] lightningcss-freebsd-x64@1.30.1: - resolution: - { - integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] lightningcss-linux-arm-gnueabihf@1.30.1: - resolution: - { - integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] lightningcss-linux-arm64-gnu@1.30.1: - resolution: - { - integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] lightningcss-linux-arm64-musl@1.30.1: - resolution: - { - integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] lightningcss-linux-x64-gnu@1.30.1: - resolution: - { - integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] lightningcss-linux-x64-musl@1.30.1: - resolution: - { - integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] lightningcss-win32-arm64-msvc@1.30.1: - resolution: - { - integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] lightningcss-win32-x64-msvc@1.30.1: - resolution: - { - integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] lightningcss@1.30.1: - resolution: - { - integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== - } - engines: { node: '>= 12.0.0' } + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} lit-element@4.1.1: - resolution: - { - integrity: sha512-HO9Tkkh34QkTeUmEdNYhMT8hzLid7YlMlATSi1q4q17HE5d9mrrEHJ/o8O2D0cMi182zK1F3v7x0PWFjrhXFew== - } + resolution: {integrity: sha512-HO9Tkkh34QkTeUmEdNYhMT8hzLid7YlMlATSi1q4q17HE5d9mrrEHJ/o8O2D0cMi182zK1F3v7x0PWFjrhXFew==} lit-html@3.2.1: - resolution: - { - integrity: sha512-qI/3lziaPMSKsrwlxH/xMgikhQ0EGOX2ICU73Bi/YHFvz2j/yMCIrw4+puF2IpQ4+upd3EWbvnHM9+PnJn48YA== - } + resolution: {integrity: sha512-qI/3lziaPMSKsrwlxH/xMgikhQ0EGOX2ICU73Bi/YHFvz2j/yMCIrw4+puF2IpQ4+upd3EWbvnHM9+PnJn48YA==} lit@3.2.1: - resolution: - { - integrity: sha512-1BBa1E/z0O9ye5fZprPtdqnc0BFzxIxTTOO/tQFmyC/hj1O3jL4TfmLBw0WEwjAokdLwpclkvGgDJwTIh0/22w== - } + resolution: {integrity: sha512-1BBa1E/z0O9ye5fZprPtdqnc0BFzxIxTTOO/tQFmyC/hj1O3jL4TfmLBw0WEwjAokdLwpclkvGgDJwTIh0/22w==} local-pkg@1.1.1: - resolution: - { - integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg== - } - engines: { node: '>=14' } + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} longest-streak@3.1.0: - resolution: - { - integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== - } + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} magic-string@0.30.17: - resolution: - { - integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== - } + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} make-dir@2.1.0: - resolution: - { - integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} mark.js@8.11.1: - resolution: - { - integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ== - } + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + + markdown-it-deflist@4.0.0: + resolution: {integrity: sha512-06186ZWDwNLg638THD70MxBeFrDMF0+nL7IWU/qwCGHGOcUIm4MTYXbfjpv0ooWnVjkSnAjW8msKaOQmNRfY6Q==} + + markdown-it-footnote@4.0.0: + resolution: {integrity: sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==} + + markdown-it-sup@2.0.0: + resolution: {integrity: sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA==} + + markdown-it-task-lists@2.1.1: + resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==} markdown-table@3.0.4: - resolution: - { - integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw== - } + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} mdast-util-find-and-replace@3.0.2: - resolution: - { - integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg== - } + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} mdast-util-from-markdown@2.0.2: - resolution: - { - integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA== - } + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} mdast-util-gfm-autolink-literal@2.0.1: - resolution: - { - integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== - } + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} mdast-util-gfm-footnote@2.1.0: - resolution: - { - integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ== - } + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} mdast-util-gfm-strikethrough@2.0.0: - resolution: - { - integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg== - } + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} mdast-util-gfm-table@2.0.0: - resolution: - { - integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg== - } + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} mdast-util-gfm-task-list-item@2.0.0: - resolution: - { - integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ== - } + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} mdast-util-gfm@3.1.0: - resolution: - { - integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ== - } + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} mdast-util-phrasing@4.1.0: - resolution: - { - integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== - } + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} mdast-util-to-hast@13.2.0: - resolution: - { - integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== - } + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} mdast-util-to-markdown@2.1.2: - resolution: - { - integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== - } + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} mdast-util-to-string@4.0.0: - resolution: - { - integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== - } + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} micromark-core-commonmark@2.0.3: - resolution: - { - integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg== - } + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} micromark-factory-destination@2.0.1: - resolution: - { - integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA== - } + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} micromark-factory-label@2.0.1: - resolution: - { - integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg== - } + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} micromark-factory-space@2.0.1: - resolution: - { - integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg== - } + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} micromark-factory-title@2.0.1: - resolution: - { - integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw== - } + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} micromark-factory-whitespace@2.0.1: - resolution: - { - integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ== - } + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} micromark-util-character@2.1.1: - resolution: - { - integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q== - } + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} micromark-util-chunked@2.0.1: - resolution: - { - integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA== - } + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} micromark-util-classify-character@2.0.1: - resolution: - { - integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q== - } + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} micromark-util-combine-extensions@2.0.1: - resolution: - { - integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg== - } + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} micromark-util-decode-numeric-character-reference@2.0.2: - resolution: - { - integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw== - } + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} micromark-util-decode-string@2.0.1: - resolution: - { - integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ== - } + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} micromark-util-encode@2.0.1: - resolution: - { - integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw== - } + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} micromark-util-html-tag-name@2.0.1: - resolution: - { - integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA== - } + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} micromark-util-normalize-identifier@2.0.1: - resolution: - { - integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q== - } + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} micromark-util-resolve-all@2.0.1: - resolution: - { - integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg== - } + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} micromark-util-sanitize-uri@2.0.1: - resolution: - { - integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ== - } + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} micromark-util-subtokenize@2.1.0: - resolution: - { - integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA== - } + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} micromark-util-symbol@2.0.1: - resolution: - { - integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q== - } + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} micromark-util-types@2.0.2: - resolution: - { - integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA== - } + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} micromark@4.0.2: - resolution: - { - integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA== - } + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} micromatch@4.0.8: - resolution: - { - integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} mime@1.6.0: - resolution: - { - integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - } - engines: { node: '>=4' } + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} hasBin: true minimatch@9.0.5: - resolution: - { - integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} minipass@7.1.2: - resolution: - { - integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - } - engines: { node: '>=16 || 14 >=14.17' } + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} minisearch@7.1.2: - resolution: - { - integrity: sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA== - } + resolution: {integrity: sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==} minizlib@3.0.2: - resolution: - { - integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== - } - engines: { node: '>= 18' } + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} mitt@3.0.1: - resolution: - { - integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== - } + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} mkdirp@3.0.1: - resolution: - { - integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - } - engines: { node: '>=10' } + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} hasBin: true mlly@1.7.4: - resolution: - { - integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== - } + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + modern-tar@0.8.5: + resolution: {integrity: sha512-snEhs+6G5Tjd4I7tLCDOaoln2RgE0bD19RzEKgvgK2hZ5VKy3MpLhLTZ2fWpXSTg4K2cyPwp+VHATFJhxfnOeA==} + engines: {node: '>=18.0.0'} + + motion-dom@13.3.0: + resolution: {integrity: sha512-AmAnB6pHdZ1vHGzWzuzteG6Q3j1lHKeX/lbST6jGlgm0cjvLUgaCk1xhOuPMOy5SgovN6wnnUdwFrkcsus7Ftg==} + + motion-utils@13.3.0: + resolution: {integrity: sha512-sgSschQp7EseHInIlR7hBbMuvet3RA0bs28KPZAXJcGKGdxHGvh1ogpYDilY3bOMtl73EqPNmp75sAKHYPU5sg==} + + motion-v@2.4.4: + resolution: {integrity: sha512-AMb3Acnl+xFZhCFqEklnpDK/STntM2BCrySqlnoinLnD7hgHmJ7p09RY5r3exhne2speoKM6KIEg7TMDy8cT9w==} + peerDependencies: + '@vueuse/core': '>=10.0.0' + vue: '>=3.0.0' ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - } + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} muggle-string@0.4.1: - resolution: - { - integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ== - } + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} nanoid@3.3.11: - resolution: - { - integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== - } - engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true needle@3.3.1: - resolution: - { - integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q== - } - engines: { node: '>= 4.4.x' } + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} hasBin: true node-addon-api@7.1.1: - resolution: - { - integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== - } + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} oniguruma-parser@0.5.4: - resolution: - { - integrity: sha512-yNxcQ8sKvURiTwP0mV6bLQCYE7NKfKRRWunhbZnXgxSmB1OXa1lHrN3o4DZd+0Si0kU5blidK7BcROO8qv5TZA== - } + resolution: {integrity: sha512-yNxcQ8sKvURiTwP0mV6bLQCYE7NKfKRRWunhbZnXgxSmB1OXa1lHrN3o4DZd+0Si0kU5blidK7BcROO8qv5TZA==} oniguruma-to-es@4.1.0: - resolution: - { - integrity: sha512-SNwG909cSLo4vPyyPbU/VJkEc9WOXqu2ycBlfd1UCXLqk1IijcQktSBb2yRQ2UFPsDhpkaf+C1dtT3PkLK/yWA== - } + resolution: {integrity: sha512-SNwG909cSLo4vPyyPbU/VJkEc9WOXqu2ycBlfd1UCXLqk1IijcQktSBb2yRQ2UFPsDhpkaf+C1dtT3PkLK/yWA==} package-manager-detector@0.2.11: - resolution: - { - integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ== - } + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + + package-manager-detector@1.8.0: + resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} parse-node-version@1.0.1: - resolution: - { - integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== - } - engines: { node: '>= 0.10' } + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} path-browserify@1.0.1: - resolution: - { - integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - } + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} pathe@2.0.3: - resolution: - { - integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== - } + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} perfect-debounce@1.0.0: - resolution: - { - integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== - } + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} picocolors@1.1.1: - resolution: - { - integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - } + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - } - engines: { node: '>=8.6' } + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} pify@4.0.1: - resolution: - { - integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} pkg-types@1.3.1: - resolution: - { - integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== - } + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} pkg-types@2.1.0: - resolution: - { - integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A== - } + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} postcss@8.5.6: - resolution: - { - integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== - } - engines: { node: ^10 || ^12 || >=14 } + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} preact@10.26.4: - resolution: - { - integrity: sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w== - } + resolution: {integrity: sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==} prettier@3.6.2: - resolution: - { - integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== - } - engines: { node: '>=14' } + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} hasBin: true property-information@7.0.0: - resolution: - { - integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg== - } + resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} prr@1.0.1: - resolution: - { - integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== - } + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} quansync@0.2.10: - resolution: - { - integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A== - } + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} readdirp@4.1.2: - resolution: - { - integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== - } - engines: { node: '>= 14.18.0' } + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} regex-recursion@6.0.2: - resolution: - { - integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg== - } + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} regex-utilities@2.3.0: - resolution: - { - integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng== - } + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} regex@6.0.1: - resolution: - { - integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA== - } + resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} rfdc@1.4.1: - resolution: - { - integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== - } + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} rollup@4.39.0: - resolution: - { - integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g== - } - engines: { node: '>=18.0.0', npm: '>=8.0.0' } + resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true safer-buffer@2.1.2: - resolution: - { - integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - } + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} sass@1.89.2: - resolution: - { - integrity: sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA== - } - engines: { node: '>=14.0.0' } + resolution: {integrity: sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==} + engines: {node: '>=14.0.0'} hasBin: true sax@1.4.1: - resolution: - { - integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== - } + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} search-insights@2.17.3: - resolution: - { - integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ== - } + resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} semver@5.7.2: - resolution: - { - integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - } + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true shiki@3.2.1: - resolution: - { - integrity: sha512-VML/2o1/KGYkEf/stJJ+s9Ypn7jUKQPomGLGYso4JJFMFxVDyPNsjsI3MB3KLjlMOeH44gyaPdXC6rik2WXvUQ== - } + resolution: {integrity: sha512-VML/2o1/KGYkEf/stJJ+s9Ypn7jUKQPomGLGYso4JJFMFxVDyPNsjsI3MB3KLjlMOeH44gyaPdXC6rik2WXvUQ==} source-map-js@1.2.1: - resolution: - { - integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} source-map@0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} space-separated-tokens@2.0.2: - resolution: - { - integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== - } + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} speakingurl@14.0.1: - resolution: - { - integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ== - } - engines: { node: '>=0.10.0' } + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} stringify-entities@4.0.4: - resolution: - { - integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== - } + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} superjson@2.2.2: - resolution: - { - integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q== - } - engines: { node: '>=16' } + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + + svg-path-properties@2.1.0: + resolution: {integrity: sha512-Zp8IvhMTfQDeVqC8wczQQXJiF7HrafV/SFkRzjYcagchNh/FL+o/Ljbe++6vOfimkZp/bVHFJXb/V2dk51YgwA==} + engines: {node: '>=22.0.0'} + + svgo@4.1.0: + resolution: {integrity: sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==} + engines: {node: '>=16'} + hasBin: true tabbable@6.2.0: - resolution: - { - integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== - } + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} tailwindcss@4.1.11: - resolution: - { - integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA== - } + resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} tapable@2.2.2: - resolution: - { - integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== - } - engines: { node: '>=6' } + resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + engines: {node: '>=6'} tar@7.4.3: - resolution: - { - integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} tinyexec@0.3.2: - resolution: - { - integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== - } + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} to-regex-range@5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - } - engines: { node: '>=8.0' } + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} trim-lines@3.0.1: - resolution: - { - integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== - } + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} tslib@2.8.1: - resolution: - { - integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - } + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} twoslash-protocol@0.3.1: - resolution: - { - integrity: sha512-BMePTL9OkuNISSyyMclBBhV2s9++DiOCyhhCoV5Kaht6eaWLwVjCCUJHY33eZJPsyKeZYS8Wzz0h+XI01VohVw== - } + resolution: {integrity: sha512-BMePTL9OkuNISSyyMclBBhV2s9++DiOCyhhCoV5Kaht6eaWLwVjCCUJHY33eZJPsyKeZYS8Wzz0h+XI01VohVw==} twoslash-vue@0.3.1: - resolution: - { - integrity: sha512-9/PS0/iL2m8G6N2ILdI18sZ8l6ex+W2nN5jIaTpfFPlnY0MOX2G5UxEVs+AuNimM9SwEnwfiIuDY9ubDCIQpSQ== - } + resolution: {integrity: sha512-9/PS0/iL2m8G6N2ILdI18sZ8l6ex+W2nN5jIaTpfFPlnY0MOX2G5UxEVs+AuNimM9SwEnwfiIuDY9ubDCIQpSQ==} peerDependencies: typescript: ^5.5.0 twoslash@0.3.1: - resolution: - { - integrity: sha512-OGqMTGvqXTcb92YQdwGfEdK0nZJA64Aj/ChLOelbl3TfYch2IoBST0Yx4C0LQ7Lzyqm9RpgcpgDxeXQIz4p2Kg== - } + resolution: {integrity: sha512-OGqMTGvqXTcb92YQdwGfEdK0nZJA64Aj/ChLOelbl3TfYch2IoBST0Yx4C0LQ7Lzyqm9RpgcpgDxeXQIz4p2Kg==} peerDependencies: typescript: ^5.5.0 typescript@5.8.3: - resolution: - { - integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== - } - engines: { node: '>=14.17' } + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} hasBin: true ufo@1.5.4: - resolution: - { - integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== - } + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} undici-types@6.21.0: - resolution: - { - integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== - } + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} unist-util-is@6.0.0: - resolution: - { - integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== - } + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} unist-util-position@5.0.0: - resolution: - { - integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== - } + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} unist-util-stringify-position@4.0.0: - resolution: - { - integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== - } + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} unist-util-visit-parents@6.0.1: - resolution: - { - integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== - } + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} unist-util-visit@5.0.0: - resolution: - { - integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== - } + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} vfile-message@4.0.2: - resolution: - { - integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== - } + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} vfile@6.0.3: - resolution: - { - integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== - } + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} vite@6.2.5: - resolution: - { - integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA== - } - engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + resolution: {integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 @@ -2593,28 +1723,16 @@ packages: optional: true vitepress-markdown-timeline@1.2.2: - resolution: - { - integrity: sha512-eDFcvudmTW33pI7XdT+ZeUPvpc4CPXI0LZbsZZ54j36G56AN6qYEBiwZpDHl77E4QvqAIJMc8phXXvm7P/Lc+Q== - } + resolution: {integrity: sha512-eDFcvudmTW33pI7XdT+ZeUPvpc4CPXI0LZbsZZ54j36G56AN6qYEBiwZpDHl77E4QvqAIJMc8phXXvm7P/Lc+Q==} vitepress-plugin-comment-with-giscus@1.1.15: - resolution: - { - integrity: sha512-1DJjgN+7SYvn5ZkjuSXPmz7nlqfcrh4qCGGviiZghA2ELXnaO2m9WY7m+RisPSaqCn90xqe0JbO2T4NMq8iUBg== - } + resolution: {integrity: sha512-1DJjgN+7SYvn5ZkjuSXPmz7nlqfcrh4qCGGviiZghA2ELXnaO2m9WY7m+RisPSaqCn90xqe0JbO2T4NMq8iUBg==} vitepress-plugin-group-icons@1.3.8: - resolution: - { - integrity: sha512-BIx1HgXEvbDeJX8NqVvthWHQqEW2slj1SkAWLMNoUR5IJq1dq6LmrURYCyznMJCB3/0g+YY89ifvQp3in1fX3g== - } + resolution: {integrity: sha512-BIx1HgXEvbDeJX8NqVvthWHQqEW2slj1SkAWLMNoUR5IJq1dq6LmrURYCyznMJCB3/0g+YY89ifvQp3in1fX3g==} vitepress@2.0.0-alpha.4: - resolution: - { - integrity: sha512-3/tiBTx47d4to5RqfYwWeht9ND0la0C8Vc0gtbdY3RMffFnWGmAQryODTXDN9Cm1exXZr8ywcxA2eJcpxa3igQ== - } + resolution: {integrity: sha512-3/tiBTx47d4to5RqfYwWeht9ND0la0C8Vc0gtbdY3RMffFnWGmAQryODTXDN9Cm1exXZr8ywcxA2eJcpxa3igQ==} hasBin: true peerDependencies: markdown-it-mathjax3: ^4 @@ -2626,18 +1744,12 @@ packages: optional: true vue-resize@2.0.0-alpha.1: - resolution: - { - integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg== - } + resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} peerDependencies: vue: ^3.0.0 vue@3.5.13: - resolution: - { - integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ== - } + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -2645,19 +1757,14 @@ packages: optional: true yallist@5.0.0: - resolution: - { - integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== - } - engines: { node: '>=18' } + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} zwitch@2.0.4: - resolution: - { - integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== - } + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: + '@algolia/autocomplete-core@1.17.9(@algolia/client-search@5.23.2)(algoliasearch@5.23.2)(search-insights@2.17.3)': dependencies: '@algolia/autocomplete-plugin-algolia-insights': 1.17.9(@algolia/client-search@5.23.2)(algoliasearch@5.23.2)(search-insights@2.17.3) @@ -2773,6 +1880,11 @@ snapshots: package-manager-detector: 0.2.11 tinyexec: 0.3.2 + '@antfu/install-pkg@2.1.0': + dependencies: + package-manager-detector: 1.8.0 + tinyexec: 1.3.1 + '@antfu/utils@8.1.1': {} '@babel/helper-string-parser@7.25.9': {} @@ -2788,6 +1900,10 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@cyberalien/svg-utils@1.2.19': + dependencies: + '@iconify/types': 2.0.0 + '@docsearch/css@3.9.0': {} '@docsearch/js@3.9.0(@algolia/client-search@5.23.2)(search-insights@2.17.3)': @@ -2902,7 +2018,7 @@ snapshots: giscus: 1.6.0 vue: 3.5.13(typescript@5.8.3) - '@iconify-json/carbon@1.2.8': + '@iconify-json/carbon@1.2.27': dependencies: '@iconify/types': 2.0.0 @@ -2914,11 +2030,15 @@ snapshots: dependencies: '@iconify/types': 2.0.0 + '@iconify-json/lucide@1.2.133': + dependencies: + '@iconify/types': 2.0.0 + '@iconify-json/octicon@1.2.5': dependencies: '@iconify/types': 2.0.0 - '@iconify-json/simple-icons@1.2.30': + '@iconify-json/simple-icons@1.2.96': dependencies: '@iconify/types': 2.0.0 @@ -2926,6 +2046,23 @@ snapshots: dependencies: '@iconify/types': 2.0.0 + '@iconify/tailwind4@1.2.3(tailwindcss@4.1.11)': + dependencies: + '@iconify/tools': 5.0.14 + '@iconify/types': 2.0.0 + '@iconify/utils': 3.1.7 + tailwindcss: 4.1.11 + + '@iconify/tools@5.0.14': + dependencies: + '@cyberalien/svg-utils': 1.2.19 + '@iconify/types': 2.0.0 + '@iconify/utils': 3.1.7 + fflate: 0.8.3 + modern-tar: 0.8.5 + pathe: 2.0.3 + svgo: 4.1.0 + '@iconify/types@2.0.0': {} '@iconify/utils@2.3.0': @@ -2941,6 +2078,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@iconify/utils@3.1.7': + dependencies: + '@antfu/install-pkg': 2.1.0 + '@iconify/types': 2.0.0 + import-meta-resolve: 4.2.0 + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.2 @@ -2981,7 +2124,7 @@ snapshots: '@nolebase/vitepress-plugin-enhanced-readabilities@2.15.1(typescript@5.8.3)(vitepress@2.0.0-alpha.4(@algolia/client-search@5.23.2)(@types/node@22.14.0)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(postcss@8.5.6)(sass@1.89.2)(search-insights@2.17.3)(typescript@5.8.3))': dependencies: - '@iconify-json/carbon': 1.2.8 + '@iconify-json/carbon': 1.2.27 '@iconify-json/icon-park-outline': 1.2.2 '@nolebase/ui': 2.15.1(typescript@5.8.3)(vitepress@2.0.0-alpha.4(@algolia/client-search@5.23.2)(@types/node@22.14.0)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.30.1)(postcss@8.5.6)(sass@1.89.2)(search-insights@2.17.3)(typescript@5.8.3)) less: 4.3.0 @@ -3114,7 +2257,7 @@ snapshots: dependencies: '@shikijs/types': 3.2.1 '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 hast-util-to-html: 9.0.5 '@shikijs/engine-javascript@3.2.1': @@ -3153,7 +2296,7 @@ snapshots: '@shikijs/types@3.2.1': dependencies: '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@shikijs/vitepress-twoslash@3.2.1(typescript@5.8.3)': dependencies: @@ -3254,6 +2397,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -3431,6 +2578,8 @@ snapshots: birpc@0.2.19: {} + boolbase@1.0.0: {} + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -3456,6 +2605,8 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@11.1.0: {} + confbox@0.1.8: {} confbox@0.2.2: {} @@ -3468,6 +2619,30 @@ snapshots: dependencies: is-what: 4.1.16 + css-select@6.0.0: + dependencies: + boolbase: 1.0.0 + css-what: 7.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@7.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + csstype@3.1.3: {} dayjs@1.11.13: {} @@ -3493,6 +2668,24 @@ snapshots: dependencies: dequal: 2.0.3 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + emoji-regex-xs@1.0.0: {} enhanced-resolve@5.18.2: @@ -3541,6 +2734,8 @@ snapshots: exsolve@1.0.4: {} + fflate@0.8.3: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -3556,6 +2751,12 @@ snapshots: dependencies: tabbable: 6.2.0 + framer-motion@13.4.0: + dependencies: + motion-dom: 13.3.0 + motion-utils: 13.3.0 + tslib: 2.8.1 + fsevents@2.3.3: optional: true @@ -3569,7 +2770,7 @@ snapshots: hast-util-to-html@9.0.5: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@types/unist': 3.0.3 ccount: 2.0.1 comma-separated-tokens: 2.0.3 @@ -3583,10 +2784,12 @@ snapshots: hast-util-whitespace@3.0.0: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 he@1.2.0: {} + hey-listen@1.0.8: {} + hookable@5.5.3: {} html-void-elements@3.0.0: {} @@ -3601,6 +2804,8 @@ snapshots: immutable@5.1.3: {} + import-meta-resolve@4.2.0: {} + is-extglob@2.1.1: optional: true @@ -3715,6 +2920,14 @@ snapshots: mark.js@8.11.1: {} + markdown-it-deflist@4.0.0: {} + + markdown-it-footnote@4.0.0: {} + + markdown-it-sup@2.0.0: {} + + markdown-it-task-lists@2.1.1: {} + markdown-table@3.0.4: {} mdast-util-find-and-replace@3.0.2: @@ -3831,6 +3044,10 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.1.0 @@ -3996,6 +3213,26 @@ snapshots: pkg-types: 1.3.1 ufo: 1.5.4 + modern-tar@0.8.5: {} + + motion-dom@13.3.0: + dependencies: + motion-utils: 13.3.0 + + motion-utils@13.3.0: {} + + motion-v@2.4.4(@vueuse/core@12.8.2(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)): + dependencies: + '@vueuse/core': 12.8.2(typescript@5.8.3) + framer-motion: 13.4.0 + hey-listen: 1.0.8 + motion-dom: 13.3.0 + motion-utils: 13.3.0 + vue: 3.5.13(typescript@5.8.3) + transitivePeerDependencies: + - react + - react-dom + ms@2.1.3: {} muggle-string@0.4.1: {} @@ -4011,6 +3248,10 @@ snapshots: node-addon-api@7.1.1: optional: true + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + oniguruma-parser@0.5.4: {} oniguruma-to-es@4.1.0: @@ -4024,6 +3265,8 @@ snapshots: dependencies: quansync: 0.2.10 + package-manager-detector@1.8.0: {} + parse-node-version@1.0.1: {} path-browserify@1.0.1: {} @@ -4123,6 +3366,8 @@ snapshots: sax@1.4.1: optional: true + sax@1.6.1: {} + search-insights@2.17.3: {} semver@5.7.2: @@ -4157,6 +3402,18 @@ snapshots: dependencies: copy-anything: 3.0.5 + svg-path-properties@2.1.0: {} + + svgo@4.1.0: + dependencies: + commander: 11.1.0 + css-select: 6.0.0 + css-tree: 3.2.1 + css-what: 7.0.0 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.1 + tabbable@6.2.0: {} tailwindcss@4.1.11: {} @@ -4174,6 +3431,8 @@ snapshots: tinyexec@0.3.2: {} + tinyexec@1.3.1: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -4276,7 +3535,7 @@ snapshots: dependencies: '@docsearch/css': 3.9.0 '@docsearch/js': 3.9.0(@algolia/client-search@5.23.2)(search-insights@2.17.3) - '@iconify-json/simple-icons': 1.2.30 + '@iconify-json/simple-icons': 1.2.96 '@shikijs/core': 3.2.1 '@shikijs/transformers': 3.2.1 '@shikijs/types': 3.2.1 diff --git a/public/devchalk-mark.png b/public/devchalk-mark.png new file mode 100644 index 000000000..312a2ce32 Binary files /dev/null and b/public/devchalk-mark.png differ diff --git a/public/logo@2x.png b/public/logo@2x.png new file mode 100644 index 000000000..0edbe1235 Binary files /dev/null and b/public/logo@2x.png differ diff --git a/public/meta.png b/public/meta.png index 109677996..41b11d116 100644 Binary files a/public/meta.png and b/public/meta.png differ diff --git a/uz_UZ/ai/sdk.md b/uz_UZ/ai/sdk.md index 3408d6fcd..73cbe1785 100644 --- a/uz_UZ/ai/sdk.md +++ b/uz_UZ/ai/sdk.md @@ -1,7 +1,5 @@ # AI SDK -[[toc]] - ## Kirish AI SDK Goravel ilovalarida AI provayderlari bilan o'zaro aloqa qilish uchun yagona API taqdim etadi. U `AI` fasadini, holatli suhbatlarni, agent klasslarini, provayder/model opsiyalarini, ilovalarni, oqimli javoblarni, rasm yaratishni, audio yaratishni va transkripsiyani o'z ichiga oladi. diff --git a/uz_UZ/architecture-concepts/facades.md b/uz_UZ/architecture-concepts/facades.md index cd6f4cf12..349bac1d6 100644 --- a/uz_UZ/architecture-concepts/facades.md +++ b/uz_UZ/architecture-concepts/facades.md @@ -1,7 +1,5 @@ # Fasadlar -[[toc]] - ## Kirish `facades` ilova yadrosining asosiy funksiyalari uchun "static" interfeysni ta'minlaydi va ko'proq moslashuvchan, chiroyli va sinov o'tkazish oson bo'lgan sintaksisni taqdim etadi. Goravel’ning barcha facadelari app/facades papkasi ichida joylashgan: diff --git a/uz_UZ/architecture-concepts/request-lifecycle.md b/uz_UZ/architecture-concepts/request-lifecycle.md index bdf9b3263..e1ae76221 100644 --- a/uz_UZ/architecture-concepts/request-lifecycle.md +++ b/uz_UZ/architecture-concepts/request-lifecycle.md @@ -1,7 +1,5 @@ # So‘rovning ishlash jarayoni -[[toc]] - ## Kirish Har qanday vositadan real hayotda foydalanish, uning qanday ishlashini bilganingizda yanada intuitiv va tushunarli bo‘ladi. Ushbu hujjat sizga Goravel qanday ishlashini aniq va umumiy darajada tushuntirib berishni maqsad qiladi. Agar har bir atamani darhol to'g'ri tushunmasangiz, tashvishlanmang - faqat narsalar qanday ishlashini asosiy ma'noda tushunishga harakat qiling, va siz qo'llanmaning qolgan qismini o'rganayotganda bilimingiz o'sib boradi. diff --git a/uz_UZ/architecture-concepts/service-container.md b/uz_UZ/architecture-concepts/service-container.md index c4f6db47d..313a8aa5f 100644 --- a/uz_UZ/architecture-concepts/service-container.md +++ b/uz_UZ/architecture-concepts/service-container.md @@ -1,7 +1,5 @@ # Xizmat Konteyneri -[[toc]] - ## Kirish Goravel xizmat konteyneri sinf bog'liqliklarini boshqarish va bog'liqlik in'ektsiyasini amalga oshirish uchun kuchli vosita hisoblanadi. U Goravelning barcha modullarini o'z ichiga oladi va sizga o'z xizmatlaringizni konteynerga bog'lash va kerak bo'lganda ularni hal qilish imkonini beradi. Xizmat konteyneri Goravel atrofidagi uchinchi tomon paketlari uchun kuchli qo'llab-quvvatlashni ta'minlaydi. diff --git a/uz_UZ/architecture-concepts/service-providers.md b/uz_UZ/architecture-concepts/service-providers.md index c5011f485..00c3df9b9 100644 --- a/uz_UZ/architecture-concepts/service-providers.md +++ b/uz_UZ/architecture-concepts/service-providers.md @@ -1,7 +1,5 @@ # Xizmat ko'rsatuvchilar -[[toc]] - ## Kirish The most important thing in the kernel boot operation is to load the `ServiceProvider`. Ilovaning barcha `ServiceProvider`lari `bootstrap/providers.go` faylida sozlanadi. diff --git a/uz_UZ/database/getting-started.md b/uz_UZ/database/getting-started.md index 894685198..b54a6b520 100644 --- a/uz_UZ/database/getting-started.md +++ b/uz_UZ/database/getting-started.md @@ -1,7 +1,5 @@ # Boshlash -[[toc]] - ## Kirish Deyarli barcha ilovalar ma'lumotlar bazalari bilan o'zaro aloqada bo'lishi kerak, shuning uchun Goravel juda oddiy va qulay ma'lumotlar bazasi o'zaro aloqasini taqdim etadi. Dasturchilar ma'lumotlar bazalari bilan ishlash uchun native SQL, so'rov quruvchi va [Orm](../orm/getting-started) dan foydalanishlari mumkin. Hozirda Goravel quyidagi to'rtta ma'lumotlar bazasini rasmiy qo'llab-quvvatlaydi: @@ -75,7 +73,9 @@ var product Product err := facades.DB().Select(&product, "SELECT * FROM products WHERE id = ?", 1) ``` -> Eslatma: Turli ma'lumotlar bazasi drayverlari turli joy egallovchilarni talab qiladi. Masalan, `?` belgisi MySQL uchun, `@` belgisi esa PostgreSQL uchun ishlatiladi. +::: warning +Turli ma'lumotlar bazasi drayverlari turli joy egallovchilarni talab qiladi. Masalan, `?` belgisi MySQL uchun, `@` belgisi esa PostgreSQL uchun ishlatiladi. +::: ### Kiritish diff --git a/uz_UZ/database/migrations.md b/uz_UZ/database/migrations.md index 3bb151ca5..c4241d232 100644 --- a/uz_UZ/database/migrations.md +++ b/uz_UZ/database/migrations.md @@ -1,7 +1,5 @@ # Migratsiyalar -[[toc]] - ## Kirish Bir necha odam ilovalarni ishlab chiqishda hamkorlik qilganda, sinxronizatsiya uchun standartlashtirilgan ma'lumotlar bazasi tuzilishiga ega bo'lish juda muhimdir. Bunisiz, har bir kishining individual ma'lumotlari mos kelmasligi sababli tartibsizlik yuzaga kelishi mumkin. Ma'lumotlar bazasi migratsiyasi bu muammoning yechimidir. Ma'lumotlar bazasi tuzilishi versiyalarni boshqarish orqali barcha ishlab chiquvchilar orasida uning izchilligini ta'minlash uchun nazorat qilinadi. diff --git a/uz_UZ/database/queries.md b/uz_UZ/database/queries.md index 371e58532..cbeee9d18 100644 --- a/uz_UZ/database/queries.md +++ b/uz_UZ/database/queries.md @@ -1,7 +1,5 @@ # So'rov Quruvchi -[[toc]] - ## Kirish Ma'lumotlar bazasi so'rovlari quruvchisi ma'lumotlar bazasi so'rovlarini yaratish va bajarish uchun qulay interfeysni taqdim etadi. U ilovangizda ko'p ma'lumotlar bazasi operatsiyalarini bajarish uchun ishlatilishi mumkin va barcha qo'llab-quvvatlanadigan ma'lumotlar bazasi tizimlari bilan ishlaydi. @@ -130,7 +128,9 @@ err := facades.DB().Table("products").Chunk(2, func(rows []db.Row) error { }) ``` -> Eslatma: Chunk chaqiruvida yozuvlarni o'zgartirish, yozuvlarning chunk natijalariga kiritilmasligiga olib kelishi mumkin. +::: warning +Chunk chaqiruvida yozuvlarni o'zgartirish, yozuvlarning chunk natijalariga kiritilmasligiga olib kelishi mumkin. +::: ### Kursor diff --git a/uz_UZ/database/seeding.md b/uz_UZ/database/seeding.md index c59d18c09..b4b16c077 100644 --- a/uz_UZ/database/seeding.md +++ b/uz_UZ/database/seeding.md @@ -1,7 +1,5 @@ # Ma'lumotlar bazasi: Urg'ochi qo'shish -[[toc]] - ## Kirish Goravel ma'lumotlar bazangizni seed struct yordamida ma'lumotlar bilan to'ldirish imkoniyatini o'z ichiga oladi. Barcha urug' strukturalari `database/seeders` katalogida saqlanadi. Standart bo‘yicha, siz uchun `DatabaseSeeder` struktura belgilangan. diff --git a/uz_UZ/digging-deeper/artisan-console.md b/uz_UZ/digging-deeper/artisan-console.md index 9415e6fa5..1475fba53 100644 --- a/uz_UZ/digging-deeper/artisan-console.md +++ b/uz_UZ/digging-deeper/artisan-console.md @@ -1,7 +1,5 @@ # Artisan Konsoli -[[toc]] - ## Kirish Artisan - Goravel bilan birga keladigan, buyruq qatori bilan ishlash uchun CLI vositasidir. Siz uni `facades.Artisan()` yordamida ochishingiz mumkin. Ushbu vosita sizning ilovangizni rivojlantirishda yordam beradigan bir nechta foydali buyruqlarga ega. Barcha mavjud buyruqlarni ko'rish uchun quyidagi buyruqdan foydalaning. @@ -92,7 +90,9 @@ Qaytarilgan qiymat filtrlash xatti-harakatini belgilaydi: - **`[]string{}` qaytarilsa** — barcha buyruqlar olib tashlanadi. - **Yozuvlar qaytarilsa** — faqat imzosi yozuvga mos keladigan buyruqlar saqlanadi. -> Eslatma: Filtr `WithCommands` orqali qo'shilgan barcha buyruqlarga, shu jumladan foydalanuvchi tomonidan qo'lda qo'shilgan buyruqlarga ham qo'llaniladi, shuning uchun foydalanuvchi filtrni chetlab o'ta olmaydi. +::: info +Filtr `WithCommands` orqali qo'shilgan barcha buyruqlarga, shu jumladan foydalanuvchi tomonidan qo'lda qo'shilgan buyruqlarga ham qo'llaniladi, shuning uchun foydalanuvchi filtrni chetlab o'ta olmaydi. +::: ### Buyruq tuzilmasi @@ -636,9 +636,11 @@ func (receiver *ConsoleMakeCommand) Extend() command.Extend { Ba'zan siz Artisan buyrug'ini CLI tashqarisida bajarishingiz mumkin, buning uchun `facades.Artisan()` da `Call` metodidan foydalanishingiz mumkin. ```go -facades.Route().Get("/", func(c *gin.Context) { +facades.Route().Get("/", func(ctx http.Context) http.Response { facades.Artisan().Call("emails") facades.Artisan().Call("emails --lang Chinese name") // With arguments and options + + return ctx.Response().Success().String("done") }) ``` diff --git a/uz_UZ/digging-deeper/cache.md b/uz_UZ/digging-deeper/cache.md index 5ca3d271c..62e1db58c 100644 --- a/uz_UZ/digging-deeper/cache.md +++ b/uz_UZ/digging-deeper/cache.md @@ -1,7 +1,5 @@ # Kesh -[[toc]] - ## Kirish Goravel kengaytiriladigan keshlash modulini taqdim etadi, uni `facades.Cache()` yordamida boshqarish mumkin. Goravel "memory" haydovchisi bilan birga keladi, boshqa haydovchilar uchun mos keladigan mustaqil kengaytma paketlarini tekshiring: diff --git a/uz_UZ/digging-deeper/collections.md b/uz_UZ/digging-deeper/collections.md index fc7c26ca9..6f791326c 100644 --- a/uz_UZ/digging-deeper/collections.md +++ b/uz_UZ/digging-deeper/collections.md @@ -1,7 +1,5 @@ # To'plamlar -[[toc]] - ## Kirish Goravel `github.com/goravel/framework/support/collect` paketi orqali fluent to'plam API sini taqdim etadi. To'plamlar kesim ma'lumotlarini zanjirlanadigan metodlar bilan filtrlash, o'zgartirish, yig'ish va tekshirishni qulay qiladi. diff --git a/uz_UZ/digging-deeper/color.md b/uz_UZ/digging-deeper/color.md index 14ac1beee..79bb129b7 100644 --- a/uz_UZ/digging-deeper/color.md +++ b/uz_UZ/digging-deeper/color.md @@ -1,7 +1,5 @@ # Rang -[[toc]] - ## Kirish `color` paketi [PTerm](https://github.com/pterm/pterm) kutubxonasi yordamida terminal chiqishini ranglash uchun funksiyalar to'plamini taqdim etadi. diff --git a/uz_UZ/digging-deeper/event.md b/uz_UZ/digging-deeper/event.md index 320cf579e..d9b51cd26 100644 --- a/uz_UZ/digging-deeper/event.md +++ b/uz_UZ/digging-deeper/event.md @@ -1,7 +1,5 @@ # Tadbirlar -[[toc]] - ## Kirish Goravel hodisalari oddiy kuzatuvchi naqshini amalga oshiradi, ilovangiz ichida sodir bo'ladigan turli xil hodisalarga obuna bo'lish va tinglash imkonini beradi. Tadbir sinflari odatda `app/events` katalogida saqlanadi, ularning tinglovchilari esa `app/listeners` katalogida saqlanadi. Agar ilovangizda bu kataloglarni ko'rmasangiz, xavotirlanmang, chunki ular siz Artisan konsol buyruqlari yordamida hodisalar va tinglovchilarni yaratayotganda siz uchun yaratiladi. diff --git a/uz_UZ/digging-deeper/filesystem.md b/uz_UZ/digging-deeper/filesystem.md index d811de10a..3fd4587dd 100644 --- a/uz_UZ/digging-deeper/filesystem.md +++ b/uz_UZ/digging-deeper/filesystem.md @@ -1,7 +1,5 @@ # Fayl saqlash -[[toc]] - ## Kirish Goravel mahalliy fayl tizimlari, Amazon S3, Aliyun OSS, Tencent COS, Minio va Cloudinary bilan ishlash uchun oddiy drayverlarni taqdim etadi. Yanada yaxshisi, ushbu saqlash variantlari o'rtasida mahalliy ishlab chiqish mashinangiz va ishlab chiqarish serveringiz o'rtasida o'tish juda oddiy, chunki har bir tizim uchun API bir xil bo'lib qoladi. Goravel `local` haydovchi bilan birga keladi, boshqa haydovchilar uchun iltimos, tegishli mustaqil kengaytma paketini tekshiring: @@ -337,4 +335,6 @@ type Driver interface { } ``` -> Eslatma: Maxsus drayver ro'yxatdan o'tkazilganda konfiguratsiya yuklanmaganligi sababli, iltimos, maxsus drayverda konfiguratsiyani olish uchun `facades.Config().Env()` dan foydalaning. +::: warning +Maxsus drayver ro'yxatdan o'tkazilganda konfiguratsiya yuklanmaganligi sababli, iltimos, maxsus drayverda konfiguratsiyani olish uchun `facades.Config().Env()` dan foydalaning. +::: diff --git a/uz_UZ/digging-deeper/helpers.md b/uz_UZ/digging-deeper/helpers.md index 56d858419..1dd7f3cd5 100644 --- a/uz_UZ/digging-deeper/helpers.md +++ b/uz_UZ/digging-deeper/helpers.md @@ -1,7 +1,5 @@ # Yordamchilar -[[toc]] - ## Mavjud usullar ### Yo'llar diff --git a/uz_UZ/digging-deeper/http-client.md b/uz_UZ/digging-deeper/http-client.md index 34009f84a..bdf3a9de7 100644 --- a/uz_UZ/digging-deeper/http-client.md +++ b/uz_UZ/digging-deeper/http-client.md @@ -1,7 +1,5 @@ # HTTP mijozi -[[toc]] - ## Kirish Dasturiy ta'minotni ishlab chiqishda, ma'lumotlarni olish uchun API ni chaqirish kerak bo'lgan ko'p holatlar mavjud — xoh u mikroservisga ulanish bo'lsin, xoh uchinchi tomon API siga kirish bo'lsin. Bunday hollarda, diff --git a/uz_UZ/digging-deeper/localization.md b/uz_UZ/digging-deeper/localization.md index 46fd8a318..1b11c14c7 100644 --- a/uz_UZ/digging-deeper/localization.md +++ b/uz_UZ/digging-deeper/localization.md @@ -1,7 +1,5 @@ # Mahalliylashtirish -[[toc]] - ## Kirish Goravelning lokalizatsiya xususiyatlari turli tillardagi satrlarni olishning qulay usulini taqdim etadi, bu esa ilovangizda bir nechta tillarni qo'llab-quvvatlashni osonlashtiradi. Til satrlari `lang` katalogidagi fayllarda saqlanadi va Goravel til fayllarini tartibga solishning ikkita usulini qo'llab-quvvatlaydi: diff --git a/uz_UZ/digging-deeper/mail.md b/uz_UZ/digging-deeper/mail.md index df41d6cfb..b01f5d0fb 100644 --- a/uz_UZ/digging-deeper/mail.md +++ b/uz_UZ/digging-deeper/mail.md @@ -1,7 +1,5 @@ # Pochta -[[toc]] - ## Kirish Goravel pochtani mahalliy ravishda osongina yuborish uchun `facades.Mail()` dan foydalanishi mumkin. diff --git a/uz_UZ/digging-deeper/package-development.md b/uz_UZ/digging-deeper/package-development.md index 9b74e4e39..25e39e0ea 100644 --- a/uz_UZ/digging-deeper/package-development.md +++ b/uz_UZ/digging-deeper/package-development.md @@ -1,7 +1,5 @@ # Paketlarni ishlab chiqish -[[toc]] - ## Kirish Paketlar Goravelga funksiyalarni qo'shishning asosiy usuli hisoblanadi. Ushbu paketlar Goravel dasturini takomillashtirish uchun maxsus ishlab chiqilgan marshrutlar, kontrollerlar va konfiguratsiyalarni o'z ichiga olishi mumkin. Ushbu qo'llanma Goravelga xos paketlarni ishlab chiqishga qaratilgan. diff --git a/uz_UZ/digging-deeper/pluralization.md b/uz_UZ/digging-deeper/pluralization.md index a36c6df09..ab9da8f10 100644 --- a/uz_UZ/digging-deeper/pluralization.md +++ b/uz_UZ/digging-deeper/pluralization.md @@ -1,7 +1,5 @@ # Ko'pliklashtirish -[[toc]] - ## Kirish Satrlar har qanday veb-ilova uchun muhimdir. Goravel so'zlarni birlik va ko'plik shakllariga aylantirish uchun oddiy yordamchi dasturlarni taqdim etadi. Sukut bo'yicha **inglizcha** ni qo'llab-quvvatlaydi, lekin siz boshqa tillarni yoki maxsus qoidalarni osongina qo'shishingiz mumkin. diff --git a/uz_UZ/digging-deeper/processes.md b/uz_UZ/digging-deeper/processes.md index 3f5613a4c..eddb31ca1 100644 --- a/uz_UZ/digging-deeper/processes.md +++ b/uz_UZ/digging-deeper/processes.md @@ -1,7 +1,5 @@ # Jarayonlar -[[toc]] - ## Kirish Goravel Go'ning standart `os/exec` paketi atrofida ifodali va oqlangan API taqdim etadi, bu sizga ilovangizdan tashqi buyruqlarni muammosiz chaqirish imkonini beradi. Odatiy bo'lib, Go'ning jarayonlarni boshqarishi batafsil bo'lishi mumkin; Goravel'ning "Jarayon" jabhasi bu umumiy vazifani soddalashtiradi, buyruqlarni bajarish, chiqishlarni boshqarish va asinxron jarayonlarni boshqarish uchun ravon interfeysni taklif qiladi. diff --git a/uz_UZ/digging-deeper/queues.md b/uz_UZ/digging-deeper/queues.md index 07a16c7c0..6f228cf59 100644 --- a/uz_UZ/digging-deeper/queues.md +++ b/uz_UZ/digging-deeper/queues.md @@ -1,7 +1,5 @@ # Navbatlar -[[toc]] - ## Kirish Veb-ilovangizni yaratishda, veb-so‘rov davomida bajarish uchun juda uzoq vaqt talab qiladigan, yuklangan CSV faylini tahlil qilish va saqlash kabi vazifalar bo‘lishi mumkin. Xo‘sh, Goravel sizga orqa fonda ishlaydigan navbatga qo‘yilgan ishlarni yaratish imkoniyatini beruvchi yechimni taklif qiladi. Shu tarzda, vaqt talab qiladigan vazifalarni navbatga o‘tkazish orqali, ilovangiz veb-so‘rovlarga ancha tezroq javob bera oladi va mijozlaringiz uchun yaxshi foydalanuvchi tajribasini taqdim etadi. Ushbu xususiyatni amalga oshirish uchun biz `facades.Queue()` dan foydalanamiz. diff --git a/uz_UZ/digging-deeper/strings.md b/uz_UZ/digging-deeper/strings.md index 69aa98337..41d62bf58 100644 --- a/uz_UZ/digging-deeper/strings.md +++ b/uz_UZ/digging-deeper/strings.md @@ -1,7 +1,5 @@ # Matnllar -[[toc]] - ## Kirish Goravel sizga satrlarni osongina boshqarish imkonini beruvchi ravon satrlarni boshqarish kutubxonasini taqdim etadi. Ravon Strings sizga bir nechta satr operatsiyalarini usul zanjiri orqali birlashtirish imkonini beradi, bu yerda usullarning aksariyati qo'shimcha usullarni zanjirlash imkonini beruvchi `support/str.String` misolini qaytaradi. Zanjirli operatsiyalarni qo'llagandan so'ng, oxirgi satr qiymatini olish uchun siz asosiy "satr" qiymatini qaytaradigan "String" usulini chaqirishingiz mumkin. diff --git a/uz_UZ/digging-deeper/task-scheduling.md b/uz_UZ/digging-deeper/task-scheduling.md index b2a4c7505..876a5648e 100644 --- a/uz_UZ/digging-deeper/task-scheduling.md +++ b/uz_UZ/digging-deeper/task-scheduling.md @@ -1,7 +1,5 @@ # Vazifa rejalashtirish -[[toc]] - ## Kirish Avvalroq, serveringizda rejalashtirilishi kerak bo‘lgan har bir vazifa uchun cron konfiguratsiyasi yozuvini yaratishingiz kerak edi. Biroq, bu yondashuv tezda muammoga aylanadi, chunki vazifa jadvalingiz manba nazoratida emas va cron yozuvlarini ko‘rish yoki qo‘shish/o‘zgartirish uchun serveringizga SSH orqali ulanishingiz kerak. diff --git a/uz_UZ/digging-deeper/telemetry.md b/uz_UZ/digging-deeper/telemetry.md index 5fad4fa1c..9218a2545 100644 --- a/uz_UZ/digging-deeper/telemetry.md +++ b/uz_UZ/digging-deeper/telemetry.md @@ -1,7 +1,5 @@ # Telemetriya -[[toc]] - ## Kirish Goravel [OpenTelemetry](https://opentelemetry.io) asosida qurilgan kuzatuvchanlik modulini taqdim etadi, undan `facades.Telemetry()` orqali foydalanish mumkin. Bu sizning ilovangizdan treyslar, metrikalar va loglarni yig'ish va ularni Jaeger, Prometheus, Grafana yoki Datadog kabi har qanday OTLP-mos backendga eksport qilish imkonini beradi. diff --git a/uz_UZ/getting-started/compile.md b/uz_UZ/getting-started/compile.md index c5cd08fa7..3e8bb2318 100644 --- a/uz_UZ/getting-started/compile.md +++ b/uz_UZ/getting-started/compile.md @@ -1,7 +1,5 @@ # Tuzish -[[toc]] - ## Tuzish buyrug‘i Goravel loyihasini quyidagi buyruq orqali tuzish mumkin: @@ -126,7 +124,9 @@ docker-compose build docker-compose up ``` -> Eslatma: Agar tashqi kirish kerak bo‘lsa, APP_HOST ni 0.0.0.0 ga o‘zgartirishingiz kerak +::: tip +Agar tashqi kirish kerak bo‘lsa, APP_HOST ni 0.0.0.0 ga o‘zgartirishingiz kerak +::: ## Vaqt mintaqasini o‘rnatish diff --git a/uz_UZ/getting-started/configuration.md b/uz_UZ/getting-started/configuration.md index 91fd515c1..0bc88c9a5 100644 --- a/uz_UZ/getting-started/configuration.md +++ b/uz_UZ/getting-started/configuration.md @@ -1,7 +1,5 @@ # Konfiguratsiya -[[toc]] - ## Kirish Goravel freymvorkining barcha konfiguratsiya fayllari `config` papkasida saqlanadi. Siz aniq ko'rsatmalarni ko'rib chiqishingiz va loyiha ehtiyojlariga mos ravishda ularni moslashuvchan sozlashingiz mumkin. diff --git a/uz_UZ/getting-started/directory-structure.md b/uz_UZ/getting-started/directory-structure.md index 30104bd04..339ca08b6 100644 --- a/uz_UZ/getting-started/directory-structure.md +++ b/uz_UZ/getting-started/directory-structure.md @@ -1,7 +1,5 @@ # Papka tuzilishi -[[toc]] - ## Kirish Standart fayl tuzilmasi loyihaning rivojlanishini yaxshiroq boshlashingizga yordam beradi, shuningdek, siz yangi papkalarni bemalol qo‘shishingiz mumkin, lekin standart papkalarni o‘zgartirmang. diff --git a/uz_UZ/getting-started/installation.md b/uz_UZ/getting-started/installation.md index b7f44a7ed..8590c086d 100644 --- a/uz_UZ/getting-started/installation.md +++ b/uz_UZ/getting-started/installation.md @@ -1,7 +1,5 @@ # O'rnatish -[[toc]] - ## Server Talablari - Golang >= 1.23 @@ -97,8 +95,6 @@ Air muvaffaqiyatli o'rnatilgandan so'ng, u muhitingizda to'g'ri bajarilishiga is Sozlashingizga qarab, Air avtomatik ravishda buyruq sifatida mavjud bo'lmasligi mumkin. Uning to'g'ri ishlashini ta'minlashning ikkita oddiy usuli: ---- - #### 🪄 Variant 1: Yordamchi Skriptdan (`air.sh`) Foydalanish Agar Air o'rnatilgan bo'lsa, lekin terminal buyrug'i sifatida tan olinmasa, uni avtomatik ravishda topadigan va ishga tushiradigan kichik yordamchi skript yaratishingiz mumkin. @@ -152,8 +148,7 @@ Ushbu sozlashdan so'ng, loyihangizni shunchaki ishga tushirish orqali boshlashin air ``` -#### ✅ Maslahat - +:::tip Air o'rnatilganligi va kirish mumkinligini tekshirish uchun ishga tushiring: ```bash @@ -161,6 +156,7 @@ which air ``` Agar u to'g'ri yo'lni qaytarmasa (masalan, `/Users/yourname/go/bin/air`), bu yordamchi skript yoki yo'l hali sozlanmaganligini anglatadi. +::: ## Konfiguratsiya diff --git a/uz_UZ/getting-started/packages.md b/uz_UZ/getting-started/packages.md index b57eb758c..d4e881a50 100644 --- a/uz_UZ/getting-started/packages.md +++ b/uz_UZ/getting-started/packages.md @@ -1,3 +1,7 @@ +--- +aside: false +--- + # Ajoyib Kengaytiruvchi Paketlar Bu yerda Goravel uchun kengaytirilgan paketlarni topishingiz mumkin, shuningdek, o'zingizning paketingizni joylashtirish uchun [goravel/docs](https://github.com/goravel/docs) repozitoriyasiga PR yaratishingiz mumkin. Iltimos, paketingizning test qamrovini iloji boricha yaxshilang. @@ -17,8 +21,8 @@ Bu yerda Goravel uchun kengaytirilgan paketlarni topishingiz mumkin, shuningdek, | [goravel/anthropic](https://github.com/goravel/anthropic) | `facades.AI()` uchun Anthropic haydovchisi | 73.3% | | [goravel/mysql](https://github.com/goravel/mysql) | MySQL ma'lumotlar bazasi haydovchisi | 73.3% | | [goravel/sqlserver](https://github.com/goravel/sqlserver) | SQL Server ma'lumotlar bazasi haydovchisi | 60.6% | -| [goravel/sqlite](https://github.com/goravel/sqlite) | SQLite ma'lumotlar bazasi haydovchisi | 45.2% | | [goravel/gemini](https://github.com/goravel/gemini) | `facades.AI()` uchun Gemini haydovchisi | 51.8% | +| [goravel/sqlite](https://github.com/goravel/sqlite) | SQLite ma'lumotlar bazasi haydovchisi | 45.2% | | [portofolio-mager/goravel-mongodb](https://github.com/portofolio-mager/goravel-mongodb) | MongoDB paketi | 16.9% | | [hulutech-web/goravel-kit-cli](https://github.com/hulutech-web/goravel-kit-cli) | Goravel qolip buyruq qatori vositasi | 15.2% | | [hulutech-web/goravel-workflow](https://github.com/hulutech-web/goravel-workflow) | Ish jarayoni paketi | 4.4% | diff --git a/uz_UZ/index.md b/uz_UZ/index.md index 4274234af..c22c63908 100644 --- a/uz_UZ/index.md +++ b/uz_UZ/index.md @@ -1,5 +1,4 @@ --- -layout: home title: Goravel — Golang uchun to‘liq imkoniyatlarga ega zamonaviy freymvork head: @@ -16,135 +15,7 @@ head: - [ 'meta', { name: twitter:description, content: Goravel - bu to'liq funksiyalarga ega va ajoyib kengaytiriladigan Golang dasturlash tizimidir. Gopherlarning o'z ilovalarini tezda qurishlariga yordam berish uchun boshlang'ich iskala sifatida. } ] - [ 'meta', { name: twitter:image, content: https://www.goravel.dev/meta.png } ] -hero: - name: Goravel - text: To'liq xususiyatli Golang dasturlash freymvorki - tagline: Komponentlashtirish, yuqori samaradorlik, kengaytirish oson, PHP dasturchilarining birinchi tanlovi. - # image: /logo.svg - actions: - - theme: brand - text: Tezda boshlash - link: /getting-started/installation - - theme: alt - text: 🌟 Github Star - link: https://github.com/goravel/goravel - target: _blank -features: - - title: 🧰 Yengil yoki to'liq imkoniyatli - details: Siz zaruriy xususiyatlarga ega bo'lgan yengil versiya yoki ORM, HTTP, jurnal, keshlash va boshqa barcha ishlanmalar uchun asosiy vositalarni o'z ichiga olgan to'liq xususiyatli versiya o'rtasida tanlashingiz mumkin. - - title: 💻 Komponentlashtirish - details: Modul dizayni, har bir modul mustaqil va alohida ishlatilishi mumkin, bu esa ishlab chiqish va texnik xizmat ko'rsatishni qulayroq qiladi. - - title: 🚀 Yuqori samaradorlik - details: Golang bilan qurilgan, tez va sezgir ilovalar yaratish uchun bir nechta ajoyib kengaytmalarni birlashtiradi. - - title: 📈 Kengaytirish oson - details: Modul bir nechta haydovchilarni taqdim etadi va ehtiyojlarga qarab kengaytirish paketlarini ishlab chiqishi mumkin, kichik loyihalardan tortib katta tizimlargacha bo'lgan har qanday o'lchamdagi ilovalar uchun mos keladi. - - title: 👥 Faol hamjamiyat - details: Faol hamjamiyat tomonidan qo'llab-quvvatlanadi, ular uning rivojlanishi, hujjatlashtirilishi va doimiy qo'llab-quvvatlashiga hissa qo'shadi. - - title: 🔄 PHP dasturchilarning birinchi tanlovi - details: Freymvork uslubi Laravel bilan muvofiq, PHP dasturchilariga yangi framework o'rganmasdan kuchli Golang ilovalarini yaratish imkonini beradi. Laravelga hurmat! +layout: goravel-home +sidebar: false +aside: false --- - -
Hissa qo'shganlar
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
Guruh
-
- -
- -
Wechat guruhiga qo'shilish uchun QR kodni skanerlang
-
- -
- - - -
Discord guruhiga qo'shilish uchun menga bosing
-
- -
-
- -
-
Mukofot
-
- -
- -
Wechat orqali QR kodni skanerlash
-
- - -
-
- - diff --git a/uz_UZ/orm/factories.md b/uz_UZ/orm/factories.md index 9f601b4e1..f678920f3 100644 --- a/uz_UZ/orm/factories.md +++ b/uz_UZ/orm/factories.md @@ -1,7 +1,5 @@ # Zavodlar -[[toc]] - ## Kirish Ilovingizni sinovdan o‘tkazish yoki ma’lumotlar bazangizni to‘ldirishda, oldindan ma’lumotlar bazangizga bir nechta yozuvlarni kiritish zarur bo‘lishi mumkin. Har bir ustun uchun qo‘lda qiymatlarni kiritish o‘rniga, Goravel sizga model zavodlarini yaratish orqali har bir modelingiz uchun standart atributlar to‘plamini belgilash imkonini beradi. diff --git a/uz_UZ/orm/getting-started.md b/uz_UZ/orm/getting-started.md index 20caeef4a..3e440bb70 100644 --- a/uz_UZ/orm/getting-started.md +++ b/uz_UZ/orm/getting-started.md @@ -1,7 +1,5 @@ # Boshlash -[[toc]] - ## Kirish Goravel juda oddiy va oson ishlatiladigan ma'lumotlar bazasi o'zaro ta'sirini taqdim etadi, dasturchilar `facades.Orm()` yordamida amallarni bajarishlari mumkin. Boshlashdan oldin [Ma'lumotlar bazasini sozlash](../database/getting-started) bo'limiga murojaat qiling. @@ -1057,7 +1055,9 @@ func (u *User) DispatchesEvents() map[contractsorm.EventType]func(contractsorm.E } ``` -> Eslatma: Faqat sizga kerak bo'lgan tadbirlarni ro'yxatdan o'tkazing. Orm orqali partiyali operatsiyalar bajarilayotganda model tadbirlari ishga tushirilmaydi. +::: warning +Faqat sizga kerak bo'lgan tadbirlarni ro'yxatdan o'tkazing. Orm orqali partiyali operatsiyalar bajarilayotganda model tadbirlari ishga tushirilmaydi. +::: ### Kuzatuvchilar @@ -1115,7 +1115,9 @@ func Boot() contractsfoundation.Application { } ``` -> Eslatma: Agar siz `DispatchesEvents` va `Observer` ni bir vaqtning o'zida o'rnatsangiz, faqat `DispatchesEvents` qo'llaniladi. +::: warning +Agar siz `DispatchesEvents` va `Observer` ni bir vaqtning o'zida o'rnatsangiz, faqat `DispatchesEvents` qo'llaniladi. +::: #### Kuzatuvchidagi parametr diff --git a/uz_UZ/orm/relationships.md b/uz_UZ/orm/relationships.md index c00b56e57..56ccb9cfb 100644 --- a/uz_UZ/orm/relationships.md +++ b/uz_UZ/orm/relationships.md @@ -1,7 +1,5 @@ # Bog'lanishlar -[[toc]] - ## Kirish Ma'lumotlar bazasi jadvallari o'zaro bog'langan bo'lishi odatiy holdir. Masalan, blog postida ko'p sharhlar bo'lishi mumkin yoki buyurtma uni joylagan foydalanuvchiga bog'langan bo'lishi mumkin. `Orm` bunday bog'lanishlarni boshqarish va ular bilan ishlashni osonlashtiradi va u turli keng tarqalgan bog'lanish turlarini qo'llab-quvvatlaydi: diff --git a/uz_UZ/prologue/contributions.md b/uz_UZ/prologue/contributions.md index c9225ee8c..597d07cdc 100644 --- a/uz_UZ/prologue/contributions.md +++ b/uz_UZ/prologue/contributions.md @@ -1,7 +1,5 @@ # Hissa qo‘shish bo‘yicha qo‘llanma -[[toc]] - Goravel turli isteʼdodlardan, masalan, kodlash, tarjima, maqola, o‘quv qo‘llanmalari va boshqalardan boy va xilma-xil hissalarni kutib oladi. Ikki xususiyatni (5 ta "Yaxshi birinchi muammo" == 1 ta "Xususiyat") bajarganingizdan so‘ng, siz asosiy hissa qo‘shuvchi sifatida tan olinasiz. Har uch oyda bitta xususiyatni bajarish orqali siz bu maqomni saqlab turishingiz mumkin. Keling, Goravelni birgalikda yanada samaraliroq qilaylik! @@ -184,7 +182,9 @@ Mavjud ko‘nikmalarni `--force` bilan qayta yozish: goravel skill:install --force goravel-testing ``` -> **Eslatma**: Mavjud ko‘nikmalar `--force` ishlatilmaguncha saqlanadi. +::: info +Mavjud ko‘nikmalar `--force` ishlatilmaguncha saqlanadi. +::: ## Xulq qoidalari diff --git a/uz_UZ/security/authentication.md b/uz_UZ/security/authentication.md index 9fcf873a7..95cb1b604 100644 --- a/uz_UZ/security/authentication.md +++ b/uz_UZ/security/authentication.md @@ -1,7 +1,5 @@ # Autentifikatsiya -[[toc]] - ## Kirish Autentifikatsiya veb-ilovalarda ajralmas xususiyatdir. Goravelning `facades.Auth()` moduli JWT va Session drayverlarini qo‘llab-quvvatlaydi va siz drayver va foydalanuvchi provayderini sozlashingiz mumkin. diff --git a/uz_UZ/security/authorization.md b/uz_UZ/security/authorization.md index 99fc84e1b..69112bd08 100644 --- a/uz_UZ/security/authorization.md +++ b/uz_UZ/security/authorization.md @@ -1,7 +1,5 @@ # Avtorizatsiya -[[toc]] - ## Kirish Goravel foydalanuvchilarning resurslar ustidagi amallarini boshqarish uchun o‘rnatilgan [autentifikatsiya](./authentication.md) xizmatlari va oson foydalaniladigan avtorizatsiya xususiyatini taklif etadi. Foydalanuvchi autentifikatsiyadan o‘tgan bo‘lsa ham, u ma’lum Eloquent modellarini yoki ma’lumotlar bazasi yozuvlarini o‘zgartirish yoki o‘chirish huquqiga ega bo‘lmasligi mumkin. Goravelning avtorizatsiya xususiyati bu avtorizatsiya tekshiruvlarini tizimli boshqarish usulini taqdim etadi. diff --git a/uz_UZ/security/encryption.md b/uz_UZ/security/encryption.md index fd1a9b2ea..96d627557 100644 --- a/uz_UZ/security/encryption.md +++ b/uz_UZ/security/encryption.md @@ -1,7 +1,5 @@ # Shifrlash -[[toc]] - ## Kirish Goravelning shifrlash xizmatlari OpenSSL yordamida AES-256 shifrlash orqali matnni shifrlash va ochish uchun oddiy, qulay interfeysni taqdim etadi. Goravelning barcha shifrlangan qiymatlari xabar autentifikatsiya kodi (GMAC) yordamida imzolangan, shuning uchun ularning asosiy qiymati shifrlanganidan keyin o‘zgartirilishi yoki buzilishi mumkin emas. diff --git a/uz_UZ/security/hashing.md b/uz_UZ/security/hashing.md index f22bd7e40..0ded55765 100644 --- a/uz_UZ/security/hashing.md +++ b/uz_UZ/security/hashing.md @@ -1,7 +1,5 @@ # Xeshlash -[[toc]] - ## Kirish Goravel `facades.Hash()` foydalanuvchi parollarini saqlash uchun xavfsiz Argon2id va Bcrypt xeshlashni taqdim etadi. Agar siz Goravel ilova boshlangʻich toʻplamlaridan birini ishlatayotgan boʻlsangiz, sukut boʻyicha roʻyxatdan oʻtish va autentifikatsiya uchun Argon2id ishlatiladi. diff --git a/uz_UZ/testing/getting-started.md b/uz_UZ/testing/getting-started.md index 0271a05e6..11064a20b 100644 --- a/uz_UZ/testing/getting-started.md +++ b/uz_UZ/testing/getting-started.md @@ -1,7 +1,5 @@ # Boshlash -[[toc]] - ## Kirish Goravelning testlash funksiyasi Golangning rasmiy test komponentiga tayanadi, birlik testlarini kengaytirib, integratsion testlarni qo‘llab-quvvatlaydi va ilova mustahkamligini oshiradi. diff --git a/uz_UZ/testing/http-tests.md b/uz_UZ/testing/http-tests.md index 19656fae2..5b260396d 100644 --- a/uz_UZ/testing/http-tests.md +++ b/uz_UZ/testing/http-tests.md @@ -1,7 +1,5 @@ # HTTP Testlari -[[toc]] - ## Kirish Veb-ilovalarni yaratishda, siz tez-tez HTTP so'rovlaringiz boshidan oxirigacha to'g'ri ishlayotganligini sinab ko'rishingiz kerak bo'ladi. Goravelning test vositalari buni oddiy qiladi - siz murakkab test muhitlarini sozlashsiz so'rovlarni simulyatsiya qilishingiz va javoblarni tekshirishingiz mumkin. diff --git a/uz_UZ/testing/mock.md b/uz_UZ/testing/mock.md index 6895220fc..3c6ff7363 100644 --- a/uz_UZ/testing/mock.md +++ b/uz_UZ/testing/mock.md @@ -1,7 +1,5 @@ # Mock -[[toc]] - ## Tavsifi Goravelning barcha funksiyalari `facades` yordamida amalga oshiriladi va barcha `facades` interfeyslardan tashkil topgan. Shunday qilib, [stretchr/testify](http://github.com/stretchr/testify) dan olingan mock funksiyasi bilan Goravel ajoyib sinov tajribasini taqdim eta oladi. diff --git a/uz_UZ/the-basics/controllers.md b/uz_UZ/the-basics/controllers.md index 2f2d94315..0863dd29d 100644 --- a/uz_UZ/the-basics/controllers.md +++ b/uz_UZ/the-basics/controllers.md @@ -1,7 +1,5 @@ # Kontrollerlar -[[toc]] - ## Kirish Alohida marshrutda barcha so‘rovni qayta ishlash mantiqini yopish (closure) shaklida belgilash o‘rniga, birlashtirish uchun kontrollerdan foydalanish mumkin. Kontrollerlar `app/http/controllers` katalogida saqlanadi. diff --git a/uz_UZ/the-basics/grpc.md b/uz_UZ/the-basics/grpc.md index 93bb859c8..f4ba9a83f 100644 --- a/uz_UZ/the-basics/grpc.md +++ b/uz_UZ/the-basics/grpc.md @@ -1,7 +1,5 @@ # Grpc -[[toc]] - ## Kirish Grpc moduli `facades.Grpc()` orqali boshqarilishi mumkin. Goravel gRPC xizmatlarini yaratish va ulardan foydalanishning nafis usulini taqdim etadi, ham server, ham mijoz tomonlarini qo'llab-quvvatlaydi. diff --git a/uz_UZ/the-basics/logging.md b/uz_UZ/the-basics/logging.md index 2591322c0..a2dc7a84e 100644 --- a/uz_UZ/the-basics/logging.md +++ b/uz_UZ/the-basics/logging.md @@ -1,7 +1,5 @@ # Loglash -[[toc]] - ## Kirish Ilovaning ishlash holatini tushunish uchun Goravel kuchli log xizmatini taqdim etadi, u log xabarlari va tizim xatolarini `facades.Log()` orqali fayl yoki boshqa kanallarga yozishi mumkin. diff --git a/uz_UZ/the-basics/middleware.md b/uz_UZ/the-basics/middleware.md index 07b597b1e..a5c15ae3e 100644 --- a/uz_UZ/the-basics/middleware.md +++ b/uz_UZ/the-basics/middleware.md @@ -1,7 +1,5 @@ # Middleware -[[toc]] - ## Kirish Middleware sizning ilovangizga kiruvchi HTTP so‘rovlarini tekshirish va filtrlash uchun qulay mexanizmni taqdim etadi. @@ -101,7 +99,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **Eslatma**: Middleware'ni chiqarib tashlash middleware'larni aniqlash uchun `Signature()` metodidan foydalanadi. `WithoutMiddleware` to'g'ri ishlashi uchun har bir middleware noyob imzo qaytarishiga ishonch hosil qiling. O'rnatilgan freymvork middleware'lari allaqachon noyob imzolarni taqdim etadi. +::: warning +Middleware'ni chiqarib tashlash middleware'larni aniqlash uchun `Signature()` metodidan foydalanadi. `WithoutMiddleware` to'g'ri ishlashi uchun har bir middleware noyob imzo qaytarishiga ishonch hosil qiling. O'rnatilgan freymvork middleware'lari allaqachon noyob imzolarni taqdim etadi. +::: ## So‘rovni to‘xtatish diff --git a/uz_UZ/the-basics/request.md b/uz_UZ/the-basics/request.md index 03ab6bdd2..9a5cfa7d0 100644 --- a/uz_UZ/the-basics/request.md +++ b/uz_UZ/the-basics/request.md @@ -1,7 +1,5 @@ # HTTP So‘rovlari -[[toc]] - ## Kirish Goravelning `contracts/http/Request` metodi ilova tomonidan qayta ishlangan joriy HTTP so‘rovi bilan o‘zaro aloqada bo‘lishi va birga yuborilgan kiritish ma’lumotlari va fayllarni olishi mumkin. @@ -113,7 +111,9 @@ names := ctx.Request().QueryMap("names") queries := ctx.Request().Queries() ``` -> Eslatma: Faqat bir o‘lchamli Json ma’lumotlari olinishi mumkin, aks holda bo‘sh qaytariladi. +::: warning +Faqat bir o‘lchamli Json ma’lumotlari olinishi mumkin, aks holda bo‘sh qaytariladi. +::: ### Kiritish Qiymatini Olish diff --git a/uz_UZ/the-basics/response.md b/uz_UZ/the-basics/response.md index 782221973..bb498ef7c 100644 --- a/uz_UZ/the-basics/response.md +++ b/uz_UZ/the-basics/response.md @@ -1,7 +1,5 @@ # HTTP Javobi -[[toc]] - ## Kirish Controllerda HTTP javobi uchun `ctx.Response()` dan foydalanishingiz mumkin. diff --git a/uz_UZ/the-basics/routing.md b/uz_UZ/the-basics/routing.md index 30e63af4b..e8223d480 100644 --- a/uz_UZ/the-basics/routing.md +++ b/uz_UZ/the-basics/routing.md @@ -1,7 +1,5 @@ # Marshrutlash -[[toc]] - ## Kirish Goravel marshrutlash moduli `facades.Route()` orqali boshqarilishi mumkin. @@ -185,7 +183,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **Eslatma**: Middleware'ni chiqarib tashlash middleware'larni aniqlash uchun `Signature()` metodidan foydalanadi. `WithoutMiddleware` to'g'ri ishlashi uchun har bir middleware noyob imzo qaytarishiga ishonch hosil qiling. O'rnatilgan freymvork middleware'lari allaqachon noyob imzolarni taqdim etadi. +::: warning +Middleware'ni chiqarib tashlash middleware'larni aniqlash uchun `Signature()` metodidan foydalanadi. `WithoutMiddleware` to'g'ri ishlashi uchun har bir middleware noyob imzo qaytarishiga ishonch hosil qiling. O'rnatilgan freymvork middleware'lari allaqachon noyob imzolarni taqdim etadi. +::: ## Barcha marshrutlarni olish diff --git a/uz_UZ/the-basics/session.md b/uz_UZ/the-basics/session.md index 988c657fd..f6a442b35 100644 --- a/uz_UZ/the-basics/session.md +++ b/uz_UZ/the-basics/session.md @@ -1,7 +1,5 @@ # Session -[[toc]] - ## Kirish Seans sizga bir nechta so‘rovlar bo‘yicha foydalanuvchi ma’lumotlarini saqlash imkonini beradi, bu esa tabiatan stateless HTTP protokolida holatli tajribani ta’minlaydi. Ushbu foydalanuvchi ma’lumotlari server tomonida doimiy ravishda saqlanadi. Goravel turli doimiy saqlash haydovchilari bilan o‘zaro aloqada bo‘lish uchun birlashtirilgan interfeysni taklif qiladi. diff --git a/uz_UZ/the-basics/validation.md b/uz_UZ/the-basics/validation.md index 52087d123..6e0ed62d8 100644 --- a/uz_UZ/the-basics/validation.md +++ b/uz_UZ/the-basics/validation.md @@ -1,7 +1,5 @@ # Tekshirish -[[toc]] - ## Kirish Goravel ilovangizning kiruvchi ma'lumotlarini tekshirish uchun bir nechta turli yondashuvlarni taqdim etadi. Barcha kiruvchi HTTP so'rovlarida mavjud bo'lgan `Validate` usulidan foydalanish eng keng tarqalgan usuldir. Goravel qulay tekshirish qoidalarining keng turlarini o'z ichiga oladi. diff --git a/uz_UZ/the-basics/views.md b/uz_UZ/the-basics/views.md index 6792893c3..9c200c5fd 100644 --- a/uz_UZ/the-basics/views.md +++ b/uz_UZ/the-basics/views.md @@ -1,7 +1,5 @@ # Ko‘rishlar -[[toc]] - ## Kirish Albatta, marshrutlaringiz va kontrollerlaringizdan to‘liq HTML hujjatlarini to‘g‘ridan-to‘g‘ri qaytarish amaliy emas. Yaxshiyamki, ko‘rishlar barcha HTML kodimizni alohida fayllarga joylashtirishning qulay usulini taqdim etadi. Ko‘rishlar kontroller/dastur mantiqini taqdimot mantiqidan ajratadi va ular `resources/views` katalogida saqlanadi. diff --git a/uz_UZ/upgrade/history.md b/uz_UZ/upgrade/history.md index 6e16432b3..ef70c822c 100644 --- a/uz_UZ/upgrade/history.md +++ b/uz_UZ/upgrade/history.md @@ -1,3 +1,7 @@ +--- +aside: false +--- + # Yangilash tarixi - [v1.15 dan v1.16 ga yangilash](v1.16.md) diff --git a/uz_UZ/upgrade/v1.1.md b/uz_UZ/upgrade/v1.1.md index 7722876ec..b57fb9c45 100644 --- a/uz_UZ/upgrade/v1.1.md +++ b/uz_UZ/upgrade/v1.1.md @@ -1,7 +1,5 @@ # v1.0 dan v1.1 ga yangilash -[[toc]] - ## Yuqori ta'sirli o'zgarishlar - [Bog'liqliklarni yangilash](#bog-liqliklarni-yangilash) diff --git a/uz_UZ/upgrade/v1.10.md b/uz_UZ/upgrade/v1.10.md index 6006556f9..036cec715 100644 --- a/uz_UZ/upgrade/v1.10.md +++ b/uz_UZ/upgrade/v1.10.md @@ -1,7 +1,5 @@ # v1.9 dan v1.10 ga yangilash -[[toc]] - ## Qiziqarli Yangi Imkoniyatlar 🎉 - [facades.Crypt qo'shish(1.10.0)](#bog-liqliklarni-yangilash) diff --git a/uz_UZ/upgrade/v1.11.md b/uz_UZ/upgrade/v1.11.md index 8a9f0d5d9..2af69d965 100644 --- a/uz_UZ/upgrade/v1.11.md +++ b/uz_UZ/upgrade/v1.11.md @@ -1,7 +1,5 @@ # v1.10 dan v1.11 ga yangilash -[[toc]] - ## v1.11.3 ### Xatolik tuzatishlar 🐛 diff --git a/uz_UZ/upgrade/v1.18.md b/uz_UZ/upgrade/v1.18.md index 318d4ddb1..bbb6549bd 100644 --- a/uz_UZ/upgrade/v1.18.md +++ b/uz_UZ/upgrade/v1.18.md @@ -349,7 +349,9 @@ Test diff namunasi: +s.Equal("{\"message\":{\"name\":{\"required\":\"The name field is required.\"}}}", content) ``` -> **Eslatma**: Wildcard qoidalari (masalan, `scores.*`, `tags.*`) endi hech qanday kiritish bo'lmasa ham, xato chiqishida izchil ravishda paydo bo'ladi. Agar testlaringiz to'liq xato javob tanasini tekshirsa, ular uchun tasdiqlar qo'shing. +::: warning +Wildcard qoidalari (masalan, `scores.*`, `tags.*`) endi hech qanday kiritish bo'lmasa ham, xato chiqishida izchil ravishda paydo bo'ladi. Agar testlaringiz to'liq xato javob tanasini tekshirsa, ular uchun tasdiqlar qo'shing. +::: ### 6c. O'rnatilgan qoidalar bilan ziddiyatli maxsus qoidalarni qayta nomlash @@ -620,7 +622,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **Eslatma**: Middleware chiqarib tashlash middleware-larni identifikatsiya qilish uchun `Signature()` metodidan foydalanadi. `WithoutMiddleware` to'g'ri ishlashi uchun har bir middleware noyob imzo qaytarishiga ishonch hosil qiling. O'rnatilgan framework middleware-lari allaqachon noyob imzolarni taqdim etadi. +::: warning +Middleware chiqarib tashlash middleware-larni identifikatsiya qilish uchun `Signature()` metodidan foydalanadi. `WithoutMiddleware` to'g'ri ishlashi uchun har bir middleware noyob imzo qaytarishiga ishonch hosil qiling. O'rnatilgan framework middleware-lari allaqachon noyob imzolarni taqdim etadi. +::: [Hujjatni ko'rish](../the-basics/routing.md#without-middleware) @@ -779,7 +783,9 @@ func (r *ServiceProvider) Boot(app foundation.Application) { [Hujjatni ko'rish](../the-basics/views.md#paketlardan-viewlarni-ro-yxatdan-o-tkazish) -> **Eslatma**: Agar siz bu xususiyatni fiber haydovchisida ishlatmoqchi bo'lsangiz, iltimos [Fiber haydovchi shablon konfiguratsiyasi DefaultTemplate bilan almashtirildi](#fiber-haydovchi-shablon-konfiguratsiyasi-defaulttemplate-bilan-almashtirildi) bo'limiga qarang. +::: tip +Agar siz bu xususiyatni fiber haydovchisida ishlatmoqchi bo'lsangiz, iltimos [Fiber haydovchi shablon konfiguratsiyasi DefaultTemplate bilan almashtirildi](#fiber-haydovchi-shablon-konfiguratsiyasi-defaulttemplate-bilan-almashtirildi) bo'limiga qarang. +::: ### Paket sozlash import taxalluslarini qo'llab-quvvatlaydi diff --git a/uz_UZ/upgrade/v1.4.md b/uz_UZ/upgrade/v1.4.md index b6f1b0cff..699fd312e 100644 --- a/uz_UZ/upgrade/v1.4.md +++ b/uz_UZ/upgrade/v1.4.md @@ -1,7 +1,5 @@ # v1.3 dan v1.4 ga yangilash -[[toc]] - ## Yuqori ta'sirli o'zgarishlar - [Grpc modulini optimallashtirish](#grpc-modulini-optimallashtirish) diff --git a/uz_UZ/upgrade/v1.5.md b/uz_UZ/upgrade/v1.5.md index 134b61681..78fabcc9b 100644 --- a/uz_UZ/upgrade/v1.5.md +++ b/uz_UZ/upgrade/v1.5.md @@ -1,7 +1,5 @@ # v1.4 dan v1.5 ga yangilash -[[toc]] - ## Yuqori Ta'sirli O'zgarishlar - [Fayl Saqlash Modulini Qo'shish](#fayl-saqlash-modulini-qo-shish) diff --git a/uz_UZ/upgrade/v1.6.md b/uz_UZ/upgrade/v1.6.md index db4e1cb03..10a9bf2cc 100644 --- a/uz_UZ/upgrade/v1.6.md +++ b/uz_UZ/upgrade/v1.6.md @@ -1,7 +1,5 @@ # v1.5 dan v1.6 ga yangilash -[[toc]] - ## Yuqori ta'sirli o'zgarishlar - [Avtorizatsiya modulini qo'shish](#avtorizatsiya-modulini-qo-shish) diff --git a/uz_UZ/upgrade/v1.7.md b/uz_UZ/upgrade/v1.7.md index 2feb036a4..c7ce76249 100644 --- a/uz_UZ/upgrade/v1.7.md +++ b/uz_UZ/upgrade/v1.7.md @@ -1,7 +1,5 @@ # v1.6 dan v1.7 ga yangilash -[[toc]] - ## Yuqori ta'sirli o'zgarishlar - [Validatsiya modulini qo'shish(v1.7.0)](#bog-liqliklarni-yangilash) diff --git a/uz_UZ/upgrade/v1.8.md b/uz_UZ/upgrade/v1.8.md index df7de1070..646e7f8e1 100644 --- a/uz_UZ/upgrade/v1.8.md +++ b/uz_UZ/upgrade/v1.8.md @@ -1,7 +1,5 @@ # v1.7 dan v1.8 ga yangilash -[[toc]] - ## Qiziqarli yangi imkoniyatlar 🎉 - [Orm uchun model assotsiatsiyasini qo'shish (1.8.0)](#orm-uchun-model-assotsiatsiyasini-qo-shish) diff --git a/uz_UZ/upgrade/v1.9.md b/uz_UZ/upgrade/v1.9.md index a80375677..2a59a6389 100644 --- a/uz_UZ/upgrade/v1.9.md +++ b/uz_UZ/upgrade/v1.9.md @@ -1,7 +1,5 @@ # v1.8 dan v1.9 ga yangilash -[[toc]] - ## Yaxshilanishlar 🚀 - [Ma'lumotlar bazasini o'qish-yozish ajratishini qo'shish (1.9.0)](#ma-lumotlar-bazasini-o-qish-yozish-ajratishini-qo-shish) diff --git a/zh_CN/ai/sdk.md b/zh_CN/ai/sdk.md index a555b83a9..45e9bea7e 100644 --- a/zh_CN/ai/sdk.md +++ b/zh_CN/ai/sdk.md @@ -1,7 +1,5 @@ # AI SDK -[[toc]] - ## 简介 AI SDK 为 Goravel 应用提供了一个统一的 API 来与 AI 供应商交互。它引入了 `AI` 门面、有状态对话、Agent 类、供应商/模型选项、提示附件、流式响应、图像生成、音频生成和语音转录。 diff --git a/zh_CN/architecture-concepts/facades.md b/zh_CN/architecture-concepts/facades.md index c58c0f883..fc0db49b8 100644 --- a/zh_CN/architecture-concepts/facades.md +++ b/zh_CN/architecture-concepts/facades.md @@ -1,7 +1,5 @@ # Facades -[[toc]] - ## 简介 `facades` 为应用的核心功能提供一个「静态」接口,能够提供更加灵活、更加优雅、易于测试的语法。 Goravel 的所有 `facades` 都定义在 `app/facades` 文件夹下: @@ -45,7 +43,9 @@ func Route() route.Route { } ``` -> `facades` 被暴露于应用程序中,你也可以在 `app/facades` 文件夹中创建自己的 `facades` 或覆盖现有的 `facades`。 +::: tip +`facades` 被暴露于应用程序中,你也可以在 `app/facades` 文件夹中创建自己的 `facades` 或覆盖现有的 `facades`。 +::: ## 安装/卸载 Facades @@ -65,4 +65,6 @@ func Route() route.Route { ./artisan package:uninstall Route ``` -> 注意:如果你使用 `./artisan package:install` 命令手动选择 `facades`,需要按下 `x` 选择要安装的 facades,然后按下 `Enter` 确认安装。 如果你直接按下 `Enter`,默认没有 `facades` 被选中。 +::: tip +如果你使用 `./artisan package:install` 命令手动选择 `facades`,需要按下 `x` 选择要安装的 facades,然后按下 `Enter` 确认安装。 如果你直接按下 `Enter`,默认没有 `facades` 被选中。 +::: diff --git a/zh_CN/architecture-concepts/request-lifecycle.md b/zh_CN/architecture-concepts/request-lifecycle.md index 7117c0d35..94a51d7c4 100644 --- a/zh_CN/architecture-concepts/request-lifecycle.md +++ b/zh_CN/architecture-concepts/request-lifecycle.md @@ -1,7 +1,5 @@ # 请求周期 -[[toc]] - ## 简介 了解其工作原理会让任何工具在现实世界中使用起来更加直观。 这份文档旨在为您提供一个清晰的高层次视角,了解Goravel的工作原理。 不要担心一开始不能完全理解每个术语——只需大致了解事物是如何工作的,随着你继续探索其余文档,你的专业知识将会增长。 diff --git a/zh_CN/architecture-concepts/service-container.md b/zh_CN/architecture-concepts/service-container.md index 226453541..211e58e3e 100644 --- a/zh_CN/architecture-concepts/service-container.md +++ b/zh_CN/architecture-concepts/service-container.md @@ -1,7 +1,5 @@ # 服务容器 -[[toc]] - ## 简介 Goravel的服务容器是一个功能强大的工具,用于管理类依赖和实现依赖注入。 它包含了框架所有模块,并允许你将自己的服务绑定到容器中,在需要时进行解析。 服务容器为Goravel周边的第三方包提供了有力的支持。 diff --git a/zh_CN/architecture-concepts/service-providers.md b/zh_CN/architecture-concepts/service-providers.md index 6b91501c6..d6ee0e28e 100644 --- a/zh_CN/architecture-concepts/service-providers.md +++ b/zh_CN/architecture-concepts/service-providers.md @@ -1,7 +1,5 @@ # 服务提供者 -[[toc]] - ## 简介 内核启动过程中最重要的是加载 服务提供者。 应用程序下的所有 `ServiceProvider` 都在 `bootstrap/providers.go` 文件中进行配置。 @@ -76,7 +74,7 @@ type Runner interface { } ``` -下面是一个在 `ServiceProvider` 中定义 `HTTPRunner` 的示例,用于启动和关闭 HTTP 服务器。它的签名为 `goravel:http`,意味着可以通过 [app.disabled_runners](../getting-started/configuration.md#disabled-runners) 配置选项在 `app.Start()` 中选择性地禁用它。 +下面是一个在 `ServiceProvider` 中定义 `HTTPRunner` 的示例,用于启动和关闭 HTTP 服务器。它的签名为 `goravel:http`,意味着可以通过 [app.disabled_runners](../getting-started/configuration.md#禁用-runners) 配置选项在 `app.Start()` 中选择性地禁用它。 ```go type ServiceProvider struct {} diff --git a/zh_CN/database/getting-started.md b/zh_CN/database/getting-started.md index f312f7267..837ca4dda 100644 --- a/zh_CN/database/getting-started.md +++ b/zh_CN/database/getting-started.md @@ -1,7 +1,5 @@ # 简介 -[[toc]] - ## 简介 几乎所有的应用程序都需要和数据库进行交互,Goravel 为此提供了一套非常简单易用的数据库交互方式。 开发者可以使用原生 SQL,查询构造器,以及 [Orm](../orm/getting-started) 等方式与数据库交互。 目前,Goravel 为以下四种数据库提供了官方支持: @@ -75,7 +73,9 @@ var product Product err := facades.DB().Select(&product, "SELECT * FROM products WHERE id = ?", 1) ``` -> 注意:不同数据库驱动需要使用不同的占位符。 例如:`?` 占位符适用于 MySQL,而 `@` 占位符适用于 PostgreSQL。 +::: warning +不同数据库驱动需要使用不同的占位符。 例如:`?` 占位符适用于 MySQL,而 `@` 占位符适用于 PostgreSQL。 +::: ### Insert diff --git a/zh_CN/database/migrations.md b/zh_CN/database/migrations.md index 434a4f811..cac38a935 100644 --- a/zh_CN/database/migrations.md +++ b/zh_CN/database/migrations.md @@ -1,7 +1,5 @@ # 迁移 -[[toc]] - ## 简介 当多人协作开发应用程序时,如果同步数据库结构没有一个统一的规范,以保证所有人的本地数据都是一致的,那将是灾难。数据库迁移就是为了解决这个问题,将数据库的结构进行版本控制,以保证所有开发人员的数据库结构的一致性。 不这样做,就可能出现混乱,因为每个人的数据都不会匹配。 数据库迁移 将数据库的结构进行版本控制,以保证所有开发人员的数据库结构的一致性。 @@ -53,14 +51,14 @@ func Boot() contractsfoundation.Application { 使用 `create_users_table` 将会自动生成包含 `users` 基础结构的表,实现原理是根据正则进行匹配: -``` +```text ^create_(\w+)_table$ ^create_(\w+)$ ``` 使用 `add_avatar_to_users_table` 将会自动生成向 `users` 表增加字段的结构,实现原理是根据正则进行匹配: -``` +```text _(to|from|in)_(\w+)_table$ _(to|from|in)_(\w+)$ ``` diff --git a/zh_CN/database/queries.md b/zh_CN/database/queries.md index 3b1032883..72f4aaec7 100644 --- a/zh_CN/database/queries.md +++ b/zh_CN/database/queries.md @@ -1,7 +1,5 @@ # 查询构造器 -[[toc]] - ## 简介 Goravel 的数据库查询构造器提供了一个方便的接口来创建和执行数据库查询。 它可以用于执行应用程序中的大部分数据库操作,并且可以在所有支持的数据库系统上工作。 @@ -130,7 +128,9 @@ err := facades.DB().Table("products").Chunk(2, func(rows []db.Row) error { }) ``` -> 注意:当在 Chunk 的回调中的修改记录时,可能会导致记录未包含在分块结果中。 +::: warning +当在 Chunk 的回调中的修改记录时,可能会导致记录未包含在分块结果中。 +::: ### 游标 diff --git a/zh_CN/database/seeding.md b/zh_CN/database/seeding.md index a0488949c..a03e51ecf 100644 --- a/zh_CN/database/seeding.md +++ b/zh_CN/database/seeding.md @@ -1,7 +1,5 @@ # 数据填充 -[[toc]] - ## 简介 Goravel 内置了一个可为你的数据库填充测试数据的 struct。 所有的填充 struct 都放在 `database/seeds` 目录下。 Goravel 默认定义了一个 `DatabaseSeeder` struct。 diff --git a/zh_CN/digging-deeper/artisan-console.md b/zh_CN/digging-deeper/artisan-console.md index 95f8b063a..54217c7bf 100644 --- a/zh_CN/digging-deeper/artisan-console.md +++ b/zh_CN/digging-deeper/artisan-console.md @@ -1,7 +1,5 @@ # Artisan 命令行 -[[toc]] - ## 简介 Artisan 是 Goravel 自带的命令行工具。 该模块可以使用 `facades.Artisan()` 进行操作。 它提供了许多有用的命令,这些命令可以在构建应用时为你提供帮助。 你可以通过命令查看所有可用的 Artisan 命令。 @@ -92,7 +90,9 @@ func Boot() contractsfoundation.Application { - **返回 `[]string{}`**——删除所有命令。 - **返回条目**——仅保留签名与某个条目匹配的命令。 -> 注意:过滤器适用于所有命令,包括通过 `WithCommands` 添加的命令,因此用户无法通过手动添加命令来绕过过滤器。 +::: info +过滤器适用于所有命令,包括通过 `WithCommands` 添加的命令,因此用户无法通过手动添加命令来绕过过滤器。 +::: ### 命令结构 @@ -634,9 +634,11 @@ func (receiver *ConsoleMakeCommand) Extend() command.Extend { 有时你可能希望在 CLI 之外执行 Artisan 命令,可以使用 `facades.Artisan()` 上的 `Call` 方法来完成此操作。 ```go -facades.Route().GET("/", func(c *gin.Context) { +facades.Route().Get("/", func(ctx http.Context) http.Response { facades.Artisan().Call("emails") facades.Artisan().Call("emails --lang Chinese name") // 携带参数与选项 + + return ctx.Response().Success().String("done") }) ``` diff --git a/zh_CN/digging-deeper/cache.md b/zh_CN/digging-deeper/cache.md index a556d0690..f09d727c0 100644 --- a/zh_CN/digging-deeper/cache.md +++ b/zh_CN/digging-deeper/cache.md @@ -1,7 +1,5 @@ # 缓存系统 -[[toc]] - ## 简介 Goravel 提供了可拓展的缓存模块,该模块可以使用 `facades.Cache()` 进行操作。 框架默认自带 `memory` 驱动,如需其他驱动,请查看对应的独立扩展包: @@ -14,6 +12,15 @@ Goravel 提供了可拓展的缓存模块,该模块可以使用 `facades.Cache 在 `config/cache.go` 中进行所有自定义配置。 +### 缓存键前缀 + +`prefix` 配置会添加到每个缓存键之前,避免多个应用共用同一缓存存储时发生键冲突。 前缀为 `goravel_cache` 时,键 `users` 会存储为 `goravel_cache:users`。 前缀为空时,键按原样存储。 + +```go +// config/cache.go +"prefix": config.GetString("APP_NAME", "goravel") + "_cache", +``` + ## 使用缓存 ### 注入 Context diff --git a/zh_CN/digging-deeper/collections.md b/zh_CN/digging-deeper/collections.md index 27f228246..8fab5d5d8 100644 --- a/zh_CN/digging-deeper/collections.md +++ b/zh_CN/digging-deeper/collections.md @@ -1,7 +1,5 @@ # 集合 -[[toc]] - ## 简介 Goravel 通过 `github.com/goravel/framework/support/collect` 包提供了流畅的集合 API。集合可以方便地使用链式方法来过滤、转换、聚合和检查切片数据。 diff --git a/zh_CN/digging-deeper/color.md b/zh_CN/digging-deeper/color.md index bc9041a5f..b808a682f 100644 --- a/zh_CN/digging-deeper/color.md +++ b/zh_CN/digging-deeper/color.md @@ -1,7 +1,5 @@ # Color -[[toc]] - ## 简介 `color` 包提供一系列的方法以便在控制台上输出带颜色的内容,该功能由 [PTerm](https://github.com/pterm/pterm) 提供驱动。 diff --git a/zh_CN/digging-deeper/event.md b/zh_CN/digging-deeper/event.md index ab5cbb974..98a4ecb91 100644 --- a/zh_CN/digging-deeper/event.md +++ b/zh_CN/digging-deeper/event.md @@ -1,7 +1,5 @@ # 事件系统 -[[toc]] - ## 简介 Goravel 的事件系统提供了一个简单的观察者模式的实现,允许你能够订阅和监听在你的应用中的发生的各种事件。 事件类一般来说存储在 `app/events` 目录,监听者的类存储在 `app/listeners` 目录。 不要担心在你的应用中没有看到这两个目录,因为通过 Artisan 命令行来创建事件和监听者的时候目录会同时被创建。 diff --git a/zh_CN/digging-deeper/filesystem.md b/zh_CN/digging-deeper/filesystem.md index 5b049349b..20b924070 100644 --- a/zh_CN/digging-deeper/filesystem.md +++ b/zh_CN/digging-deeper/filesystem.md @@ -1,7 +1,5 @@ # 文件存储 -[[toc]] - ## 简介 Goravel 为使用本地文件系统、Amazon S3、Aliyun OSS、Tencent COS、Minio 和 Cloudinary 提供了简单易用的驱动程序。 更棒的是,由于每个系统的 API 保持不变,所以在这些存储选项之间切换是非常简单的。 框架自带 `local` 驱动,如需其他驱动,请查看对应的独立扩展包: @@ -17,7 +15,9 @@ Goravel 为使用本地文件系统、Amazon S3、Aliyun OSS、Tencent COS、Min 配置文件位于 `config/filesystems.go`。 在这个文件中你可以配置所有的「磁盘」,每个磁盘代表特定的存储驱动及存储位置。 -> 技巧:你可以配置任意数量的磁盘,甚至可以添加多个使用相同驱动的磁盘。 +::: tip +你可以配置任意数量的磁盘,甚至可以添加多个使用相同驱动的磁盘。 +::: ### 本地驱动 @@ -87,7 +87,9 @@ if (facades.Storage().Disk("s3").Missing("file.jpg")) { url := facades.Storage().Url("file.jpg") ``` -> 注意:当使用 `local` 驱动时, `Url` 的返回值不是 url 编码的。 因此,我们建议总是使用可以创建有效 url 的名称来存储文件。 +::: warning +当使用 `local` 驱动时, `Url` 的返回值不是 url 编码的。 因此,我们建议总是使用可以创建有效 url 的名称来存储文件。 +::: #### 临时地址 @@ -212,7 +214,9 @@ file, err := filesystem.NewFile("./logo.png") path := facades.Storage().PutFileAs("photos", file, "name") ``` -> `StoreAs` 与 `PutFileAs` 指定的文件名如果不带后缀,将根据文件的 MIME 自动添加后缀;否则,直接使用指定的文件名。 +::: info +`StoreAs` 与 `PutFileAs` 指定的文件名如果不带后缀,将根据文件的 MIME 自动添加后缀;否则,直接使用指定的文件名。 +::: ### 指定一个磁盘 @@ -337,4 +341,6 @@ type Driver interface { } ``` -> 注意:由于注册自定义驱动时配置信息尚未加载完毕,所以在自定义驱动中,请使用 `facades.Config().Env()` 获取配置信息。 +::: warning +由于注册自定义驱动时配置信息尚未加载完毕,所以在自定义驱动中,请使用 `facades.Config().Env()` 获取配置信息。 +::: diff --git a/zh_CN/digging-deeper/helpers.md b/zh_CN/digging-deeper/helpers.md index dc0a48988..8e3d0a024 100644 --- a/zh_CN/digging-deeper/helpers.md +++ b/zh_CN/digging-deeper/helpers.md @@ -1,7 +1,5 @@ # Helpers -[[toc]] - ## 可用方法 ### 路径 diff --git a/zh_CN/digging-deeper/http-client.md b/zh_CN/digging-deeper/http-client.md index 8055a083b..f165bf260 100644 --- a/zh_CN/digging-deeper/http-client.md +++ b/zh_CN/digging-deeper/http-client.md @@ -1,7 +1,5 @@ # HTTP 客户端 -[[toc]] - ## 简介 在软件开发中,有很多时候你需要调用 API 来获取数据——无论是连接到微服务还是访问第三方 API。 在这种情况下,Goravel 提供了一个易于使用、富有表现力且极简的 API,它基于标准的 `net/http` 库构建,所有这些都旨在提升开发者的体验。 @@ -158,11 +156,11 @@ response, err := facades.Http(). Get("https://api.example.com") ``` -为了方便起见,你可以使用 `AcceptJson` 快速指定你期望 API 响应为 `application/json` 格式: +为了方便起见,你可以使用 `AcceptJSON` 快速指定你期望 API 响应为 `application/json` 格式: ```go response, err := facades.Http(). - AcceptJson(). + AcceptJSON(). Get("https://api.example.com/data") ``` @@ -209,7 +207,7 @@ response, err := facades.Http(). Get("https://api.example.com/api/resource") ``` -:::tip +::: tip `WithToken` 方法还接受一个可选的第二个参数,用于指定令牌类型(例如,“Bearer”、“Token”)。 如果未提供类型,则默认为“Bearer”。 @@ -253,7 +251,7 @@ type User struct { func main() { var user User - response, err := facades.Http().AcceptJson().Get("https://jsonplaceholder.typicode.com/users/1") + response, err := facades.Http().AcceptJSON().Get("https://jsonplaceholder.typicode.com/users/1") if err != nil { fmt.Println("Error making request:", err) return @@ -459,7 +457,7 @@ func TestExternalApi(t *testing.T) { } ``` -:::warning 全局状态与并行测试 +::: warning 全局状态与并行测试 `Fake` 和 `Reset` 方法会改变 HTTP 客户端的全局状态。 因此,**你应该避免并行运行模拟 HTTP 客户端的测试**(`t.Parallel()`)。 这样做可能会导致竞态条件,即一个测试重置模拟时,另一个测试仍在运行。 ::: diff --git a/zh_CN/digging-deeper/localization.md b/zh_CN/digging-deeper/localization.md index a4955c1ed..01777c73e 100644 --- a/zh_CN/digging-deeper/localization.md +++ b/zh_CN/digging-deeper/localization.md @@ -1,14 +1,12 @@ # 本地化 -[[toc]] - ## 简介 Goravel 的本地化功能提供了一种方便的方法来检索各种语言的字符串,从而使你可以轻松地在应用程序中支持多种语言。 语言字符串存储在 `lang` 目录里的文件中,Goravel 支持两种方式组织语言文件: 每一种语言文件独立一个文件: -``` +```text /lang en.json cn.json @@ -16,7 +14,7 @@ Goravel 的本地化功能提供了一种方便的方法来检索各种语言的 或者当语言过多时,可以对其进行分类: -``` +```text /lang /en user.json @@ -40,7 +38,7 @@ facades.Route().Get("/", func(ctx http.Context) http.Response { 你可以配置一个「备用语言」,当当前语言不包含给定的翻译字符串时,将使用该语言。 和默认语言一样,备用语言也是在 `config/app.go` 配置文件中配置。 -``` +```go "fallback_locale": "en", ``` @@ -48,7 +46,7 @@ facades.Route().Get("/", func(ctx http.Context) http.Response { 你可以使用 `CurrentLocale` 和 `IsLocale` 方法来确定当前的 `locale` 或检查 `locale` 是否是一个给定值。 -``` +```go locale := facades.App().CurrentLocale(ctx) if facades.App().IsLocale(ctx, "en") {} ``` @@ -73,7 +71,7 @@ if facades.App().IsLocale(ctx, "en") {} 例如: -``` +```json // lang/en.json { "name": "It's your name", @@ -143,7 +141,7 @@ facades.Lang(ctx).Choice("messages.apples", 10) 也可以在复数化字符串中定义占位符属性。 通过将数组作为第三个参数传递给 `facades.Lang(ctx).Choice()` 方法,可以替换这些占位符: -``` +```go "minutes_ago": "{1} :value minute ago|[2,*] :value minutes ago", facades.Lang(ctx).Choice("time.minutes_ago", 5, translation.Option{ @@ -159,7 +157,7 @@ facades.Lang(ctx).Choice("time.minutes_ago", 5, translation.Option{ 在多语言文件同级目录下创建一个 `fs.go` 文件: -``` +```text /lang en.json cn.json diff --git a/zh_CN/digging-deeper/mail.md b/zh_CN/digging-deeper/mail.md index 68b0987af..e60e9334a 100644 --- a/zh_CN/digging-deeper/mail.md +++ b/zh_CN/digging-deeper/mail.md @@ -1,7 +1,5 @@ # 发送邮件 -[[toc]] - ## 简介 Goravel 可以使用 `facades.Mail()` 便捷的在本地发送邮件。 diff --git a/zh_CN/digging-deeper/package-development.md b/zh_CN/digging-deeper/package-development.md index e15b7831f..f300525bc 100644 --- a/zh_CN/digging-deeper/package-development.md +++ b/zh_CN/digging-deeper/package-development.md @@ -1,7 +1,5 @@ # 扩展包开发 -[[toc]] - ## 简介 包是向 Goravel 添加功能的主要方式。 这些包可能包含专门用于增强 Goravel 应用程序的路由、控制器和配置。 本指南主要涵盖了那些特定于 Goravel 的包的开发。 diff --git a/zh_CN/digging-deeper/pluralization.md b/zh_CN/digging-deeper/pluralization.md index c20d49e3d..f4c0b8500 100644 --- a/zh_CN/digging-deeper/pluralization.md +++ b/zh_CN/digging-deeper/pluralization.md @@ -1,7 +1,5 @@ # 复数 -[[toc]] - ## 介绍 字符串对于任何 Web 应用程序都很重要。 Goravel 提供了简单的工具在单数和复数形式之间转换单词。 它默认支持**英语**,但你可以轻松添加其他语言或自定义规则。 @@ -26,7 +24,7 @@ pluralizer.Singular("cars") // "car" 有时默认规则不足以处理特定单词。 Goravel 允许你添加自己的规则来处理这些情况。 -:::warning +::: warning 添加规则会全局改变复数化的工作方式。 你应该在应用程序启动时执行此操作,例如在服务提供者的 `Boot` 方法中。 ::: diff --git a/zh_CN/digging-deeper/processes.md b/zh_CN/digging-deeper/processes.md index 3c7e6eee3..58aa00384 100644 --- a/zh_CN/digging-deeper/processes.md +++ b/zh_CN/digging-deeper/processes.md @@ -1,7 +1,5 @@ # 进程 -[[toc]] - ## 介绍 Goravel 围绕 Go 标准 `os/exec` 包提供了一个富有表现力且优雅的 API,允许你从应用程序中无缝调用外部命令。 默认情况下,Go 的进程处理可能很冗长;Goravel 的 `Process` facade 简化了这一常见任务,为执行命令、处理输出和管理异步进程提供了流畅的接口。 @@ -166,7 +164,7 @@ result := facades.Process().Pipe(func(pipe process.Pipe) { }).Run() ``` -:::warning +::: warning 诸如 `Timeout`、`Env` 或 `Input` 之类的进程选项必须在调用 `Pipe` 方法**之后**进行配置。 在 `Pipe` 调用之前应用的任何配置都将被忽略。 @@ -225,7 +223,7 @@ case <-time.After(1 * time.Second): result := running.Wait() ``` -:::warning +::: warning 即使你使用 `Done` 通道来检测完成,之后也**必须**调用 `Wait()`。 这确保进程被操作系统正确“捕获”并清理底层资源。 ::: @@ -273,7 +271,7 @@ if running.Running() { } ``` -:::tip +::: tip 如果你需要在进程完成时执行代码,请勿轮询 `Running()`。 请使用 `Done()` 通道或 `Wait()` 方法,这比重复检查状态要高效得多。 ::: @@ -374,7 +372,7 @@ case <-time.After(10 * time.Second): 可以使用 `OnOutput` 方法实时检查池的输出。 -:::warning +::: warning `OnOutput` 回调可能会从多个 goroutine 并发调用。 确保你的回调逻辑是线程安全的。 ::: diff --git a/zh_CN/digging-deeper/queues.md b/zh_CN/digging-deeper/queues.md index 74fa2f54b..4f292a934 100644 --- a/zh_CN/digging-deeper/queues.md +++ b/zh_CN/digging-deeper/queues.md @@ -1,7 +1,5 @@ # 队列 -[[toc]] - ## 简介 在构建 Web 应用程序时,你可能需要执行一些比较耗时的任务(例如解析和存储上传的 CSV 文件)。 Goravel 可以让你轻松地创建可在后台排队处理的任务。 通过将耗时的任务移到队列中,你的应用程序可以以超快的速度响应 Web 请求,并为客户提供更好的用户体验。 我们使用 `facades.Queue()` 实现这些功能。 @@ -44,7 +42,7 @@ err := facades.Queue().Job(&jobs.Test{}, []queue.Arg{ 自定义驱动实现后,可以添加配置到 `config/queue.go` 中: -``` +```go ... "connections": map[string]any{ "redis": map[string]any{ diff --git a/zh_CN/digging-deeper/strings.md b/zh_CN/digging-deeper/strings.md index c72cdf9f6..deadfe17e 100644 --- a/zh_CN/digging-deeper/strings.md +++ b/zh_CN/digging-deeper/strings.md @@ -1,7 +1,5 @@ # Strings -[[toc]] - ## 简介 Goravel 提供了一个流畅的字符串操作库,允许你轻松地操作字符串。 可以使用 `String` 方法创建一个 `string` 实例,允许你调用各种方法,每个方法都会返回当前字符串实例,允许你将多个方法链接在一起。 要在应用链式操作后获得最终字符串值,你可以调用 `String` 方法,返回底部的 `string` 值。 diff --git a/zh_CN/digging-deeper/task-scheduling.md b/zh_CN/digging-deeper/task-scheduling.md index c016981f4..277ef143c 100644 --- a/zh_CN/digging-deeper/task-scheduling.md +++ b/zh_CN/digging-deeper/task-scheduling.md @@ -1,7 +1,5 @@ # 任务调度 -[[toc]] - ## 简介 过去,你可能需要在服务器上为每一个调度任务去创建 Cron 条目。 因为这些任务的调度不是通过代码控制的,你要查看或新增任务调度都需要通过 SSH 远程登录到服务器上去操作,所以这种方式很快会让人变得痛苦不堪。 @@ -101,7 +99,9 @@ facades.Schedule().Command("send:emails name").EveryMinute().DelayIfStillRunning ### 任务只运行在一台服务器上 -> 要使用此功能,你的应用程序必须使用 memcached, dynamodb, 或 redis 缓存驱动程序作为应用程序的默认缓存驱动程序。 此外,所有服务器必须和同一个中央缓存服务器通信。 +::: warning +此功能会在默认缓存中加锁,因此所有服务器必须共享同一个缓存。 请使用 [redis](./cache.md) 等共享驱动作为默认缓存驱动。 `memory` 驱动无法使用,因为每台服务器各自独立。 +::: 如果你的应用运行在多台服务器上,可能需要限制调度任务只在某台服务器上运行。 例如,假设你有一个每个星期五晚上生成新报告的调度任务。 如果任务调度器运行在三台服务器上,调度任务会在三台服务器上运行并且生成三次报告。 不够优雅! diff --git a/zh_CN/digging-deeper/telemetry.md b/zh_CN/digging-deeper/telemetry.md index d4825a8e8..7afdede1d 100644 --- a/zh_CN/digging-deeper/telemetry.md +++ b/zh_CN/digging-deeper/telemetry.md @@ -1,7 +1,5 @@ # Telemetry -[[toc]] - ## 简介 Goravel 提供了基于 [OpenTelemetry](https://opentelemetry.io) 构建的可观测性模块,可通过 `facades.Telemetry()` 操作。它允许你从应用程序中收集追踪、指标和日志,并将其导出到任何兼容 OTLP 的后端,如 Jaeger、Prometheus、Grafana 或 Datadog。 diff --git a/zh_CN/getting-started/compile.md b/zh_CN/getting-started/compile.md index 1540d5ced..86facd770 100644 --- a/zh_CN/getting-started/compile.md +++ b/zh_CN/getting-started/compile.md @@ -1,7 +1,5 @@ # 编译 -[[toc]] - ## 编译命令 Goravel 项目可以通过以下命令编译: @@ -47,7 +45,7 @@ go build . 部署时需要将下列文件与文件夹上传至服务器: -``` +```text .env ./main // 编译生成的二进制文件 ./public // 如果存在 @@ -67,13 +65,13 @@ go build --ldflags "-extldflags -static" -o main . 编译有平台区分,需要根据部署情况,选择匹配的编译方式。 ```shell -// 编译 Linux 环境 +# 编译 Linux 环境 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build . -// 编译 Windows 环境 +# 编译 Windows 环境 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build . -// 编译 Mac 环境 +# 编译 Mac 环境 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build . ``` @@ -126,7 +124,9 @@ docker-compose build docker-compose up ``` -> 注意:如需外部访问,需要将 APP_HOST 改为 0.0.0.0 +::: tip +如需外部访问,需要将 APP_HOST 改为 0.0.0.0 +::: ## 设置时区 @@ -134,13 +134,13 @@ docker-compose up 1. 在 Dockerfile 中添加时区设置 -``` +```dockerfile RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone ``` 2. 在编译时设置时区 -``` +```shell go build -tags timetzdata . ``` diff --git a/zh_CN/getting-started/configuration.md b/zh_CN/getting-started/configuration.md index 50b47986e..dfefdb119 100644 --- a/zh_CN/getting-started/configuration.md +++ b/zh_CN/getting-started/configuration.md @@ -1,7 +1,5 @@ # 配置信息 -[[toc]] - ## 简介 Goravel 框架所有配置文件都保存在 `config` 目录中。 你可以进入具体文件查看配置说明,根据项目需要灵活配置。 @@ -12,7 +10,9 @@ Goravel 框架所有配置文件都保存在 `config` 目录中。 你可以进 因此,框架在根目录提供了 `.env.example` 文件。 需要你在开发前,复制该文件并重命名为 `.env`,根据项目需要修改 `.env` 文件中的配置项。 -注意,`.env` 文件不应该加入版本控制,因为多人协作时,不同的开发人员有可能使用不同的配置,不同的部署环境配置也不相同。 +::: warning +`.env` 文件不应该加入版本控制,因为多人协作时,不同的开发人员有可能使用不同的配置,不同的部署环境配置也不相同。 +::: 此外,如果有入侵者获得了你的代码仓库访问权限,将会有暴露敏感配置的风险。 如果你想新增新的配置项,可以添加到 `.env.example` 文件中,以此来同步所有开发者的配置。 diff --git a/zh_CN/getting-started/directory-structure.md b/zh_CN/getting-started/directory-structure.md index 49ef7a65e..7c1680714 100644 --- a/zh_CN/getting-started/directory-structure.md +++ b/zh_CN/getting-started/directory-structure.md @@ -1,14 +1,12 @@ # 文件夹结构 -[[toc]] - ## 简介 默认的文件结构可以使你更好的开始项目推进,你也可以自由的新增文件夹,但默认文件夹不要修改。 ## 文件树 -``` +```text goravel/ ├── app/ # 核心应用逻辑 │ ├── ai/ # AI 代理和工具 diff --git a/zh_CN/getting-started/installation.md b/zh_CN/getting-started/installation.md index a4b011f97..81ceb3aaa 100644 --- a/zh_CN/getting-started/installation.md +++ b/zh_CN/getting-started/installation.md @@ -1,10 +1,8 @@ # 安装 -[[toc]] - ## 服务要求 -- Golang >= 1.23 +- Golang >= 1.25 ## 安装 Goravel @@ -13,13 +11,15 @@ 根据[文档](https://github.com/goravel/installer)初始化安装器,然后使用下面命令初始化一个新的 Goravel 项目: ```shell -// 安装最新版本的 goravel 安装器 +# 安装最新版本的 goravel 安装器 go install github.com/goravel/installer/goravel@latest -// 输入您想要安装项目 +# 输入您想要安装项目 goravel new blog ``` +安装器会询问使用哪个模板:完整框架,或仅包含核心 facades 的 [Goravel Lite](#goravel-goravel-lite)。 + ### 手动安装 #### goravel/goravel @@ -27,16 +27,16 @@ goravel new blog 包含所有 facades 的全功能框架。 ```shell -// 下载框架 +# 下载框架 git clone --depth=1 https://github.com/goravel/goravel.git && rm -rf goravel/.git* -// 安装依赖 +# 安装依赖 cd goravel && go mod tidy -// 创建 .env 环境配置文件 +# 创建 .env 环境配置文件 cp .env.example .env -// 生成应用密钥 +# 生成应用密钥 ./artisan key:generate ``` @@ -45,23 +45,24 @@ cp .env.example .env 仅包含核心功能的轻量级框架,适合构建微服务或小型应用。 你可以根据需要安装额外的 facades。 ```shell -// 下载框架 +# 下载框架 git clone --depth=1 https://github.com/goravel/goravel-lite.git && rm -rf goravel-lite/.git* -s -// 安装依赖 +# 安装依赖 cd goravel-lite && go mod tidy -// 创建 .env 环境配置文件 +# 创建 .env 环境配置文件 cp .env.example .env -// 生成应用密钥 +# 生成应用密钥 ./artisan key:generate -// 根据需要安装额外的 facades,例如: +# 根据需要安装额外的 facades,例如: ./artisan package:install Cache ``` -> 如果安装依赖较慢,请使用国内代理,[详见文章](https://learnku.com/go/wikis/38122)。 +::: tip +如果安装依赖较慢,请使用国内代理,[详见文章](https://learnku.com/go/wikis/38122)。 +::: ## 启动服务 @@ -87,19 +88,17 @@ APP_ENV=production APP_DEBUG=true go run . 安装 [airverse/air] (https://github.com/air-verse/air), Goravel 有一个内置的配置文件,可以直接使用: -``` +```shell air ``` -#### 🧰 安装 Air 后 +#### 安装 Air 后 安装了 Air 成功后,你需要确保它能够在你的环境中正确执行。 根据你的环境设置,Air 可能不能自动成为一个有效的命令。 以下是确保正确运行的两种简单方式: ---- - -#### 🪄 选项 1: 使用一个 Helper 脚本 (`air.sh`) +#### 选项 1: 使用一个 Helper 脚本 (`air.sh`) 如果 Air 已安装但无法被识别为一个终端命令,你可以创建一个脚本,自动定位和运行它。 @@ -135,7 +134,7 @@ $GO_BIN 这样会确保 Air 正常运行即使你的 `$PATH` 中没有包含 Go 软件库。 -#### 💡 选项2:将Go Bin 添加到PATH (Mac/Linux) +#### 选项 2:将Go Bin 添加到PATH (Mac/Linux) 如果你喜欢在没有脚本的情况下直接运行 air,你可以添加 Go bin 目录到你的 PATH。 @@ -152,8 +151,7 @@ source ~/.zshrc air ``` -#### ✅ 提示 - +::: tip 要验证 air 已安装并可被执行,可以运行: ```bash @@ -161,6 +159,7 @@ which air ``` 如果它没有返回一个有效的路径(例如`/Users/yourname/go/bin/air`),它意味着帮助脚本或路径尚未配置。 +::: ## 配置 @@ -191,7 +190,7 @@ Goravel 安装到本地后,要生成应用程序的密钥。 运行下面命 ```shell ./artisan env:encrypt -// 指定文件名与秘钥 +# 指定文件名与秘钥 ./artisan env:encrypt --name .env.safe --key BgcELROHL8sAV568T7Fiki7krjLHOkUc ``` @@ -200,6 +199,6 @@ Goravel 安装到本地后,要生成应用程序的密钥。 运行下面命 ```shell GORAVEL_ENV_ENCRYPTION_KEY=BgcELROHL8sAV568T7Fiki7krjLHOkUc ./artisan env:decrypt -// 或者 +# 或者 ./artisan env:decrypt --name .env.safe --key BgcELROHL8sAV568T7Fiki7krjLHOkUc ``` diff --git a/zh_CN/getting-started/packages.md b/zh_CN/getting-started/packages.md index 2254126d1..1f1e04d7e 100644 --- a/zh_CN/getting-started/packages.md +++ b/zh_CN/getting-started/packages.md @@ -1,8 +1,12 @@ +--- +aside: false +--- + # 优秀扩展包 你可以在这里寻找 Goravel 扩展包,你也可以为 [goravel/docs](https://github.com/goravel/docs) 创建一个 PR 将自己的扩展包添加到这里,请尽可能提高包的测试覆盖率。 -| 包 | 介绍 | 测试覆盖率\* | +| 包 | 介绍 | 测试覆盖率 | | --------------------------------------------------------------------------------------- | ------------------------------- | --------------------- | | [goravel/gin](https://github.com/goravel/gin) | `facades.Route()` 模块 Gin 驱动 | 83.1% | | [goravel/fiber](https://github.com/goravel/fiber) | `facades.Route()` 模块 Fiber 驱动 | 81.0% | @@ -17,8 +21,8 @@ | [goravel/anthropic](https://github.com/goravel/anthropic) | `facades.AI()` 模块 Anthropic 驱动 | 73.3% | | [goravel/mysql](https://github.com/goravel/mysql) | MySQL 数据库驱动 | 73.3% | | [goravel/sqlserver](https://github.com/goravel/sqlserver) | Sqlserver 数据库驱动 | 60.6% | -| [goravel/sqlite](https://github.com/goravel/sqlite) | Sqlite 数据库驱动 | 45.2% | | [goravel/gemini](https://github.com/goravel/gemini) | `facades.AI()` 模块 Gemini 驱动 | 51.8% | +| [goravel/sqlite](https://github.com/goravel/sqlite) | Sqlite 数据库驱动 | 45.2% | | [portofolio-mager/goravel-mongodb](https://github.com/portofolio-mager/goravel-mongodb) | MongoDB 包 | 16.9% | | [hulutech-web/goravel-kit-cli](https://github.com/hulutech-web/goravel-kit-cli) | Goravel Scaffold 命令行工具 | 15.2% | | [hulutech-web/goravel-workflow](https://github.com/hulutech-web/goravel-workflow) | 工作流 | 4.4% | @@ -26,13 +30,16 @@ | [hulutech-web/tinker](https://github.com/hulutech-web/tinker) | Tinker | 3.6% | | [hulutech-web/goravel-socket](https://github.com/hulutech-web/goravel-socket) | WebSocket | 0% | -\***注意**:软件包根据其测试覆盖率排序。 +::: info +扩展包按测试覆盖率排序。 +::: -💡 提示:为帮助更多开发者发现你的包,你还可以向仓库添加相关主题。 -推荐主题:[`goravel-package`](https://github.com/topics/goravel-package) +::: tip 让更多开发者发现你的扩展包 +为你的仓库添加 [`goravel-package`](https://github.com/topics/goravel-package) 主题。 -- 在 GitHub 上,导航至仓库的主页。 -- 在页面右上角,“关于”右侧,点击齿轮图标(设置)。 -- 在“主题”下,开始输入你想添加到仓库的主题,以显示匹配主题的下拉菜单。 -- 点击你想添加的主题,或输入以创建新主题。 例如:`goravel-package`、`goravel` 及其他相关关键词。 -- 点击 `保存更改` — 这将使你的软件包更易被发现。 +1. 在 GitHub 上,导航至仓库的主页。 +2. 在页面右上角,“关于”右侧,点击齿轮图标(设置)。 +3. 在“主题”下,开始输入你想添加到仓库的主题,以显示匹配主题的下拉菜单。 +4. 点击你想添加的主题,或输入以创建新主题。 例如:`goravel-package`、`goravel` 及其他相关关键词。 +5. 点击 `保存更改` — 这将使你的软件包更易被发现。 +::: diff --git a/zh_CN/index.md b/zh_CN/index.md index e7afa645c..ea667d6b5 100644 --- a/zh_CN/index.md +++ b/zh_CN/index.md @@ -1,150 +1,21 @@ --- -layout: home -title: Goravel - 全功能 Golang 开发框架 +title: Goravel - 熟悉的结构,原生的 Go head: - - [ 'meta', { name: description, content: Goravel 是一个 Golang 开发框架,具有完整功能和卓越的可扩展性。 作为起始脚手架帮助 Gopher 快速构建自己的应用。 } ] + - [ 'meta', { name: description, content: Goravel 是一个拥有 Laravel 结构的 Go Web 框架。路由、ORM、队列、任务调度、邮件、认证与测试,尽在一个框架之中。 } ] - [ 'meta', { property: og:url, content: https://www.goravel.dev } ] - [ 'meta', { property: og:type, content: website } ] - - [ 'meta', { property: og:title, content: Goravel - 全功能 Golang 开发框架 } ] - - [ 'meta', { property: og:description, content: Goravel 是一个 Golang 开发框架,具有完整功能和卓越的可扩展性。 作为起始脚手架帮助 Gopher 快速构建自己的应用。 } ] + - [ 'meta', { property: og:title, content: Goravel - 熟悉的结构,原生的 Go } ] + - [ 'meta', { property: og:description, content: Goravel 是一个拥有 Laravel 结构的 Go Web 框架。路由、ORM、队列、任务调度、邮件、认证与测试,尽在一个框架之中。 } ] - [ 'meta', { property: og:image, content: https://www.goravel.dev/meta.png } ] - [ 'meta', { name: twitter:card, content: summary_large_image } ] - [ 'meta', { property: twitter:domain, content: www.goravel.dev } ] - [ 'meta', { property: twitter:url, content: https://www.goravel.dev } ] - - [ 'meta', { name: twitter:title, content: Goravel - 全功能 Golang 开发框架 } ] - - [ 'meta', { name: twitter:description, content: Goravel 是一个 Golang 开发框架,具有完整功能和卓越的可扩展性。 作为起始脚手架帮助 Gopher 快速构建自己的应用。 } ] + - [ 'meta', { name: twitter:title, content: Goravel - 熟悉的结构,原生的 Go } ] + - [ 'meta', { name: twitter:description, content: Goravel 是一个拥有 Laravel 结构的 Go Web 框架。路由、ORM、队列、任务调度、邮件、认证与测试,尽在一个框架之中。 } ] - [ 'meta', { name: twitter:image, content: https://www.goravel.dev/meta.png } ] -hero: - name: Goravel - text: 全功能 Golang 开发框架 - tagline: 模块化、高性能、易扩展,PHPers 的首选。 - # image: /logo.svg - actions: - - theme: brand - text: 快速开始 - link: /zh_CN/getting-started/installation - - theme: alt - text: 🌟 Github Star - link: https://github.com/goravel/goravel - target: _blank -features: - - title: 🧰 轻量 or 全功能 - details: 你可以在轻量与全功能版本间进行选择,轻量版本仅包含基础功能,全功能版本包括对象关系映射(ORM)、HTTP、日志记录、缓存等其他所有开发所需的功能。 - - title: 💻 模块化 - details: 模块化设计,每个模块独立且可单独使用,使开发和维护更加便捷。 - - title: 🚀 高性能 - details: 使用 Golang 构建,整合多种优秀扩展来创建快速且响应灵敏的应用程序。 - - title: 📈 易扩展 - details: 模块提供多种驱动,且可根据需求开发扩展包,适合任何规模的应用程序,从小型项目到大型系统。 - - title: 👥 活跃的社区 - details: 由活跃的社区支持,他们为其开发、撰写文档和持续支持做出贡献。 - - title: 🔄 PHPers 过渡首选 - details: 框架风格与 Laravel 保持一致,让 PHPer 不用学习新的框架即可创建强大的 Golang 应用程序。 致敬 Laravel! +layout: goravel-home +sidebar: false +aside: false --- - -
贡献者
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
群组
-
- -
- -
微信入群,请备注 Goravel
-
- -
- - - -
点击我加入 Discord
-
- -
-
- -
-
打赏
-
- -
- -
微信扫码
-
- - -
-
- - diff --git a/zh_CN/orm/factories.md b/zh_CN/orm/factories.md index 832941422..d194b798c 100644 --- a/zh_CN/orm/factories.md +++ b/zh_CN/orm/factories.md @@ -1,7 +1,5 @@ # 模型工厂 -[[toc]] - ## 介绍 测试时你可能需要在执行测试之前向数据库中插入一些记录。 Goravel 允许你使用模型工厂为每个模型定义一组默认属性,而不是在创建测试数据时手动指定每一列的值。 @@ -28,7 +26,7 @@ func (f *UserFactory) Definition() map[string]any { 可以使用 Artisan 命令 `make:factory` 创建工厂: -``` +```shell go run . artisan make:factory PostFactory ``` diff --git a/zh_CN/orm/getting-started.md b/zh_CN/orm/getting-started.md index 47dbc5989..493f69949 100644 --- a/zh_CN/orm/getting-started.md +++ b/zh_CN/orm/getting-started.md @@ -1,7 +1,5 @@ # 快速入门 -[[toc]] - ## 简介 Goravel 提供了一套非常简单易用的数据库交互方式,开发者可以使用 `facades.Orm()` 进行操作。 在开始之前请先[配置数据库](../database/getting-started)。 @@ -99,7 +97,7 @@ func (r *UserData) Scan(value any) (err error) { ```shell ./artisan make:model --table=users User -// 如果 Model 已存在可以使用 -f 选项强制覆盖 +# 如果 Model 已存在可以使用 -f 选项强制覆盖 ./artisan make:model --table=users -f User ``` @@ -250,7 +248,7 @@ facades.Orm().Query().WithoutGlobalScopes("name").Get(&users) | DB | [获取通用数据库接口](#获取通用数据库接口) | | Query | [获取数据库实例](#获取数据库实例) | | Transaction | [事务](#事务) | -| WithContext | [注入 Context](#注入-Context) | +| WithContext | [注入 Context](#注入-context) | ## facades.Orm().Query() 可用方法 @@ -259,7 +257,7 @@ facades.Orm().Query().WithoutGlobalScopes("name").Get(&users) | Avg | [聚合](#聚合) | | BeginTransaction | [手动开始事务](#事务) | | Commit | [提交事务](#事务) | -| Context | [注入 Context](#注入-Context) | +| Context | [注入 Context](#注入-context) | | Count | [计数](#计数) | | Create | [创建数据](#创建) | | Cursor | [游标](#游标) | @@ -280,7 +278,7 @@ facades.Orm().Query().WithoutGlobalScopes("name").Get(&users) | Group | [Group 查询](#group-by-having) | | Having | [Having 查询](#group-by-having) | | Join | [Join 查询](#join-查询) | -| Limit | [Limit 查询](#limit-查询) | +| Limit | [Limit 查询](#指定查询数量) | | LockForUpdate | [悲观锁](#悲观锁) | | Max | [最大值](#聚合) | | Min | [最小值](#聚合) | @@ -700,7 +698,9 @@ err := facades.Orm().Query().Model(&models.User{}).Create(&[]map[string]any{ }) ``` -> `created_at` 和 `updated_at` 字段将会被自动填充。 +::: info +`created_at` 和 `updated_at` 字段将会被自动填充。 +::: ### 游标 @@ -745,7 +745,9 @@ facades.Orm().Query().Model(&models.User{}).Where("name", "tom").Update(map[stri // UPDATE `users` SET `updated_at`='2023-09-18 21:07:06.489',`name`='hello',`age`=18 WHERE `name` = 'tom'; ``` -> 当使用 `struct` 进行批量更新时,Orm 只会更新非零值的字段。 你可以使用 `map` 更新字段,或者使用 `Select` 指定要更新的字段。 注意 `struct` 只能为 `Model`,如果想用非 `Model` 批量更新,需要使用 `.Table("users")`,但此时无法自动更新 `updated_at` 字段。 +::: warning 零值会被忽略 +当使用 `struct` 进行批量更新时,Orm 只会更新非零值的字段。 你可以使用 `map` 更新字段,或者使用 `Select` 指定要更新的字段。 注意 `struct` 只能为 `Model`,如果想用非 `Model` 批量更新,需要使用 `.Table("users")`,但此时无法自动更新 `updated_at` 字段。 +::: #### 更新 JSON 字段 @@ -817,7 +819,8 @@ facades.Orm().Query().Select(orm.Associations).Delete(&user) facades.Orm().Query().Select("Account").Delete(&users) ``` -注意:只有当记录的主键不为空时,关联才会被删除,Orm 会使用这些主键作为条件来删除关联记录: +::: warning +只有当记录的主键不为空时,关联才会被删除,Orm 会使用这些主键作为条件来删除关联记录: ```go // 会删除所有 name=`goravel` 的 user,但这些 user 的 account 不会被删除 @@ -829,6 +832,7 @@ facades.Orm().Query().Select("Account").Where("name", "goravel").Delete(&models. // 会删除 id = `1` 的 user,并且 account 也会被删除 facades.Orm().Query().Select("Account").Delete(&models.User{ID: 1}) ``` +::: 如果在没有任何条件的情况下执行批量删除,ORM 不会执行该操作,并返回错误。 对此,你必须加一些条件,或者使用原生 SQL。 @@ -981,7 +985,7 @@ var sum int err := facades.Orm().Query().Model(models.User{}).Sum("id", &sum) var avg float64 -err := facades.Orm().Query().Model(models.User{}).Average("age", &avg) +err := facades.Orm().Query().Model(models.User{}).Avg("age", &avg) var max int err := facades.Orm().Query().Model(models.User{}).Max("age", &max) @@ -996,7 +1000,9 @@ Orm 模型触发几个事件,允许你挂接到模型生命周期的如下节 当从数据库中检索到现有模型时,将调度 `Retrieved` 事件。 当一个新模型第一次被保存时,`Creating` 和 `Created` 事件将被触发。 `Updating` / `Updated` 事件将在修改现有模型并调用 `Save` 方法时触发。 `Saving` / `Saved` 事件将在创建或更新模型时触发 - 即使模型的属性没有更改。 以「-ing」结尾的事件名称在模型的任何更改被持久化之前被调度,而以「-ed」结尾的事件在对模型的更改被持久化之后被调度。 -注意:所有事件都只会在操作一个模型时触发。 例如在调用 `Update` 方法时,想要触发 `Updating` 和 `Updated` 事件,需要将现有模型传入到 `Model` 方法中:`facades.Orm().Query().Model(&user).Update("name", "Goravel")`。 +::: warning +所有事件都只会在操作一个模型时触发。 例如在调用 `Update` 方法时,想要触发 `Updating` 和 `Updated` 事件,需要将现有模型传入到 `Model` 方法中:`facades.Orm().Query().Model(&user).Update("name", "Goravel")`。 +::: 要开始监听模型事件,请在模型上定义一个 `DispatchesEvents` 方法。 此方法将模型生命周期的各个点映射到你定义的事件类中。 @@ -1056,7 +1062,9 @@ func (u *User) DispatchesEvents() map[contractsorm.EventType]func(contractsorm.E } ``` -> 注意:仅注册用到的事件即可。 通过 Orm 进行批量操作时,不会调度模型事件。 +::: warning +仅注册用到的事件即可。 通过 Orm 进行批量操作时,不会调度模型事件。 +::: ### 观察者 @@ -1114,7 +1122,9 @@ func Boot() contractsfoundation.Application { } ``` -> 注意:如果同时使用了 `DispatchesEvents` 与 `Observer`,将只应用 `DispatchesEvents`。 +::: warning +如果同时使用了 `DispatchesEvents` 与 `Observer`,将只应用 `DispatchesEvents`。 +::: #### 观察者传参 diff --git a/zh_CN/orm/relationships.md b/zh_CN/orm/relationships.md index fd67e2585..d565120fc 100644 --- a/zh_CN/orm/relationships.md +++ b/zh_CN/orm/relationships.md @@ -1,14 +1,12 @@ # 模型关联 -[[toc]] - ## 简介 数据库表通常相互关联。 例如,一篇博客文章可能有许多评论,或者一个订单对应一个下单用户。 Orm 让这些关联的管理和使用变得简单,并支持多种常用的关联类型: - [一对一](#一对一) - [一对多](#一对多) -- [多对多](#多对多) +- [多对多](#多对多关联) - [多态](#多态) ## 定义关联 @@ -130,7 +128,7 @@ type Comment struct { 特别提醒,由于角色可以属于多个用户,因此我们不能简单地在 `roles` 表上放置 `user_id` 列。 如果这样,这意味着角色只能属于一个用户。 为了支持将角色分配给多个用户,需要使用 `role_user` 表。 我们可以这样定义表结构: -``` +```text users id - integer name - string @@ -198,7 +196,7 @@ type Role struct { 对应表结构: -``` +```text users id - integer name - string @@ -220,7 +218,7 @@ role_user 多态关联与简单的关联类似,不过,目标模型能够在一个关联上从属于多个模型。 例如,博客 `Post` 和 `Video` 可能共享一个关联到 `Image` 模型的关系。 同时共享多个关联到 `Comment` 模型。 让我们先看看表结构: -``` +```text posts id - integer name - string diff --git a/zh_CN/prologue/compare-with-laravel.md b/zh_CN/prologue/compare-with-laravel.md index 6fc5a54f6..d2d20137d 100644 --- a/zh_CN/prologue/compare-with-laravel.md +++ b/zh_CN/prologue/compare-with-laravel.md @@ -1,40 +1,44 @@ +--- +aside: false +--- + # 与 Laravel 对比 -Goravel 深受 Laravel 框架启发,旨在为 Go 开发者带来类似的优雅和简洁性。 以下是 Goravel 与 Laravel 之间的一些关键对比,以帮助你了解 Goravel 如何与 Laravel 的功能保持一致: +Goravel 沿用了 Laravel 的结构,因此概念、门面以及大部分方法名都是相通的。 下表展示了同一件事在两个框架中的写法,如果其中一方没有该功能,会在表中注明。 -| 功能 | Goravel | Laravel | 代码示例 | -| -------------------------------------------------------------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Artisan 命令行](https://www.goravel.dev/zh_CN/digging-deeper/artisan-console.html) | ✅ | ✅ | ./artisan key:generate
php artisan key:generate | -| [用户认证](https://www.goravel.dev/zh_CN/security/authentication.html) | ✅ | ✅ | facades.Auth(ctx).Login(&user)
Auth::login($user) | -| [用户授权](https://www.goravel.dev/zh_CN/security/authorization.html) | ✅ | ✅ | facades.Gate().Allows("update", user)
Gate::allows('update', $user) | -| [缓存](https://www.goravel.dev/zh_CN/digging-deeper/cache.html) | ✅ | ✅ | facades.Cache().Put("key", "value", time.Minute)
Cache::put('key', 'value', 60) | -| [Carbon](https://www.goravel.dev/zh_CN/digging-deeper/helpers.html) | ✅ | ✅ | carbon.Now().AddDays(1)
Carbon::now()->addDays(1) | -| [自定义配置](https://www.goravel.dev/zh_CN/getting-started/configuration.html) | ✅ | ✅ | facades.Config().GetString("app.name")
config('app.name') | -| [Crypt](https://www.goravel.dev/zh_CN/security/encryption.html) | ✅ | ✅ | facades.Crypt().EncryptString("text")
Crypt::encryptString('text') | -| [数据库](https://www.goravel.dev/zh_CN/database/getting-started.html) | ✅ | ✅ | facades.DB().Table("users").Get(&users)
DB::table('users')->get() | -| [事件系统](https://www.goravel.dev/zh_CN/digging-deeper/event.html) | ✅ | ✅ | facades.Event().Job(&events.Order{}).Dispatch()
Order::dispatch() | -| [数据工厂](https://www.goravel.dev/zh_CN/orm/factories.html) | ✅ | ✅ | facades.Orm().Factory().Make(&user)
User::factory()->make() | -| [文件存储](https://www.goravel.dev/zh_CN/digging-deeper/filesystem.html) | ✅ | ✅ | facades.Storage().Put("file.txt", "content")
Storage::put('file.txt', 'content') | -| [Hash](https://www.goravel.dev/zh_CN/security/hashing.html) | ✅ | ✅ | facades.Hash().Make("password")
Hash::make('password') | -| [HTTP](https://www.goravel.dev/zh_CN/the-basics/routing.html) | ✅ | ✅ | facades.Route().Get("/", controller.Index)
Route::get('/', [Controller::class, 'index']) | -| [HTTP 客户端](https://www.goravel.dev/zh_CN/digging-deeper/http-client.html) | ✅ | ✅ | facades.Http().Get("https://api.com")
Http::get('https://api.com') | -| [本地化](https://www.goravel.dev/zh_CN/digging-deeper/localization.html) | ✅ | ✅ | facades.Lang(ctx).Get("messages.welcome")
__('messages.welcome') | -| [日志](https://www.goravel.dev/zh_CN/the-basics/logging.html) | ✅ | ✅ | facades.Log().Info("message")
Log::info('message') | -| [邮件](https://www.goravel.dev/zh_CN/digging-deeper/mail.html) | ✅ | ✅ | facades.Mail().To("user@example.com").Send()
Mail::to('user@example.com')->send(new Order()) | -| [Mock](https://www.goravel.dev/zh_CN/testing/mock.html) | ✅ | ✅ | | -| [数据库迁移](https://www.goravel.dev/zh_CN/database/migrations.html) | ✅ | ✅ | ./artisan migrate
php artisan migrate | -| [ORM](https://www.goravel.dev/zh_CN/orm/getting-started.html) | ✅ | ✅ | facades.Orm().Query().Find(&user, 1)
User::find(1) | -| [扩展包开发](https://www.goravel.dev/zh_CN/digging-deeper/package-development.html) | ✅ | ✅ | | -| [进程](https://www.goravel.dev/zh_CN/digging-deeper/process.html) | ✅ | ✅ | facades.Process().Run("ls", "-la")
\`Process::run('ls -la') | -| [队列](https://www.goravel.dev/zh_CN/digging-deeper/queues.html) | ✅ | ✅ | facades.Queue().Job(&jobs.Process{}).Dispatch()
Process::dispatch() | -| [速率限制](https://www.goravel.dev/zh_CN/digging-deeper/process.html) | ✅ | ✅ | facades.RateLimiter().For("global", ...)
RateLimiter::for('global', ...) | -| [数据填充](https://www.goravel.dev/zh_CN/database/seeding.html) | ✅ | ✅ | facades.Seeder().Call([]seeder.Seeder{&User{}})
$this->call([User::class]) | -| [Session](https://www.goravel.dev/zh_CN/the-basics/session.html) | ✅ | ✅ | ctx.Request().Session().Put("key", "value")
session(['key' => 'value']) | -| [任务调度](https://www.goravel.dev/zh_CN/digging-deeper/task-scheduling.html) | ✅ | ✅ | facades.Schedule().Command("emails:send").Daily()
Schedule::command('emails:send')->daily() | -| [测试](https://www.goravel.dev/zh_CN/testing/getting-started.html) | ✅ | ✅ | | -| [表单验证](https://www.goravel.dev/zh_CN/the-basics/validation.html) | ✅ | ✅ | ctx.Request().ValidateRequest()
$request->validate() | -| [视图](https://www.goravel.dev/zh_CN/the-basics/views.html) | ✅ | ✅ | ctx.Response().View().Make("welcome.tmpl")
view('welcome') | -| [Grpc](https://www.goravel.dev/zh_CN/the-basics/grpc.html) | ✅ | 🚧 | | -| 通知 | 🚧 | ✅ | | -| 广播 | 🚧 | ✅ | | -| Livewire | 🚧 | ✅ | | +| 功能 | Laravel | Goravel | +| --- | --- | --- | +| [Artisan 命令行](../digging-deeper/artisan-console.md) | `php artisan key:generate` | `./artisan key:generate` | +| [用户认证](../security/authentication.md) | `Auth::login($user)` | `facades.Auth(ctx).Login(&user)` | +| [用户授权](../security/authorization.md) | `Gate::allows('update-post', $post)` | `facades.Gate().Allows("update-post", map[string]any{"post": post})` | +| [缓存](../digging-deeper/cache.md) | `Cache::put('key', 'value', 60)` | `facades.Cache().Put("key", "value", time.Minute)` | +| [Carbon](../digging-deeper/helpers.md) | `Carbon::now()->addDays(1)` | `carbon.Now().AddDays(1)` | +| [自定义配置](../getting-started/configuration.md) | `config('app.name')` | `facades.Config().GetString("app.name")` | +| [Crypt](../security/encryption.md) | `Crypt::encryptString('text')` | `facades.Crypt().EncryptString("text")` | +| [数据库](../database/getting-started.md) | `DB::table('users')->get()` | `facades.DB().Table("users").Get(&users)` | +| [事件系统](../digging-deeper/event.md) | `OrderShipped::dispatch()` | `facades.Event().Job(&events.OrderShipped{}, []event.Arg{}).Dispatch()` | +| [数据工厂](../orm/factories.md) | `User::factory()->make()` | `facades.Orm().Factory().Make(&user)` | +| [文件存储](../digging-deeper/filesystem.md) | `Storage::put('file.txt', 'content')` | `facades.Storage().Put("file.txt", "content")` | +| [Hash](../security/hashing.md) | `Hash::make('password')` | `facades.Hash().Make("password")` | +| [HTTP 客户端](../digging-deeper/http-client.md) | `Http::get('https://example.com')` | `facades.Http().Get("https://example.com")` | +| [本地化](../digging-deeper/localization.md) | `__('messages.welcome')` | `facades.Lang(ctx).Get("messages.welcome")` | +| [日志](../the-basics/logging.md) | `Log::info('message')` | `facades.Log().Info("message")` | +| [邮件](../digging-deeper/mail.md) | `Mail::to('user@example.com')->send(new OrderShipped())` | `facades.Mail().To([]string{"user@example.com"}).Send()` | +| [数据库迁移](../database/migrations.md) | `php artisan migrate` | `./artisan migrate` | +| [Mock](../testing/mock.md) | `Cache::shouldReceive('get')` | `mock.Factory().Cache()` | +| [ORM](../orm/getting-started.md) | `User::find(1)` | `facades.Orm().Query().Find(&user, 1)` | +| [扩展包开发](../digging-deeper/package-development.md) | `$this->loadViewsFrom($path, 'courier')` | `facades.View().LoadViewsFrom("/path/to/package/views")` | +| [进程](../digging-deeper/processes.md) | `Process::run('ls -la')` | `facades.Process().Run("ls", "-la")` | +| [队列](../digging-deeper/queues.md) | `SendEmail::dispatch()` | `facades.Queue().Job(&jobs.SendEmail{}, []queue.Arg{}).Dispatch()` | +| [速率限制](../the-basics/routing.md#rate-limiting) | `RateLimiter::for('global', ...)` | `facades.RateLimiter().For("global", ...)` | +| [路由](../the-basics/routing.md) | `Route::get('/', [Controller::class, 'index'])` | `facades.Route().Get("/", controller.Index)` | +| [数据填充](../database/seeding.md) | `$this->call([UserSeeder::class])` | `facades.Seeder().Call([]seeder.Seeder{&UserSeeder{}})` | +| [Session](../the-basics/session.md) | `session(['key' => 'value'])` | `ctx.Request().Session().Put("key", "value")` | +| [任务调度](../digging-deeper/task-scheduling.md) | `Schedule::command('emails:send')->daily()` | `facades.Schedule().Command("emails:send").Daily()` | +| [测试](../testing/getting-started.md) | `$this->get('/tasks')` | `s.Http(s.T()).Get("/tasks")` | +| [表单验证](../the-basics/validation.md) | `$request->validate([...])` | `ctx.Request().ValidateRequest(&storePost)` | +| [视图](../the-basics/views.md) | `view('welcome')` | `ctx.Response().View().Make("welcome.tmpl")` | +| [Grpc](../the-basics/grpc.md) | 未内置 | `facades.Grpc().Connect("user")` | +| 通知 | `$user->notify(new InvoicePaid())` | 暂未支持 | +| 广播 | `broadcast(new OrderShipped($order))` | 暂未支持 | +| Livewire | `` | 暂未支持 | diff --git a/zh_CN/prologue/contributions.md b/zh_CN/prologue/contributions.md index 4857b7714..a681f9171 100644 --- a/zh_CN/prologue/contributions.md +++ b/zh_CN/prologue/contributions.md @@ -1,7 +1,5 @@ # 贡献指南 -[[toc]] - Goravel 欢迎不同人才提供丰富多样的贡献,例如编码、翻译、文章、教程等。 完成两个 `Feature`(5 个 `Good First Issue` == 1 个 `Feature`)后,你将成为核心开发者。 之后每三个月至少完成一个 `Feature`,可以保持这个头衔。 让我们一起将 Goravel 变得更高效! @@ -17,7 +15,7 @@ Goravel 欢迎不同人才提供丰富多样的贡献,例如编码、翻译、
- +
@@ -154,7 +152,7 @@ go install github.com/goravel/installer/goravel@latest ```shell goravel skill:list -// 显示技能及描述 +# 显示技能及描述 goravel skill:list --detail ``` @@ -184,7 +182,9 @@ goravel skill:install --path ~/goravel-skills goravel skill:install --force goravel-testing ``` -> **注意**:除非使用 `--force`,否则已有技能将被保留。 +::: info +除非使用 `--force`,否则已有技能将被保留。 +::: ## 行为准则 diff --git a/zh_CN/security/authentication.md b/zh_CN/security/authentication.md index 66a8f1540..b893eec38 100644 --- a/zh_CN/security/authentication.md +++ b/zh_CN/security/authentication.md @@ -1,7 +1,5 @@ # 用户认证 -[[toc]] - ## 简介 用户认证是 Web 应用中不可或缺的功能,Goravel 的 `facades.Auth()` 模块提供 JWT 和 Session 驱动的支持,并且可以根据自己需要自定义驱动。 @@ -69,7 +67,9 @@ payload, err := facades.Auth(ctx).Parse(token) 3. `ExpireAt`: 过期时间; 4. `IssuedAt`: 发行时间; -> 当 `err` 为非 `ErrorTokenExpired` 的错误时,payload == nil +::: info +当 `err` 为非 `ErrorTokenExpired` 的错误时,payload == nil +::: 可以通过 `err` 来判断 `Token` 是否过期: @@ -80,7 +80,9 @@ payload, err := facades.Auth(ctx).Parse(token) errors.Is(err, auth.ErrorTokenExpired) ``` -> Token 带不带 Bearer 前缀均可正常解析。 +::: tip +Token 带不带 Bearer 前缀均可正常解析。 +::: ## 获取用户 @@ -114,7 +116,9 @@ err := facades.Auth(ctx).Guard("admin").Parse(token) err := facades.Auth(ctx).Guard("admin").User(&user) ``` -> 当不使用默认授权时,在调用上述方法时都需要前置调用 `Guard` 方法。 +::: warning +当不使用默认授权时,在调用上述方法时都需要前置调用 `Guard` 方法。 +::: JWT Token 与其生成时所使用的守卫绑定。如果你使用不同的守卫解析 Token,Goravel 会返回 `auth.ErrorGuardMismatch`: diff --git a/zh_CN/security/authorization.md b/zh_CN/security/authorization.md index 6246c0d45..99fcec303 100644 --- a/zh_CN/security/authorization.md +++ b/zh_CN/security/authorization.md @@ -1,12 +1,10 @@ # 用户授权 -[[toc]] - ## 简介 除了提供内置的 [身份验证(authentication)](./authentication.md) 服务外,Goravel 还提供了一种可以很简单就进行使用的方法,来对用户与资源的授权关系进行管理。 即使用户已经通过了「身份验证(authentication)」, 用户也可能无权对应用程序中的模型或数据库记录进行删除或更改。 Goravel的授权功能允许有系统地管理这些授权检查。 -Goravel 主要提供了两种授权操作的方法: [拦截器](#拦截器(Gates)) 和 [策略](#策略(Policies))。 可以把拦截器(gates)和策略(policies)想象成路由和控制器。 拦截器(Gates)提供了一种轻便的基于闭包函数的授权方法,像是路由。而策略(policies),就像是一个控制器,对特定模型或资源进行管理。 在本文档中,我们将首先探讨拦截器(gates),然后是策略(policies)。 +Goravel 主要提供了两种授权操作的方法: [拦截器](#拦截器-gates) 和 [策略](#策略-policies)。 可以把拦截器(gates)和策略(policies)想象成路由和控制器。 拦截器(Gates)提供了一种轻便的基于闭包函数的授权方法,像是路由。而策略(policies),就像是一个控制器,对特定模型或资源进行管理。 在本文档中,我们将首先探讨拦截器(gates),然后是策略(policies)。 你在构建应用程序时,不用为是使用拦截器(gates)或是使用策略(policies)而担心,并不需要在两者中进行唯一选择。 大多数的应用程序都同时包含两种方法,并且同时使用两者! @@ -123,7 +121,9 @@ facades.Gate().After(func(ctx context.Context, ability string, arguments map[str }) ``` -> 注意:只有当 `facades.Gate().Define` 返回 nil 时,才会应用 `After` 的返回结果。 +::: warning +只有当 `facades.Gate().Define` 返回 nil 时,才会应用 `After` 的返回结果。 +::: ### 注入 Context diff --git a/zh_CN/security/encryption.md b/zh_CN/security/encryption.md index c764c4e47..d046ac6f7 100644 --- a/zh_CN/security/encryption.md +++ b/zh_CN/security/encryption.md @@ -1,7 +1,5 @@ # 加密解密 -[[toc]] - ## 简介 Goravel 的加密机制使用的是 OpenSSL 所提供的 AES-256 加密。 所有 Goravel 加密之后的结果都会使用消息认证码 (GMAC) 签名,使其底层值不能在加密后再次修改。 diff --git a/zh_CN/security/hashing.md b/zh_CN/security/hashing.md index ecca3333b..c69b6877f 100644 --- a/zh_CN/security/hashing.md +++ b/zh_CN/security/hashing.md @@ -1,7 +1,5 @@ # 哈希 -[[toc]] - ## 简介 Goravel `facades.Hash()` 为存储用户密码提供了安全的 Argon2id 和 Bcrypt 哈希加密方式。 如果你正在使用 Goravel 应用初始脚手架 ,默认情况下,将使用 Argon2id 进行注册和身份验证。 diff --git a/zh_CN/testing/getting-started.md b/zh_CN/testing/getting-started.md index b9a2d5a0e..62db3b0ef 100644 --- a/zh_CN/testing/getting-started.md +++ b/zh_CN/testing/getting-started.md @@ -1,7 +1,5 @@ # 快速入门 -[[toc]] - ## 介绍 Goravel 的测试功能依托于 Golang 自带的 test 官方组件,是对单元测试的扩展,使 Goravel 应用程序支持集成测试,让应用变得更加健壮。 @@ -12,7 +10,7 @@ Goravel 的测试功能依托于 Golang 自带的 test 官方组件,是对单 测试时默认使用根目录下的 `.env` 文件注入配置信息。 如果想为不同的包使用不同的 `.env` 文件,可以在包目录下创建 `.env` 文件,测试时会优先读取该文件。 -``` +```text - /app - /config - ... @@ -136,7 +134,9 @@ func (s *ExampleTestSuite) TestIndex() { 由于 `go test` 在不同包之间是并行测试。 因此当使用本地数据库或缓存进行测试时,不能在测试用例中执行重置数据库或缓存操作,否则将有可能对并行运行的其他测试用例产生影响。 针对这种情况,Goravel 支持使用 Docker 进行测试。 不同包之间可以独立使用由 Docker 创建的镜像。 -> 由于 Docker 镜像对 windows 系统的支持有限,目前 Docker 测试仅支持在非 windows 环境下运行。 +::: warning +由于 Docker 镜像对 windows 系统的支持有限,目前 Docker 测试仅支持在非 windows 环境下运行。 +::: #### 初始化镜像 @@ -293,4 +293,6 @@ func TestMain(m *testing.M) { } ``` -> 关于 TestMain 方法的更多使用,参见[官方文档](https://pkg.go.dev/testing#hdr-Main)。 +::: tip +关于 TestMain 方法的更多使用,参见[官方文档](https://pkg.go.dev/testing#hdr-Main)。 +::: diff --git a/zh_CN/testing/http-tests.md b/zh_CN/testing/http-tests.md index b31393a85..55f2dd40a 100644 --- a/zh_CN/testing/http-tests.md +++ b/zh_CN/testing/http-tests.md @@ -1,7 +1,5 @@ # HTTP Tests -[[toc]] - ## 介绍 在构建Web应用程序时,你通常需要从头到尾测试你的HTTP请求是否正常工作。 Goravel的测试工具使这变得简单——你可以模拟请求并验证响应,而无需设置复杂的测试环境。 @@ -127,7 +125,7 @@ s.Nil(err) s.True(json["created"]) ``` -:::tip +::: tip `AssertJson` 方法检查响应是否包含所有指定的值,即使响应包含额外的字段。 除非使用 `AssertExactJson`,否则不需要完全匹配。 ::: diff --git a/zh_CN/testing/mock.md b/zh_CN/testing/mock.md index dd0bcad68..c981c6c5c 100644 --- a/zh_CN/testing/mock.md +++ b/zh_CN/testing/mock.md @@ -1,7 +1,5 @@ # Mock -[[toc]] - ## 简介 Goravel 所有功能都使用 `facades` 实现,而所有的 `facades` 均由接口构成。 因此配合 [stretchr/testify](http://github.com/stretchr/testify) 的 mock 功能,Goravel 可以提供优秀的测试体验。 diff --git a/zh_CN/the-basics/controllers.md b/zh_CN/the-basics/controllers.md index 88426cecd..4bd50fb7a 100644 --- a/zh_CN/the-basics/controllers.md +++ b/zh_CN/the-basics/controllers.md @@ -1,7 +1,5 @@ # 控制器 -[[toc]] - ## 简介 为了代替在单独路由中以闭包形式定义所有的请求处理逻辑,可以使用控制器来进行整合。 控制器被存放在 `app/http/controllers` 目录中。 diff --git a/zh_CN/the-basics/grpc.md b/zh_CN/the-basics/grpc.md index bd98a3459..562f0ec82 100644 --- a/zh_CN/the-basics/grpc.md +++ b/zh_CN/the-basics/grpc.md @@ -1,7 +1,5 @@ # Grpc -[[toc]] - ## 简介 Grpc 模块可以使用 `facades.Grpc()` 进行操作。 Goravel 提供了一种优雅的方式来构建和使用 gRPC 服务,同时支持服务端和客户端。 diff --git a/zh_CN/the-basics/logging.md b/zh_CN/the-basics/logging.md index 955189028..d6e5d97f3 100644 --- a/zh_CN/the-basics/logging.md +++ b/zh_CN/the-basics/logging.md @@ -1,7 +1,5 @@ # 日志 -[[toc]] - ## 简介 为了了解应用程序的运行状况,Goravel 提供了强大的日志模块,可以通过 `facades.Log()` 将日志消息、系统错误记录到文件或其他通道。 diff --git a/zh_CN/the-basics/middleware.md b/zh_CN/the-basics/middleware.md index bc40ef26d..491f7e451 100644 --- a/zh_CN/the-basics/middleware.md +++ b/zh_CN/the-basics/middleware.md @@ -1,7 +1,5 @@ # HTTP 中间件 -[[toc]] - ## 简介 中间件可以过滤进入应用程序的 HTTP 请求。 @@ -30,10 +28,10 @@ func (a *Auth) Signature() string { ### 命令创建中间件 -``` +```shell ./artisan make:middleware Auth -// 支持嵌套文件夹 +# 支持嵌套文件夹 ./artisan make:middleware user/Auth ``` @@ -101,7 +99,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **注意**:中间件排除使用 `Signature()` 方法来识别中间件。请确保每个中间件返回唯一的签名,以便 `WithoutMiddleware` 正常工作。框架内置的中间件已经提供了唯一的签名。 +::: warning +中间件排除使用 `Signature()` 方法来识别中间件。请确保每个中间件返回唯一的签名,以便 `WithoutMiddleware` 正常工作。框架内置的中间件已经提供了唯一的签名。 +::: ## 中断请求 diff --git a/zh_CN/the-basics/request.md b/zh_CN/the-basics/request.md index b5e666c71..c3891bdf6 100644 --- a/zh_CN/the-basics/request.md +++ b/zh_CN/the-basics/request.md @@ -1,7 +1,5 @@ # 请求 -[[toc]] - ## 简介 Goravel 的 `contracts/http/Request` 方法可以与应用程序处理的当前 HTTP 请求进行交互,以及检索与请求一起提交的输入内容和文件。 @@ -113,7 +111,9 @@ names := ctx.Request().QueryMap("names") queries := ctx.Request().Queries() ``` -> 注意:只能获取单维Json数据,否则它将返回为空。 +::: warning +只能获取单维Json数据,否则它将返回为空。 +::: ### 检索一个输入值 diff --git a/zh_CN/the-basics/response.md b/zh_CN/the-basics/response.md index 264591d1d..57906a93c 100644 --- a/zh_CN/the-basics/response.md +++ b/zh_CN/the-basics/response.md @@ -1,7 +1,5 @@ # 响应 -[[toc]] - ## 简介 可以使用 `ctx.Response()` 在控制其中进行 HTTP 响应。 diff --git a/zh_CN/the-basics/routing.md b/zh_CN/the-basics/routing.md index a246eb814..dc6623263 100644 --- a/zh_CN/the-basics/routing.md +++ b/zh_CN/the-basics/routing.md @@ -1,7 +1,5 @@ # 路由 -[[toc]] - ## 简介 Goravel 路由模块可以使用 `facades.Route()` 进行操作。 @@ -46,7 +44,7 @@ func Boot() contractsfoundation.Application { | ---------- | ----------------- | | Group | [路由分组](#路由分组) | | Prefix | [路由前缀](#路由前缀) | -| ServeHTTP | [测试路由](#测试路由) | +| ServeHTTP | [HTTP 测试](../testing/http-tests.md) | | Get | [基本路由](#基本路由) | | Post | [基本路由](#基本路由) | | Put | [基本路由](#基本路由) | @@ -185,7 +183,9 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **注意**:中间件排除使用 `Signature()` 方法来识别中间件。请确保每个中间件返回唯一的签名,以便 `WithoutMiddleware` 正常工作。框架内置的中间件已经提供了唯一的签名。 +::: warning +中间件排除使用 `Signature()` 方法来识别中间件。请确保每个中间件返回唯一的签名,以便 `WithoutMiddleware` 正常工作。框架内置的中间件已经提供了唯一的签名。 +::: ## 获取所有路由 @@ -215,7 +215,7 @@ facades.Route().Fallback(func(ctx http.Context) http.Response { }) ``` -## 速率限制 +## 速率限制 {#rate-limiting} ### 定义速率限制器 @@ -316,4 +316,6 @@ facades.Route().Middleware(middleware.Throttle("global")).Get("/", func(ctx http Goravel 已默认启用 CORS,详细配置可以到 `config/cors.go` 文件中进行修改。 -> 有关 CORS 和 CORS 标头的更多信息,请参阅 [MDN 关于 CORS 的 Web 文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers)。 +::: tip +有关 CORS 和 CORS 标头的更多信息,请参阅 [MDN 关于 CORS 的 Web 文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers)。 +::: diff --git a/zh_CN/the-basics/session.md b/zh_CN/the-basics/session.md index ffbbe782f..9143ebb86 100644 --- a/zh_CN/the-basics/session.md +++ b/zh_CN/the-basics/session.md @@ -1,7 +1,5 @@ # Session -[[toc]] - ## 简介 Session 使你可以在多个请求之间存储用户信息,为本质上无状态的 HTTP 协议提供有状态的体验。 这些用户信息在服务器端持久存储。 Goravel 提供了一个统一的接口,用于与各种持久存储驱动进行交互。 diff --git a/zh_CN/the-basics/validation.md b/zh_CN/the-basics/validation.md index 59696d2cc..7a75fc89c 100644 --- a/zh_CN/the-basics/validation.md +++ b/zh_CN/the-basics/validation.md @@ -1,7 +1,5 @@ # 表单验证 -[[toc]] - ## 简介 Goravel 提供了几种不同的方法来验证传入应用程序的数据。 最常见的做法是在所有传入的 HTTP 请求中使用 `Validate` 方法。Goravel 包含了各种方便的验证规则。 @@ -147,7 +145,9 @@ func (r *PostController) Store(ctx http.Context) { 更多验证规则详见 [可用的验证规则](#可用的验证规则)。 -> 注意,由于 `form` 传值默认为 `string` 类型,因此 request 中所有字段也都应为 `string` 类型,否则请使用 `JSON` 传值。 +::: warning +由于 `form` 传值默认为 `string` 类型,因此 request 中所有字段也都应为 `string` 类型,否则请使用 `JSON` 传值。 +::: ### 表单请求授权验证 diff --git a/zh_CN/the-basics/views.md b/zh_CN/the-basics/views.md index 6108b023e..3e748ed47 100644 --- a/zh_CN/the-basics/views.md +++ b/zh_CN/the-basics/views.md @@ -1,7 +1,5 @@ # 视图 -[[toc]] - ## 简介 当然,直接从路由和控制器返回整个 HTML 文档字符串是不切实际的。 值得庆幸的是,视图提供了一种方便的方式来将我们所有的 HTML 放在单独的文件中。 视图将你的控制器 / 应用程序逻辑与你的表现逻辑分开并存储在 `resources/views` 目录中。 @@ -10,7 +8,7 @@ 使用框架默认模版 `html/template` 时,可以通过在应用程序 `resources/views` 目录中放置具有 `.tmpl` 扩展名的文件来创建视图。 -``` +```html // resources/views/welcome.tmpl {{ define "welcome.tmpl" }} @@ -61,7 +59,7 @@ ctx.Response().View().First([]string{"custom/admin.tmpl", "admin.tmpl"}, map[str 如果需要判断视图文件是否存在,可以使用 `facades.View()` 方法。它会检查 `resources/views/` 目录以及通过 `LoadViewsFrom` 注册的任何目录: ```go -if facades.View().Exist("welcome.tmpl") { +if facades.View().Exists("welcome.tmpl") { // ... } ``` @@ -79,7 +77,7 @@ func (r *ServiceProvider) Boot(app foundation.Application) { 渲染视图时,应用程序的 `resources/views` 目录具有优先权——用户可以在 `resources/views` 中创建同名文件来覆盖任何包视图。如果在此目录中未找到视图,则会按注册顺序在已注册的包视图目录中进行回退搜索。 -`Exist` 方法除了检查 `resources/views/` 外,也会检查已注册的包视图路径。 +`Exists` 方法除了检查 `resources/views/` 外,也会检查已注册的包视图路径。 ## 向视图传递数据 diff --git a/zh_CN/upgrade/history.md b/zh_CN/upgrade/history.md index 4db9d5b2c..91107d460 100644 --- a/zh_CN/upgrade/history.md +++ b/zh_CN/upgrade/history.md @@ -1,3 +1,7 @@ +--- +aside: false +--- + # 历史版本升级 - [从 v1.15 升级到 v1.16](v1.16.md) diff --git a/zh_CN/upgrade/v1.1.md b/zh_CN/upgrade/v1.1.md index 6c6e2c693..08d5bf054 100644 --- a/zh_CN/upgrade/v1.1.md +++ b/zh_CN/upgrade/v1.1.md @@ -1,7 +1,5 @@ # 从 v1.0 升级到 v1.1 -[[toc]] - ## 高影响变化 - [更新依赖](#更新依赖) diff --git a/zh_CN/upgrade/v1.10.md b/zh_CN/upgrade/v1.10.md index a2dc1f4b6..6ea4a5ad0 100644 --- a/zh_CN/upgrade/v1.10.md +++ b/zh_CN/upgrade/v1.10.md @@ -1,7 +1,5 @@ # 从 v1.9 升级到 v1.10 -[[toc]] - ## 令人兴奋的新功能 🎉 - [新增 facades.Crypt(1.10.0)](#加密解密) @@ -67,7 +65,7 @@ Version: v1.10.0 Version: v1.10.0 -[查看文档](../the-basics/routing.md#速率限制) +[查看文档](../the-basics/routing.md#rate-limiting) ### 优化 HTTP 启动方式 diff --git a/zh_CN/upgrade/v1.11.md b/zh_CN/upgrade/v1.11.md index fe7f468bd..a67de3660 100644 --- a/zh_CN/upgrade/v1.11.md +++ b/zh_CN/upgrade/v1.11.md @@ -1,7 +1,5 @@ # 从 v1.10 升级到 v1.11 -[[toc]] - ## v1.11.3 ### Bug 修复 🐛 diff --git a/zh_CN/upgrade/v1.17.md b/zh_CN/upgrade/v1.17.md index a36d895b8..c3686d0fa 100644 --- a/zh_CN/upgrade/v1.17.md +++ b/zh_CN/upgrade/v1.17.md @@ -64,30 +64,30 @@ goravel/example 项目从 v1.16 升级到 v1.17 的 PR 可作为升级参考:[ ```shell go get github.com/goravel/framework@latest -// If using gin +# If using gin go get github.com/goravel/gin@latest -// If using fiber +# If using fiber go get github.com/goravel/fiber@latest -// If using redis +# If using redis go get github.com/goravel/redis@latest -// If using S3 +# If using S3 go get github.com/goravel/s3@latest -// If using Oss +# If using Oss go get github.com/goravel/oss@latest -// If using Cos +# If using Cos go get github.com/goravel/cos@latest -// If using Minio +# If using Minio go get github.com/goravel/minio@latest go mod tidy -// If using installer +# If using installer goravel upgrade ``` @@ -201,7 +201,7 @@ import ( 1. 删除所有 `kenel.go` 和默认的 `*_service_providers.go` 文件。 将 `*_service_providers.go` 文件中的配置移动到 `bootstrap` 文件夹。 2. 将所有 facades 从框架内部移动到 `app/facades` 文件夹,用户可以根据需要自定义或扩展它们。 3. 简化外观启动过程,不再需要在 `main.go` 中运行 facades,更多详情请参阅 [服务提供者运行器](../architecture-concepts/service-providers.md#runners)。 -4. 支持通过 `WithPath()` 函数自定义目录结构,更多详情请参阅 [自定义目录结构](../getting-started/directory-structure.md#customize-directory-structure)。 +4. 支持通过 `WithPath()` 函数自定义目录结构,更多详情请参阅 [自定义目录结构](../getting-started/directory-structure.md#自定义目录结构)。 ### 进程 Facade @@ -219,7 +219,7 @@ Goravel 现在包含一个复数化包,可根据语言规则帮助在单词的 服务提供者现在可以实现 `Runners` 接口,在应用程序启动时运行代码。 这通常用于启动或关闭服务提供者中定义的服务,例如路由、调度、队列等。 你不再需要在 `main.go` 中手动启动或关闭这些服务,因为 Goravel 会为你处理。 -此功能仅在使用 [新的简化代码结构](#simplified-code-structure) 时可用。 +此功能仅在使用 [新的简化代码结构](#简化代码结构) 时可用。 [查看文档](../architecture-concepts/service-providers.md#runners) @@ -245,7 +245,7 @@ Goravel 的日志系统现在支持以 JSON 格式输出日志,使其更容易 Goravel 的 HTTP 客户端模块现在支持多个客户端,允许你定义和使用具有各自配置的不同 HTTP 客户端,以满足应用程序内的各种用途。 -[查看文档](../digging-deeper/http-client.md#making-requests) +[查看文档](../digging-deeper/http-client.md#发起请求) ### 验证支持传递上下文 @@ -306,15 +306,15 @@ func (r *User) GlobalScopes() map[string]func(orm.Query) orm.Query { // [!code + ### facades 可按需安装和卸载 -随着 [轻量化 Goravel](#轻量化-goravel) 的发布,现在可以通过 `package:install` 和 `package:uninstall` 命令根据需要安装和卸载外观。 注意:此功能仅在你的项目使用轻量化 Goravel 构建或升级到 [新的简化代码结构](#simplified-code-structure) 时可用。 +随着 [轻量化 Goravel](#轻量版-goravel) 的发布,现在可以通过 `package:install` 和 `package:uninstall` 命令根据需要安装和卸载外观。 注意:此功能仅在你的项目使用轻量化 Goravel 构建或升级到 [新的简化代码结构](#简化代码结构) 时可用。 -[查看文档](../architecture-concepts/facades.md#install-uninstall-facades) +[查看文档](../architecture-concepts/facades.md#安装-卸载-facades) ### 邮件可通过模板发送 邮件发送支持模板,允许你使用预定义的模板发送电子邮件,以获得更好的一致性和更轻松的管理。 模板支持 http/template 和自定义驱动。 -详情请 [查看文档](../digging-deeper/mail.md#using-template) +详情请 [查看文档](../digging-deeper/mail.md#使用模板) ### build 命令支持更多选项 @@ -359,19 +359,19 @@ Sum(column string, dest any) error 添加一个新的中间件,以防止跨站请求伪造(CSRF)攻击。 此中间件可应用于路由,以确保请求来自经过身份验证的来源。 -[查看文档](../the-basics/views.md#csrf-token-middleware) +[查看文档](../the-basics/views.md#csrf-令牌中间件) ### 命令支持配置参数 命令现在支持配置参数,允许你在自定义命令中更有效地定义和处理命令行参数。 -详情请 [查看文档](../digging-deeper/artisan-console.md#arguments) +详情请 [查看文档](../digging-deeper/artisan-console.md#参数) ### make:migration 支持通过模型创建迁移 `make:migration` 命令已增强,支持基于现有模型创建迁移。 这允许通过利用模型中定义的结构来更快地创建迁移。 -[查看文档](../database/migrations.md#create-migrations) +[查看文档](../database/migrations.md#生成迁移) ### 优化 gRPC 客户端连接 diff --git a/zh_CN/upgrade/v1.18.md b/zh_CN/upgrade/v1.18.md index a23a463a7..5adc0b67a 100644 --- a/zh_CN/upgrade/v1.18.md +++ b/zh_CN/upgrade/v1.18.md @@ -349,7 +349,9 @@ rg -n 'Required.*is required to not be empty' --type go +s.Equal("{\"message\":{\"name\":{\"required\":\"The name field is required.\"}}}", content) ``` -> **注意**:通配符规则(如 `scores.*`、`tags.*`)现在即使没有提供输入也会一致地出现在错误输出中。如果你的测试检查完整的错误响应体,请为之添加断言。 +::: warning +通配符规则(如 `scores.*`、`tags.*`)现在即使没有提供输入也会一致地出现在错误输出中。如果你的测试检查完整的错误响应体,请为之添加断言。 +::: ### 6c. 重命名与内置规则冲突的自定义规则 @@ -620,9 +622,11 @@ facades.Route().Middleware(middleware.Auth()). }) ``` -> **注意**:中间件排除使用 `Signature()` 方法来识别中间件。确保每个中间件返回唯一的签名,以便 `WithoutMiddleware` 正常工作。内置框架中间件已提供唯一签名。 +::: warning +中间件排除使用 `Signature()` 方法来识别中间件。确保每个中间件返回唯一的签名,以便 `WithoutMiddleware` 正常工作。内置框架中间件已提供唯一签名。 +::: -[查看文档](../the-basics/routing.md#without-middleware) +[查看文档](../the-basics/routing.md#排除中间件) ### build 命令支持 go generate @@ -726,7 +730,7 @@ func Boot() contractsfoundation.Application { } ``` -[查看文档](../digging-deeper/artisan-console.md#过滤命令) +[查看文档](../digging-deeper/artisan-console.md#命令过滤) ### gRPC 支持 TLS 和 mTLS 凭证 @@ -779,7 +783,9 @@ func (r *ServiceProvider) Boot(app foundation.Application) { [查看文档](../the-basics/views.md#从包注册视图) -> **注意**:如果要在 Fiber 驱动中使用此功能,请参阅 [Fiber 驱动模板配置替换为 DefaultTemplate](#fiber-驱动模板配置替换为-defaulttemplate)。 +::: tip +如果要在 Fiber 驱动中使用此功能,请参阅 [Fiber 驱动模板配置替换为 DefaultTemplate](#fiber-驱动模板配置替换为-defaulttemplate)。 +::: ### 包配置支持导入别名 @@ -841,7 +847,7 @@ func (d *KafkaDriver) Receive(ctx context.Context, queue string, count int) ([]q Skill 来源于 [goravel/agents](https://github.com/goravel/agents) 仓库,默认安装到 `~/.agents/skills`。你可以按名称过滤,通过 `--path` 选择自定义目标目录,并通过 `--force` 覆盖已有 skill。 -[查看文档](../prologue/contributions.md#agent-skills) +[查看文档](../prologue/contributions.md#agent-技能) ### Fiber 驱动上下文与 Fiber 实例生命周期解耦 @@ -913,7 +919,7 @@ type Middleware interface { 此变更为每个中间件提供了通过 `Signature()` 方法的稳定身份标识,使 `WithoutMiddleware` 能够通过签名比较可靠地排除特定中间件。所有内置框架中间件(`Cors`、`Timeout`、`Throttle`、`VerifyCsrfToken` 等)已更新为返回实现此接口的结构体。 -自定义中间件必须更新为实现新接口。迁移步骤请参阅[升级指南](#步骤-2将-http-中间件从-func-迁移到-interface)。 +自定义中间件必须更新为实现新接口。迁移步骤请参阅[升级指南](#升级指南)。 [查看文档](../the-basics/middleware.md) diff --git a/zh_CN/upgrade/v1.4.md b/zh_CN/upgrade/v1.4.md index 2a539510d..91e145637 100644 --- a/zh_CN/upgrade/v1.4.md +++ b/zh_CN/upgrade/v1.4.md @@ -1,7 +1,5 @@ # 从 v1.3 升级到 v1.4 -[[toc]] - ## 高影响变化 - [优化 Grpc 模块](#优化-grpc-模块) diff --git a/zh_CN/upgrade/v1.5.md b/zh_CN/upgrade/v1.5.md index bd7c1ac52..716090c7e 100644 --- a/zh_CN/upgrade/v1.5.md +++ b/zh_CN/upgrade/v1.5.md @@ -1,7 +1,5 @@ # 从 v1.4 升级到 v1.5 -[[toc]] - ## 高影响变化 - [新增文件存储模块](#新增文件存储模块) diff --git a/zh_CN/upgrade/v1.6.md b/zh_CN/upgrade/v1.6.md index 319f27cea..ae83c69a8 100644 --- a/zh_CN/upgrade/v1.6.md +++ b/zh_CN/upgrade/v1.6.md @@ -1,7 +1,5 @@ # 从 v1.5 升级到 v1.6 -[[toc]] - ## 高影响变化 - [新增用户授权模块](#新增用户授权模块) diff --git a/zh_CN/upgrade/v1.7.md b/zh_CN/upgrade/v1.7.md index 6fb944ba3..bb9cbd1e0 100644 --- a/zh_CN/upgrade/v1.7.md +++ b/zh_CN/upgrade/v1.7.md @@ -1,7 +1,5 @@ # 从 v1.6 升级到 v1.7 -[[toc]] - ## 高影响变化 - [新增表单验证模块(v1.7.0)](#新增表单验证模块) diff --git a/zh_CN/upgrade/v1.8.md b/zh_CN/upgrade/v1.8.md index a02e308a2..a1a12e58f 100644 --- a/zh_CN/upgrade/v1.8.md +++ b/zh_CN/upgrade/v1.8.md @@ -1,7 +1,5 @@ # 从 v1.7 升级到 v1.8 -[[toc]] - ## 令人兴奋的新功能 🎉 - [Orm 新增模型关联(1.8.0)](#orm-新增模型关联) diff --git a/zh_CN/upgrade/v1.9.md b/zh_CN/upgrade/v1.9.md index 0d4f7e3d0..cc5aee9c4 100644 --- a/zh_CN/upgrade/v1.9.md +++ b/zh_CN/upgrade/v1.9.md @@ -1,7 +1,5 @@ # 从 v1.8 升级到 v1.9 -[[toc]] - ## 功能增强 🚀 - [新增数据库读写分离(1.9.0)](#新增数据库读写分离)