mirror of
https://github.com/tauri-apps/tauri-docs.git
synced 2026-01-31 00:35:16 +01:00
fix: tabs are a sin
This commit is contained in:
54
.prettierrc
54
.prettierrc
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": true,
|
||||
"plugins": ["prettier-plugin-astro"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.astro",
|
||||
"options": {
|
||||
"parser": "astro"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.json", "*.md", "*.toml", "*.yml"],
|
||||
"options": {
|
||||
"useTabs": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.md", "*.mdx"],
|
||||
"options": {
|
||||
"printWidth": 80
|
||||
}
|
||||
}
|
||||
]
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false,
|
||||
"plugins": ["prettier-plugin-astro"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.astro",
|
||||
"options": {
|
||||
"parser": "astro"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.json", "*.md", "*.toml", "*.yml"],
|
||||
"options": {
|
||||
"useTabs": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.md", "*.mdx"],
|
||||
"options": {
|
||||
"printWidth": 80
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
750
astro.config.mjs
750
astro.config.mjs
@@ -8,395 +8,395 @@ import starlightBlog from 'starlight-blog';
|
||||
import serviceWorker from 'astrojs-service-worker';
|
||||
|
||||
const authors = {
|
||||
nothingismagick: {
|
||||
name: 'Daniel Thompson-Yvetot',
|
||||
title: 'Tauri Co-Founder',
|
||||
picture: '/authors/nothingismagick.jpeg',
|
||||
},
|
||||
lucasfernog: {
|
||||
name: 'Lucas Nogueira',
|
||||
title: 'Tauri Co-Founder',
|
||||
picture: '/authors/lucasfernog.jpeg',
|
||||
},
|
||||
beanow: {
|
||||
name: 'Robin van Boven',
|
||||
title: 'Tauri Board Director',
|
||||
picture: '/authors/Beanow.png',
|
||||
},
|
||||
jbolda: {
|
||||
name: 'Jacob Bolda',
|
||||
title: 'Tauri Board Director',
|
||||
picture: '/authors/jbolda.jpeg',
|
||||
},
|
||||
lorenzolewis: {
|
||||
name: 'Lorenzo Lewis',
|
||||
title: 'Tauri Community Lead',
|
||||
picture: '/authors/lorenzolewis.png',
|
||||
},
|
||||
tweidinger: {
|
||||
name: 'Tillmann Weidinger',
|
||||
title: 'Tauri Security',
|
||||
picture: '/authors/tweidinger.png',
|
||||
},
|
||||
amrbashir: {
|
||||
name: 'Amr Bashir',
|
||||
title: 'Tauri Development',
|
||||
picture: '/authors/amrbashir.png',
|
||||
},
|
||||
wusyong: {
|
||||
name: 'Wu Yu Wei',
|
||||
title: 'Tauri Development Lead',
|
||||
picture: '/authors/wusyong.png',
|
||||
},
|
||||
chip: {
|
||||
name: 'Chip Reed',
|
||||
title: 'Tauri Security',
|
||||
picture: '/authors/chip.png',
|
||||
},
|
||||
nothingismagick: {
|
||||
name: 'Daniel Thompson-Yvetot',
|
||||
title: 'Tauri Co-Founder',
|
||||
picture: '/authors/nothingismagick.jpeg',
|
||||
},
|
||||
lucasfernog: {
|
||||
name: 'Lucas Nogueira',
|
||||
title: 'Tauri Co-Founder',
|
||||
picture: '/authors/lucasfernog.jpeg',
|
||||
},
|
||||
beanow: {
|
||||
name: 'Robin van Boven',
|
||||
title: 'Tauri Board Director',
|
||||
picture: '/authors/Beanow.png',
|
||||
},
|
||||
jbolda: {
|
||||
name: 'Jacob Bolda',
|
||||
title: 'Tauri Board Director',
|
||||
picture: '/authors/jbolda.jpeg',
|
||||
},
|
||||
lorenzolewis: {
|
||||
name: 'Lorenzo Lewis',
|
||||
title: 'Tauri Community Lead',
|
||||
picture: '/authors/lorenzolewis.png',
|
||||
},
|
||||
tweidinger: {
|
||||
name: 'Tillmann Weidinger',
|
||||
title: 'Tauri Security',
|
||||
picture: '/authors/tweidinger.png',
|
||||
},
|
||||
amrbashir: {
|
||||
name: 'Amr Bashir',
|
||||
title: 'Tauri Development',
|
||||
picture: '/authors/amrbashir.png',
|
||||
},
|
||||
wusyong: {
|
||||
name: 'Wu Yu Wei',
|
||||
title: 'Tauri Development Lead',
|
||||
picture: '/authors/wusyong.png',
|
||||
},
|
||||
chip: {
|
||||
name: 'Chip Reed',
|
||||
title: 'Tauri Security',
|
||||
picture: '/authors/chip.png',
|
||||
},
|
||||
};
|
||||
|
||||
const site = 'https://v2.tauri.app';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site,
|
||||
integrations: [
|
||||
starlight({
|
||||
plugins: [
|
||||
starlightBlog({ authors }),
|
||||
starlightLinksValidator({ errorOnRelativeLinks: false }),
|
||||
],
|
||||
title: 'Tauri',
|
||||
description: 'The cross-platform app building toolkit',
|
||||
logo: {
|
||||
dark: './src/assets/logo.svg',
|
||||
light: './src/assets/logo_light.svg',
|
||||
replacesTitle: true,
|
||||
},
|
||||
social: {
|
||||
github: 'https://github.com/tauri-apps/tauri',
|
||||
discord: 'https://discord.com/invite/tauri',
|
||||
twitter: 'https://twitter.com/TauriApps',
|
||||
mastodon: 'https://fosstodon.org/@TauriApps',
|
||||
rss: `${site}/rss`,
|
||||
},
|
||||
components: {
|
||||
Sidebar: './src/components/overrides/Sidebar.astro',
|
||||
Header: './src/components/overrides/Header.astro',
|
||||
Footer: 'src/components/overrides/Footer.astro',
|
||||
ThemeSelect: 'src/components/overrides/ThemeSelect.astro',
|
||||
PageFrame: 'src/components/overrides/PageFrame.astro',
|
||||
},
|
||||
head: [
|
||||
{
|
||||
tag: 'meta',
|
||||
attrs: { property: 'og:image', content: site + '/og.png?v=1' },
|
||||
},
|
||||
{
|
||||
tag: 'meta',
|
||||
attrs: { property: 'twitter:image', content: site + '/og.png?v=1' },
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: '/navigate.js',
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: 'link',
|
||||
attrs: {
|
||||
rel: 'manifest',
|
||||
href: '/manifest.json',
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: 'meta',
|
||||
attrs: { name: 'theme-color', content: '#181818' },
|
||||
},
|
||||
],
|
||||
editLink: {
|
||||
baseUrl: 'https://github.com/tauri-apps/tauri-docs/edit/v2',
|
||||
},
|
||||
customCss: ['./src/styles/custom.scss'],
|
||||
sidebar: [
|
||||
{
|
||||
label: 'Guides',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Quick Start',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'What is Tauri?',
|
||||
link: '/start/',
|
||||
},
|
||||
{
|
||||
label: 'Prerequisites',
|
||||
link: '/start/prerequisites/',
|
||||
},
|
||||
{
|
||||
label: 'Create a Project',
|
||||
link: '/start/create-project/',
|
||||
badge: {
|
||||
text: 'WIP',
|
||||
variant: 'caution',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Frontend Configuration',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'start/frontend' },
|
||||
},
|
||||
{
|
||||
label: 'Upgrade & Migrate',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'start/migrate' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Core Concepts',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'concept' },
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'security' },
|
||||
},
|
||||
{
|
||||
label: 'Develop',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'develop' },
|
||||
},
|
||||
{
|
||||
label: 'Distribute',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'distribute' },
|
||||
},
|
||||
{
|
||||
label: 'Learn',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'learn' },
|
||||
},
|
||||
{
|
||||
label: 'Plugins',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'plugin' },
|
||||
},
|
||||
{
|
||||
label: 'About',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'about' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'References',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Access Control List',
|
||||
link: '/reference/acl/',
|
||||
},
|
||||
{
|
||||
label: 'Command Line Interface (CLI)',
|
||||
link: '/reference/cli/',
|
||||
},
|
||||
{
|
||||
label: 'Configuration',
|
||||
link: '/reference/config/',
|
||||
},
|
||||
{
|
||||
label: 'Environment Variables',
|
||||
link: '/reference/environment-variables/',
|
||||
},
|
||||
{
|
||||
label: 'Webview Versions',
|
||||
link: '/reference/webview-versions/',
|
||||
},
|
||||
{
|
||||
label: 'Releases',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'release' },
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'reference/javascript' },
|
||||
},
|
||||
{
|
||||
label: 'Rust (docs.rs)',
|
||||
link: 'https://docs.rs/tauri/2.0.0-beta.19/tauri/index.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Blog',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'All posts',
|
||||
link: '/blog/',
|
||||
},
|
||||
{
|
||||
label: 'Recent posts',
|
||||
collapsed: false,
|
||||
autogenerate: { directory: 'blog' }, // TODO: Manually construct `items` to sort by dates
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
locales,
|
||||
lastUpdated: true,
|
||||
}),
|
||||
serviceWorker({
|
||||
workbox: {
|
||||
cleanupOutdatedCaches: true,
|
||||
clientsClaim: true,
|
||||
inlineWorkboxRuntime: true,
|
||||
skipWaiting: true,
|
||||
globIgnores: ['**_redirects**', '**_headers**'],
|
||||
globPatterns: ['**/*.js', '**/*.css'],
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: new RegExp('.*'),
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'tauri-runtime',
|
||||
expiration: {
|
||||
maxAgeSeconds: 30 * 60, // 30 minutes
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
langs: ['powershell', 'ts', 'rust', 'bash', 'json', 'toml', 'html', 'js'],
|
||||
},
|
||||
rehypePlugins: [
|
||||
rehypeHeadingIds,
|
||||
[
|
||||
rehypeAutolinkHeadings,
|
||||
{
|
||||
behavior: 'wrap',
|
||||
properties: { ariaHidden: true, tabIndex: -1, class: 'heading-link' },
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
redirects: {
|
||||
// Old blog url schema redirects
|
||||
'/blog/2022/06/19/tauri-1-0': '/blog/tauri-1-0',
|
||||
'/blog/tauri_1_0': '/blog/tauri-1-0',
|
||||
'/blog/2022/07/12/tauri-programme-turns-1-and-board-elections':
|
||||
'/blog/tauri-programme-turns-1-and-board-elections',
|
||||
'/blog/2022/09/15/tauri-1-1': '/blog/tauri-1-1',
|
||||
'/blog/2022/09/19/tauri-egui-0-1': '/blog/tauri-egui-0-1',
|
||||
'/blog/2022/11/18/tauri-1-2': '/blog/tauri-1-2',
|
||||
'/blog/2022/12/09/tauri-mobile-alpha': '/blog/tauri-mobile-alpha',
|
||||
'/blog/2023/02/03/tauri-2-0-0-alpha-3': '/blog/tauri-2-0-0-alpha-3',
|
||||
'/blog/2023/02/09/tauri-community-growth-and-feedback':
|
||||
'/blog/tauri-community-growth-and-feedback',
|
||||
'/blog/2023/03/01/create-tauri-app-version-3-released':
|
||||
'/blog/create-tauri-app-version-3-released',
|
||||
'/blog/2023/03/20/tauri-2-0-0-alpha-4': '/blog/tauri-2-0-0-alpha-4',
|
||||
'/blog/2023/05/03/tauri-1-3': '/blog/tauri-1-3',
|
||||
'/blog/2023/06/14/tauri-1-4': '/blog/tauri-1-4',
|
||||
'/blog/2023/06/15/tauri-board-elections-and-governance-updates':
|
||||
'/blog/tauri-board-elections-and-governance-updates',
|
||||
'about/intro': 'about/philosophy',
|
||||
// v1 /guides/debugging -> /guides/debug
|
||||
...i18nRedirect('/v1/guides/debugging/application', '/guides/debug/application'),
|
||||
...i18nRedirect('/v1/guides/debugging/vs-code', '/guides/debug/vs-code'),
|
||||
...i18nRedirect('/v1/guides/debugging/clion', '/guides/debug/clion'),
|
||||
// v1 /guides/development -> /guides/develop
|
||||
...i18nRedirect(
|
||||
'/v1/guides/development/development-cycle',
|
||||
'/guides/develop/development-cycle'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/development/updating-dependencies',
|
||||
'/guides/develop/updating-dependencies'
|
||||
),
|
||||
// v1 /guides/testing -> /guides/test
|
||||
...i18nRedirect('/v1/guides/testing/mocking', '/guides/test/mocking'),
|
||||
...i18nRedirect('/v1/guides/testing/webdriver/ci', '/guides/test/webdriver/ci'),
|
||||
...i18nRedirect('/v1/guides/testing/webdriver/introduction', '/guides/test/webdriver/'),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/testing/webdriver/example/setup',
|
||||
'/guides/test/webdriver/example/'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/testing/webdriver/example/selenium',
|
||||
'/guides/test/webdriver/example/selenium'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/testing/webdriver/example/webdriverio',
|
||||
'/test/webdriver/example/webdriverio'
|
||||
),
|
||||
site,
|
||||
integrations: [
|
||||
starlight({
|
||||
plugins: [
|
||||
starlightBlog({ authors }),
|
||||
starlightLinksValidator({ errorOnRelativeLinks: false }),
|
||||
],
|
||||
title: 'Tauri',
|
||||
description: 'The cross-platform app building toolkit',
|
||||
logo: {
|
||||
dark: './src/assets/logo.svg',
|
||||
light: './src/assets/logo_light.svg',
|
||||
replacesTitle: true,
|
||||
},
|
||||
social: {
|
||||
github: 'https://github.com/tauri-apps/tauri',
|
||||
discord: 'https://discord.com/invite/tauri',
|
||||
twitter: 'https://twitter.com/TauriApps',
|
||||
mastodon: 'https://fosstodon.org/@TauriApps',
|
||||
rss: `${site}/rss`,
|
||||
},
|
||||
components: {
|
||||
Sidebar: './src/components/overrides/Sidebar.astro',
|
||||
Header: './src/components/overrides/Header.astro',
|
||||
Footer: 'src/components/overrides/Footer.astro',
|
||||
ThemeSelect: 'src/components/overrides/ThemeSelect.astro',
|
||||
PageFrame: 'src/components/overrides/PageFrame.astro',
|
||||
},
|
||||
head: [
|
||||
{
|
||||
tag: 'meta',
|
||||
attrs: { property: 'og:image', content: site + '/og.png?v=1' },
|
||||
},
|
||||
{
|
||||
tag: 'meta',
|
||||
attrs: { property: 'twitter:image', content: site + '/og.png?v=1' },
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: '/navigate.js',
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: 'link',
|
||||
attrs: {
|
||||
rel: 'manifest',
|
||||
href: '/manifest.json',
|
||||
},
|
||||
},
|
||||
{
|
||||
tag: 'meta',
|
||||
attrs: { name: 'theme-color', content: '#181818' },
|
||||
},
|
||||
],
|
||||
editLink: {
|
||||
baseUrl: 'https://github.com/tauri-apps/tauri-docs/edit/v2',
|
||||
},
|
||||
customCss: ['./src/styles/custom.scss'],
|
||||
sidebar: [
|
||||
{
|
||||
label: 'Guides',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Quick Start',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'What is Tauri?',
|
||||
link: '/start/',
|
||||
},
|
||||
{
|
||||
label: 'Prerequisites',
|
||||
link: '/start/prerequisites/',
|
||||
},
|
||||
{
|
||||
label: 'Create a Project',
|
||||
link: '/start/create-project/',
|
||||
badge: {
|
||||
text: 'WIP',
|
||||
variant: 'caution',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Frontend Configuration',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'start/frontend' },
|
||||
},
|
||||
{
|
||||
label: 'Upgrade & Migrate',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'start/migrate' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Core Concepts',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'concept' },
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'security' },
|
||||
},
|
||||
{
|
||||
label: 'Develop',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'develop' },
|
||||
},
|
||||
{
|
||||
label: 'Distribute',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'distribute' },
|
||||
},
|
||||
{
|
||||
label: 'Learn',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'learn' },
|
||||
},
|
||||
{
|
||||
label: 'Plugins',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'plugin' },
|
||||
},
|
||||
{
|
||||
label: 'About',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'about' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'References',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Access Control List',
|
||||
link: '/reference/acl/',
|
||||
},
|
||||
{
|
||||
label: 'Command Line Interface (CLI)',
|
||||
link: '/reference/cli/',
|
||||
},
|
||||
{
|
||||
label: 'Configuration',
|
||||
link: '/reference/config/',
|
||||
},
|
||||
{
|
||||
label: 'Environment Variables',
|
||||
link: '/reference/environment-variables/',
|
||||
},
|
||||
{
|
||||
label: 'Webview Versions',
|
||||
link: '/reference/webview-versions/',
|
||||
},
|
||||
{
|
||||
label: 'Releases',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'release' },
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
collapsed: true,
|
||||
autogenerate: { directory: 'reference/javascript' },
|
||||
},
|
||||
{
|
||||
label: 'Rust (docs.rs)',
|
||||
link: 'https://docs.rs/tauri/2.0.0-beta.19/tauri/index.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Blog',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{
|
||||
label: 'All posts',
|
||||
link: '/blog/',
|
||||
},
|
||||
{
|
||||
label: 'Recent posts',
|
||||
collapsed: false,
|
||||
autogenerate: { directory: 'blog' }, // TODO: Manually construct `items` to sort by dates
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
locales,
|
||||
lastUpdated: true,
|
||||
}),
|
||||
serviceWorker({
|
||||
workbox: {
|
||||
cleanupOutdatedCaches: true,
|
||||
clientsClaim: true,
|
||||
inlineWorkboxRuntime: true,
|
||||
skipWaiting: true,
|
||||
globIgnores: ['**_redirects**', '**_headers**'],
|
||||
globPatterns: ['**/*.js', '**/*.css'],
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: new RegExp('.*'),
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'tauri-runtime',
|
||||
expiration: {
|
||||
maxAgeSeconds: 30 * 60, // 30 minutes
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
langs: ['powershell', 'ts', 'rust', 'bash', 'json', 'toml', 'html', 'js'],
|
||||
},
|
||||
rehypePlugins: [
|
||||
rehypeHeadingIds,
|
||||
[
|
||||
rehypeAutolinkHeadings,
|
||||
{
|
||||
behavior: 'wrap',
|
||||
properties: { ariaHidden: true, tabIndex: -1, class: 'heading-link' },
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
redirects: {
|
||||
// Old blog url schema redirects
|
||||
'/blog/2022/06/19/tauri-1-0': '/blog/tauri-1-0',
|
||||
'/blog/tauri_1_0': '/blog/tauri-1-0',
|
||||
'/blog/2022/07/12/tauri-programme-turns-1-and-board-elections':
|
||||
'/blog/tauri-programme-turns-1-and-board-elections',
|
||||
'/blog/2022/09/15/tauri-1-1': '/blog/tauri-1-1',
|
||||
'/blog/2022/09/19/tauri-egui-0-1': '/blog/tauri-egui-0-1',
|
||||
'/blog/2022/11/18/tauri-1-2': '/blog/tauri-1-2',
|
||||
'/blog/2022/12/09/tauri-mobile-alpha': '/blog/tauri-mobile-alpha',
|
||||
'/blog/2023/02/03/tauri-2-0-0-alpha-3': '/blog/tauri-2-0-0-alpha-3',
|
||||
'/blog/2023/02/09/tauri-community-growth-and-feedback':
|
||||
'/blog/tauri-community-growth-and-feedback',
|
||||
'/blog/2023/03/01/create-tauri-app-version-3-released':
|
||||
'/blog/create-tauri-app-version-3-released',
|
||||
'/blog/2023/03/20/tauri-2-0-0-alpha-4': '/blog/tauri-2-0-0-alpha-4',
|
||||
'/blog/2023/05/03/tauri-1-3': '/blog/tauri-1-3',
|
||||
'/blog/2023/06/14/tauri-1-4': '/blog/tauri-1-4',
|
||||
'/blog/2023/06/15/tauri-board-elections-and-governance-updates':
|
||||
'/blog/tauri-board-elections-and-governance-updates',
|
||||
'about/intro': 'about/philosophy',
|
||||
// v1 /guides/debugging -> /guides/debug
|
||||
...i18nRedirect('/v1/guides/debugging/application', '/guides/debug/application'),
|
||||
...i18nRedirect('/v1/guides/debugging/vs-code', '/guides/debug/vs-code'),
|
||||
...i18nRedirect('/v1/guides/debugging/clion', '/guides/debug/clion'),
|
||||
// v1 /guides/development -> /guides/develop
|
||||
...i18nRedirect(
|
||||
'/v1/guides/development/development-cycle',
|
||||
'/guides/develop/development-cycle'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/development/updating-dependencies',
|
||||
'/guides/develop/updating-dependencies'
|
||||
),
|
||||
// v1 /guides/testing -> /guides/test
|
||||
...i18nRedirect('/v1/guides/testing/mocking', '/guides/test/mocking'),
|
||||
...i18nRedirect('/v1/guides/testing/webdriver/ci', '/guides/test/webdriver/ci'),
|
||||
...i18nRedirect('/v1/guides/testing/webdriver/introduction', '/guides/test/webdriver/'),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/testing/webdriver/example/setup',
|
||||
'/guides/test/webdriver/example/'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/testing/webdriver/example/selenium',
|
||||
'/guides/test/webdriver/example/selenium'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/guides/testing/webdriver/example/webdriverio',
|
||||
'/test/webdriver/example/webdriverio'
|
||||
),
|
||||
|
||||
// v1 /references
|
||||
...i18nRedirect('/v1/references', '/concepts'),
|
||||
...i18nRedirect('/v1/reference/architecture', '/concepts/architecture'),
|
||||
...i18nRedirect('/v1/reference/architecture/process-model', '/concepts/process-model'),
|
||||
...i18nRedirect('/v1/reference/architecture/security', '/concepts/tauri-security'),
|
||||
...i18nRedirect(
|
||||
'/v1/reference/architecture/inter-process-communication',
|
||||
'/concepts/inter-process-communication'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/reference/architecture/inter-process-communication/brownfield',
|
||||
'/concepts/inter-process-communication/brownfield'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/reference/architecture/inter-process-communication/isolation',
|
||||
'/concepts/inter-process-communication/isolation'
|
||||
),
|
||||
...i18nRedirect('/v1/reference/security', '/concepts/development-security'),
|
||||
...i18nRedirect('/v1/reference/configuration-files', '/reference/configuration-files'),
|
||||
...i18nRedirect('/v1/reference/webview-versions', '/reference/webview-versions'),
|
||||
// v1 /references
|
||||
...i18nRedirect('/v1/references', '/concepts'),
|
||||
...i18nRedirect('/v1/reference/architecture', '/concepts/architecture'),
|
||||
...i18nRedirect('/v1/reference/architecture/process-model', '/concepts/process-model'),
|
||||
...i18nRedirect('/v1/reference/architecture/security', '/concepts/tauri-security'),
|
||||
...i18nRedirect(
|
||||
'/v1/reference/architecture/inter-process-communication',
|
||||
'/concepts/inter-process-communication'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/reference/architecture/inter-process-communication/brownfield',
|
||||
'/concepts/inter-process-communication/brownfield'
|
||||
),
|
||||
...i18nRedirect(
|
||||
'/v1/reference/architecture/inter-process-communication/isolation',
|
||||
'/concepts/inter-process-communication/isolation'
|
||||
),
|
||||
...i18nRedirect('/v1/reference/security', '/concepts/development-security'),
|
||||
...i18nRedirect('/v1/reference/configuration-files', '/reference/configuration-files'),
|
||||
...i18nRedirect('/v1/reference/webview-versions', '/reference/webview-versions'),
|
||||
|
||||
// Decommissioned locales -> refer to /public/_redirects file
|
||||
// '/ko/[...slug]': '/[...slug]',
|
||||
// '/it/[...slug]': '/[...slug]',
|
||||
},
|
||||
server: {
|
||||
headers: readHeaders(),
|
||||
},
|
||||
//
|
||||
// Decommissioned locales -> refer to /public/_redirects file
|
||||
// '/ko/[...slug]': '/[...slug]',
|
||||
// '/it/[...slug]': '/[...slug]',
|
||||
},
|
||||
server: {
|
||||
headers: readHeaders(),
|
||||
},
|
||||
//
|
||||
});
|
||||
|
||||
// Generates a redirect for each locale.
|
||||
function i18nRedirect(from, to) {
|
||||
const routes = {};
|
||||
Object.keys(locales).map((locale) =>
|
||||
locale === 'root'
|
||||
? (routes[from] = to)
|
||||
: (routes[`/${locale}/${from.replaceAll(/^\/*/g, '')}`] = `/${locale}/${to.replaceAll(
|
||||
/^\/*/g,
|
||||
''
|
||||
)}`)
|
||||
);
|
||||
return routes;
|
||||
const routes = {};
|
||||
Object.keys(locales).map((locale) =>
|
||||
locale === 'root'
|
||||
? (routes[from] = to)
|
||||
: (routes[`/${locale}/${from.replaceAll(/^\/*/g, '')}`] = `/${locale}/${to.replaceAll(
|
||||
/^\/*/g,
|
||||
''
|
||||
)}`)
|
||||
);
|
||||
return routes;
|
||||
}
|
||||
|
||||
// Read the HTTP header file in `public/_headers`
|
||||
function readHeaders() {
|
||||
const header_file = fs
|
||||
.readFileSync('public/_headers', { encoding: 'utf8' })
|
||||
.split('\n')
|
||||
.filter(Boolean);
|
||||
const headers = {};
|
||||
for (const line of header_file) {
|
||||
const [key, val] = line.trim().split(/\s*:\s*(.+)/);
|
||||
if (key != undefined && val != undefined) {
|
||||
headers[key] = val.toString();
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
const header_file = fs
|
||||
.readFileSync('public/_headers', { encoding: 'utf8' })
|
||||
.split('\n')
|
||||
.filter(Boolean);
|
||||
const headers = {};
|
||||
for (const line of header_file) {
|
||||
const [key, val] = line.trim().split(/\s*:\s*(.+)/);
|
||||
if (key != undefined && val != undefined) {
|
||||
headers[key] = val.toString();
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
@@ -3,69 +3,69 @@ import { existsSync, writeFileSync } from 'node:fs';
|
||||
import { slug } from 'github-slugger';
|
||||
|
||||
buildConfig(
|
||||
'../tauri/core/tauri-config-schema/schema.json',
|
||||
'../../src/content/docs/reference/config.md'
|
||||
'../tauri/core/tauri-config-schema/schema.json',
|
||||
'../../src/content/docs/reference/config.md'
|
||||
);
|
||||
|
||||
async function buildConfig(schemaFile: string, outputFile: string) {
|
||||
if (!existsSync(schemaFile)) {
|
||||
throw Error('Could not find the Tauri config schema. Is the Tauri submodule initialized?');
|
||||
}
|
||||
if (!existsSync(schemaFile)) {
|
||||
throw Error('Could not find the Tauri config schema. Is the Tauri submodule initialized?');
|
||||
}
|
||||
|
||||
let schema: JSONSchema7 = (await import(schemaFile)).default;
|
||||
let schema: JSONSchema7 = (await import(schemaFile)).default;
|
||||
|
||||
const output = [
|
||||
'---\n# NOTE: This file is auto-generated in packages/config-generator/build.ts\n# For corrections please edit https://github.com/tauri-apps/tauri/blob/dev/core/tauri-utils/src/config.rs directly\n\ntitle: Configuration\nsidebar:\n order: 1\n---',
|
||||
];
|
||||
const output = [
|
||||
'---\n# NOTE: This file is auto-generated in packages/config-generator/build.ts\n# For corrections please edit https://github.com/tauri-apps/tauri/blob/dev/core/tauri-utils/src/config.rs directly\n\ntitle: Configuration\nsidebar:\n order: 1\n---',
|
||||
];
|
||||
|
||||
output.push(
|
||||
...buildSchemaDefinition(schema, {
|
||||
headingLevel: 2,
|
||||
renderTitle: false,
|
||||
})
|
||||
);
|
||||
output.push(
|
||||
...buildSchemaDefinition(schema, {
|
||||
headingLevel: 2,
|
||||
renderTitle: false,
|
||||
})
|
||||
);
|
||||
|
||||
writeFileSync(outputFile, output.join('\n\n'));
|
||||
writeFileSync(outputFile, output.join('\n\n'));
|
||||
}
|
||||
|
||||
interface Options {
|
||||
headingLevel: number;
|
||||
renderTitle: boolean;
|
||||
leadWithType: boolean;
|
||||
headingLevel: number;
|
||||
renderTitle: boolean;
|
||||
leadWithType: boolean;
|
||||
}
|
||||
|
||||
function buildSchemaDefinition(
|
||||
schema: JSONSchema7Definition,
|
||||
passedOptions: Partial<Options> = {}
|
||||
schema: JSONSchema7Definition,
|
||||
passedOptions: Partial<Options> = {}
|
||||
): string[] {
|
||||
// Note: $id, $schema, and $comment are explicitly not rendered
|
||||
// Note: $id, $schema, and $comment are explicitly not rendered
|
||||
|
||||
// Assign default values for any missing options
|
||||
const opts = Object.assign(
|
||||
{
|
||||
headingLevel: 1,
|
||||
renderTitle: true,
|
||||
leadWithType: false,
|
||||
},
|
||||
passedOptions
|
||||
);
|
||||
// Assign default values for any missing options
|
||||
const opts = Object.assign(
|
||||
{
|
||||
headingLevel: 1,
|
||||
renderTitle: true,
|
||||
leadWithType: false,
|
||||
},
|
||||
passedOptions
|
||||
);
|
||||
|
||||
if (typeof schema === 'boolean') {
|
||||
return [`\`${schema}\``];
|
||||
}
|
||||
if (typeof schema === 'boolean') {
|
||||
return [`\`${schema}\``];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
out.push(...buildType(schema, opts));
|
||||
out.push(...buildExtendedItems(schema, opts));
|
||||
out.push(...buildConditionalSubschemas(schema, opts));
|
||||
out.push(...buildBooleanSubschemas(schema, opts));
|
||||
out.push(...buildMetadata(schema, opts));
|
||||
out.push(...buildProperties(schema, opts));
|
||||
out.push(...buildExtendedMetadata(schema, opts));
|
||||
out.push(...buildDefinitions(schema, opts));
|
||||
out.push(...buildType(schema, opts));
|
||||
out.push(...buildExtendedItems(schema, opts));
|
||||
out.push(...buildConditionalSubschemas(schema, opts));
|
||||
out.push(...buildBooleanSubschemas(schema, opts));
|
||||
out.push(...buildMetadata(schema, opts));
|
||||
out.push(...buildProperties(schema, opts));
|
||||
out.push(...buildExtendedMetadata(schema, opts));
|
||||
out.push(...buildDefinitions(schema, opts));
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,37 +74,37 @@ function buildSchemaDefinition(
|
||||
* Also see: buildExtendedMetadata()
|
||||
*/
|
||||
function buildMetadata(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
opts.renderTitle &&
|
||||
schema.title &&
|
||||
out.push(`${'#'.repeat(Math.min(opts.headingLevel, 6))} ${schema.title}`);
|
||||
opts.renderTitle &&
|
||||
schema.title &&
|
||||
out.push(`${'#'.repeat(Math.min(opts.headingLevel, 6))} ${schema.title}`);
|
||||
|
||||
if (schema.readOnly || schema.writeOnly) {
|
||||
const line = [];
|
||||
schema.readOnly && line.push('Read only');
|
||||
schema.writeOnly && line.push('Write only');
|
||||
out.push(line.join(' & '));
|
||||
}
|
||||
if (schema.readOnly || schema.writeOnly) {
|
||||
const line = [];
|
||||
schema.readOnly && line.push('Read only');
|
||||
schema.writeOnly && line.push('Write only');
|
||||
out.push(line.join(' & '));
|
||||
}
|
||||
|
||||
schema.description &&
|
||||
out.push(
|
||||
schema.description
|
||||
// Set headings to appropriate level
|
||||
.replaceAll(/#{1,6}(?=.+[\n\\n])/g, '#'.repeat(Math.min(opts.headingLevel + 1, 6)))
|
||||
// Fix improperly formatted heading links
|
||||
.replaceAll(/#{1,6}(?=[^\s#])/g, '#')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
// Fix for link at https://github.com/tauri-apps/tauri/blob/713f84db2b5bf17e4217053a229f9c11cbb22c74/core/tauri-config-schema/schema.json#L1863-L1864
|
||||
.replace('#SecurityConfig.devCsp', '#securityconfig')
|
||||
);
|
||||
schema.description &&
|
||||
out.push(
|
||||
schema.description
|
||||
// Set headings to appropriate level
|
||||
.replaceAll(/#{1,6}(?=.+[\n\\n])/g, '#'.repeat(Math.min(opts.headingLevel + 1, 6)))
|
||||
// Fix improperly formatted heading links
|
||||
.replaceAll(/#{1,6}(?=[^\s#])/g, '#')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
// Fix for link at https://github.com/tauri-apps/tauri/blob/713f84db2b5bf17e4217053a229f9c11cbb22c74/core/tauri-config-schema/schema.json#L1863-L1864
|
||||
.replace('#SecurityConfig.devCsp', '#securityconfig')
|
||||
);
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,318 +117,318 @@ function buildMetadata(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
* Non-JSON data validation: contentMediaType, contentEncoding
|
||||
*/
|
||||
function buildType(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
let line: string = '';
|
||||
let line: string = '';
|
||||
|
||||
if (schema.type) {
|
||||
if (Array.isArray(schema.type)) {
|
||||
line += schema.type.map((value) => buildTypeName(value, schema, opts)).join(' | ');
|
||||
} else {
|
||||
line += buildTypeName(schema.type, schema, opts);
|
||||
}
|
||||
}
|
||||
if (schema.type) {
|
||||
if (Array.isArray(schema.type)) {
|
||||
line += schema.type.map((value) => buildTypeName(value, schema, opts)).join(' | ');
|
||||
} else {
|
||||
line += buildTypeName(schema.type, schema, opts);
|
||||
}
|
||||
}
|
||||
|
||||
if (schema.$ref) {
|
||||
const reference = schema.$ref.split('/').pop();
|
||||
if (schema.$ref) {
|
||||
const reference = schema.$ref.split('/').pop();
|
||||
|
||||
if (!reference) {
|
||||
throw Error(`Invalid reference: ${schema.$ref}`);
|
||||
}
|
||||
if (!reference) {
|
||||
throw Error(`Invalid reference: ${schema.$ref}`);
|
||||
}
|
||||
|
||||
line += `[\`${reference}\`](#${slug(reference)})`;
|
||||
}
|
||||
line += `[\`${reference}\`](#${slug(reference)})`;
|
||||
}
|
||||
|
||||
if (schema.const) {
|
||||
switch (typeof schema.const) {
|
||||
case 'string':
|
||||
line += `\`"${schema.const}"\``;
|
||||
break;
|
||||
default:
|
||||
line += `\`${schema.const}\``;
|
||||
}
|
||||
}
|
||||
if (schema.const) {
|
||||
switch (typeof schema.const) {
|
||||
case 'string':
|
||||
line += `\`"${schema.const}"\``;
|
||||
break;
|
||||
default:
|
||||
line += `\`${schema.const}\``;
|
||||
}
|
||||
}
|
||||
|
||||
if (schema.enum) {
|
||||
const enumValues: string[] = [];
|
||||
schema.enum.forEach((value) => {
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
enumValues.push(`\`"${value}"\``);
|
||||
break;
|
||||
default:
|
||||
enumValues.push(`\`${value}\``);
|
||||
}
|
||||
});
|
||||
line += enumValues.join(' | ');
|
||||
}
|
||||
if (schema.enum) {
|
||||
const enumValues: string[] = [];
|
||||
schema.enum.forEach((value) => {
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
enumValues.push(`\`"${value}"\``);
|
||||
break;
|
||||
default:
|
||||
enumValues.push(`\`${value}\``);
|
||||
}
|
||||
});
|
||||
line += enumValues.join(' | ');
|
||||
}
|
||||
|
||||
const validation = [];
|
||||
const validation = [];
|
||||
|
||||
// Number validation
|
||||
schema.multipleOf && validation.push(`multiple of \`${schema.multipleOf}\``);
|
||||
schema.maximum && validation.push(`maximum of \`${schema.maximum}\``);
|
||||
schema.exclusiveMaximum && validation.push(`exclusive maximum of \`${schema.exclusiveMaximum}\``);
|
||||
schema.minimum && validation.push(`minimum of \`${schema.minimum}\``);
|
||||
schema.exclusiveMinimum && validation.push(`exclusive minimum of \`${schema.exclusiveMinimum}\``);
|
||||
// Number validation
|
||||
schema.multipleOf && validation.push(`multiple of \`${schema.multipleOf}\``);
|
||||
schema.maximum && validation.push(`maximum of \`${schema.maximum}\``);
|
||||
schema.exclusiveMaximum && validation.push(`exclusive maximum of \`${schema.exclusiveMaximum}\``);
|
||||
schema.minimum && validation.push(`minimum of \`${schema.minimum}\``);
|
||||
schema.exclusiveMinimum && validation.push(`exclusive minimum of \`${schema.exclusiveMinimum}\``);
|
||||
|
||||
// String validation
|
||||
schema.maxLength && validation.push(`maximum length of \`${schema.maxLength}\``);
|
||||
schema.minLength && validation.push(`minimum length of \`${schema.minLength}\``);
|
||||
schema.pattern && validation.push(`pattern of \`${schema.pattern}\``);
|
||||
// String validation
|
||||
schema.maxLength && validation.push(`maximum length of \`${schema.maxLength}\``);
|
||||
schema.minLength && validation.push(`minimum length of \`${schema.minLength}\``);
|
||||
schema.pattern && validation.push(`pattern of \`${schema.pattern}\``);
|
||||
|
||||
// Array validation
|
||||
schema.maxItems && validation.push(`maximum of \`${schema.maxItems}\` items`);
|
||||
schema.minItems && validation.push(`minimum of \`${schema.minItems}\` items`);
|
||||
schema.uniqueItems && validation.push(`each item must be unique`);
|
||||
// Array validation
|
||||
schema.maxItems && validation.push(`maximum of \`${schema.maxItems}\` items`);
|
||||
schema.minItems && validation.push(`minimum of \`${schema.minItems}\` items`);
|
||||
schema.uniqueItems && validation.push(`each item must be unique`);
|
||||
|
||||
// Object validation
|
||||
schema.maxProperties && validation.push(`maximum of \`${schema.maxProperties}\` properties`);
|
||||
schema.minProperties && validation.push(`minimum of \`${schema.minProperties}\` properties`);
|
||||
// Object validation
|
||||
schema.maxProperties && validation.push(`maximum of \`${schema.maxProperties}\` properties`);
|
||||
schema.minProperties && validation.push(`minimum of \`${schema.minProperties}\` properties`);
|
||||
|
||||
// Semantic validation
|
||||
schema.format && validation.push(`formatted as \`${schema.format}\``);
|
||||
// Semantic validation
|
||||
schema.format && validation.push(`formatted as \`${schema.format}\``);
|
||||
|
||||
// Non-JSON data validation
|
||||
schema.contentMediaType &&
|
||||
validation.push(`content media type of \`${schema.contentMediaType}\``);
|
||||
schema.contentEncoding && validation.push(`content encoding of \`${schema.contentEncoding}\``);
|
||||
// Non-JSON data validation
|
||||
schema.contentMediaType &&
|
||||
validation.push(`content media type of \`${schema.contentMediaType}\``);
|
||||
schema.contentEncoding && validation.push(`content encoding of \`${schema.contentEncoding}\``);
|
||||
|
||||
if (validation.length > 0) {
|
||||
line += ' ' + validation.join(', ');
|
||||
}
|
||||
if (validation.length > 0) {
|
||||
line += ' ' + validation.join(', ');
|
||||
}
|
||||
|
||||
return [line];
|
||||
return [line];
|
||||
|
||||
function buildTypeName(
|
||||
typeName: JSONSchema7TypeName,
|
||||
parentSchema: JSONSchema7Definition,
|
||||
opts: Options
|
||||
): string {
|
||||
// Rendering logic for enums and consts are handled separately
|
||||
if (typeof parentSchema === 'object' && (parentSchema.enum || parentSchema.const)) {
|
||||
return '';
|
||||
}
|
||||
function buildTypeName(
|
||||
typeName: JSONSchema7TypeName,
|
||||
parentSchema: JSONSchema7Definition,
|
||||
opts: Options
|
||||
): string {
|
||||
// Rendering logic for enums and consts are handled separately
|
||||
if (typeof parentSchema === 'object' && (parentSchema.enum || parentSchema.const)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let line = '';
|
||||
switch (typeName) {
|
||||
case 'object':
|
||||
break;
|
||||
case 'array':
|
||||
if (typeof parentSchema !== 'object' || !parentSchema.items) {
|
||||
throw Error('Invalid array');
|
||||
}
|
||||
if (Array.isArray(parentSchema.items)) {
|
||||
line += parentSchema.items
|
||||
.map((value) => {
|
||||
const definition = buildSchemaDefinition(value, opts);
|
||||
if (definition.length > 1) {
|
||||
// Format additional information to be in parenthesis
|
||||
const [first, ...rest] = definition;
|
||||
return [first, ' (', rest.join(', '), ')'];
|
||||
} else {
|
||||
return definition.join();
|
||||
}
|
||||
})
|
||||
.join(' | ');
|
||||
} else {
|
||||
line += buildSchemaDefinition(parentSchema.items, opts);
|
||||
}
|
||||
line += '[]';
|
||||
break;
|
||||
default:
|
||||
line += '`' + typeName + '`';
|
||||
}
|
||||
return line;
|
||||
}
|
||||
let line = '';
|
||||
switch (typeName) {
|
||||
case 'object':
|
||||
break;
|
||||
case 'array':
|
||||
if (typeof parentSchema !== 'object' || !parentSchema.items) {
|
||||
throw Error('Invalid array');
|
||||
}
|
||||
if (Array.isArray(parentSchema.items)) {
|
||||
line += parentSchema.items
|
||||
.map((value) => {
|
||||
const definition = buildSchemaDefinition(value, opts);
|
||||
if (definition.length > 1) {
|
||||
// Format additional information to be in parenthesis
|
||||
const [first, ...rest] = definition;
|
||||
return [first, ' (', rest.join(', '), ')'];
|
||||
} else {
|
||||
return definition.join();
|
||||
}
|
||||
})
|
||||
.join(' | ');
|
||||
} else {
|
||||
line += buildSchemaDefinition(parentSchema.items, opts);
|
||||
}
|
||||
line += '[]';
|
||||
break;
|
||||
default:
|
||||
line += '`' + typeName + '`';
|
||||
}
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds: additionalItems, contains
|
||||
*/
|
||||
function buildExtendedItems(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (schema.additionalItems) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
if (schema.contains) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
if (schema.additionalItems) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
if (schema.contains) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
schema.additionalItems && out.push(`additionalItems: ${JSON.stringify(schema.additionalItems)}`);
|
||||
schema.contains && out.push(`contains: ${JSON.stringify(schema.contains)}`);
|
||||
schema.additionalItems && out.push(`additionalItems: ${JSON.stringify(schema.additionalItems)}`);
|
||||
schema.contains && out.push(`contains: ${JSON.stringify(schema.contains)}`);
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds: required, properties, patternProperties, additionalProperties, dependencies, propertyNames
|
||||
*/
|
||||
function buildProperties(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
if (schema.properties) {
|
||||
out.push(`**Object Properties**:`);
|
||||
if (schema.properties) {
|
||||
out.push(`**Object Properties**:`);
|
||||
|
||||
const properties = Object.entries(schema.properties)
|
||||
.filter(([key]) => key !== '$schema')
|
||||
.sort(([a], [b]) => a.localeCompare(b));
|
||||
const properties = Object.entries(schema.properties)
|
||||
.filter(([key]) => key !== '$schema')
|
||||
.sort(([a], [b]) => a.localeCompare(b));
|
||||
|
||||
out.push(
|
||||
properties
|
||||
.map(
|
||||
([key]) =>
|
||||
`- ${key} ${schema.required && schema.required.includes(key) ? '(required)' : ''}`
|
||||
)
|
||||
.join('\n')
|
||||
);
|
||||
out.push(
|
||||
properties
|
||||
.map(
|
||||
([key]) =>
|
||||
`- ${key} ${schema.required && schema.required.includes(key) ? '(required)' : ''}`
|
||||
)
|
||||
.join('\n')
|
||||
);
|
||||
|
||||
properties.forEach(([key, value]) => {
|
||||
out.push(`${'#'.repeat(Math.min(6, opts.headingLevel + 1))} ${key}`);
|
||||
out.push(...buildSchemaDefinition(value, { ...opts, headingLevel: opts.headingLevel + 1 }));
|
||||
});
|
||||
}
|
||||
properties.forEach(([key, value]) => {
|
||||
out.push(`${'#'.repeat(Math.min(6, opts.headingLevel + 1))} ${key}`);
|
||||
out.push(...buildSchemaDefinition(value, { ...opts, headingLevel: opts.headingLevel + 1 }));
|
||||
});
|
||||
}
|
||||
|
||||
schema.additionalProperties &&
|
||||
out.push(
|
||||
`**Allows additional properties**: ${buildSchemaDefinition(
|
||||
schema.additionalProperties,
|
||||
opts
|
||||
)}`
|
||||
);
|
||||
schema.additionalProperties &&
|
||||
out.push(
|
||||
`**Allows additional properties**: ${buildSchemaDefinition(
|
||||
schema.additionalProperties,
|
||||
opts
|
||||
)}`
|
||||
);
|
||||
|
||||
if (schema.patternProperties || schema.dependencies || schema.propertyNames) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
if (schema.patternProperties || schema.dependencies || schema.propertyNames) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
|
||||
schema.patternProperties &&
|
||||
out.push(`patternProperties: ${JSON.stringify(schema.patternProperties)}`);
|
||||
schema.dependencies && out.push(`dependencies: ${JSON.stringify(schema.dependencies)}`);
|
||||
schema.propertyNames && out.push(`propertyNames: ${JSON.stringify(schema.propertyNames)}`);
|
||||
schema.patternProperties &&
|
||||
out.push(`patternProperties: ${JSON.stringify(schema.patternProperties)}`);
|
||||
schema.dependencies && out.push(`dependencies: ${JSON.stringify(schema.dependencies)}`);
|
||||
schema.propertyNames && out.push(`propertyNames: ${JSON.stringify(schema.propertyNames)}`);
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds: if, then, else
|
||||
*/
|
||||
function buildConditionalSubschemas(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
if (schema.if || schema.then || schema.else) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
if (schema.if || schema.then || schema.else) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
|
||||
schema.if && out.push(`if: ${JSON.stringify(schema.if)}`);
|
||||
schema.then && out.push(`then: ${JSON.stringify(schema.then)}`);
|
||||
schema.else && out.push(`else: ${JSON.stringify(schema.else)}`);
|
||||
schema.if && out.push(`if: ${JSON.stringify(schema.if)}`);
|
||||
schema.then && out.push(`then: ${JSON.stringify(schema.then)}`);
|
||||
schema.else && out.push(`else: ${JSON.stringify(schema.else)}`);
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds: allOf, anyOf, oneOf, not
|
||||
*/
|
||||
function buildBooleanSubschemas(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
if (schema.allOf) {
|
||||
out.push(...buildXOf('All', schema.allOf, opts));
|
||||
}
|
||||
if (schema.allOf) {
|
||||
out.push(...buildXOf('All', schema.allOf, opts));
|
||||
}
|
||||
|
||||
if (schema.anyOf) {
|
||||
out.push(...buildXOf('Any', schema.anyOf, opts));
|
||||
}
|
||||
if (schema.anyOf) {
|
||||
out.push(...buildXOf('Any', schema.anyOf, opts));
|
||||
}
|
||||
|
||||
if (schema.oneOf) {
|
||||
out.push(...buildXOf('One', schema.oneOf, opts));
|
||||
}
|
||||
if (schema.oneOf) {
|
||||
out.push(...buildXOf('One', schema.oneOf, opts));
|
||||
}
|
||||
|
||||
if (schema.not) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
if (schema.not) {
|
||||
throw Error('Not implemented');
|
||||
}
|
||||
|
||||
schema.not && out.push(`not: ${JSON.stringify(schema.not)}`);
|
||||
schema.not && out.push(`not: ${JSON.stringify(schema.not)}`);
|
||||
|
||||
return out;
|
||||
return out;
|
||||
|
||||
function buildXOf(
|
||||
label: 'One' | 'Any' | 'All',
|
||||
schemas: JSONSchema7Definition[],
|
||||
opts: Options
|
||||
): string[] {
|
||||
const definitions = schemas.map((value) =>
|
||||
buildSchemaDefinition(value, { ...opts, leadWithType: true })
|
||||
);
|
||||
function buildXOf(
|
||||
label: 'One' | 'Any' | 'All',
|
||||
schemas: JSONSchema7Definition[],
|
||||
opts: Options
|
||||
): string[] {
|
||||
const definitions = schemas.map((value) =>
|
||||
buildSchemaDefinition(value, { ...opts, leadWithType: true })
|
||||
);
|
||||
|
||||
if (definitions.every((definition) => definition.length == 1)) {
|
||||
// Short definition, can be rendered on a single line
|
||||
return [definitions.join(' | ')];
|
||||
}
|
||||
if (definitions.every((definition) => definition.length == 1)) {
|
||||
// Short definition, can be rendered on a single line
|
||||
return [definitions.join(' | ')];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
if (definitions.length > 1) {
|
||||
// Render as a list
|
||||
out.push(`**${label} of the following**:`);
|
||||
const list: string[] = [];
|
||||
if (definitions.length > 1) {
|
||||
// Render as a list
|
||||
out.push(`**${label} of the following**:`);
|
||||
const list: string[] = [];
|
||||
|
||||
const additionalDefinitions: string[][] = [];
|
||||
const additionalDefinitions: string[][] = [];
|
||||
|
||||
definitions.forEach((definition) => {
|
||||
if (definition[0].startsWith('`object`')) {
|
||||
// Is an object, need to render subdefinitions
|
||||
const [first] = definition;
|
||||
list.push(`- ${first}: Subdefinition ${additionalDefinitions.length + 1}`);
|
||||
additionalDefinitions.push(definition);
|
||||
} else {
|
||||
// Render inline in list
|
||||
list.push(`- ${definition.map((value) => value.replaceAll('\n', ' ')).join(' ')}`);
|
||||
}
|
||||
});
|
||||
definitions.forEach((definition) => {
|
||||
if (definition[0].startsWith('`object`')) {
|
||||
// Is an object, need to render subdefinitions
|
||||
const [first] = definition;
|
||||
list.push(`- ${first}: Subdefinition ${additionalDefinitions.length + 1}`);
|
||||
additionalDefinitions.push(definition);
|
||||
} else {
|
||||
// Render inline in list
|
||||
list.push(`- ${definition.map((value) => value.replaceAll('\n', ' ')).join(' ')}`);
|
||||
}
|
||||
});
|
||||
|
||||
out.push(list.join('\n'));
|
||||
out.push(list.join('\n'));
|
||||
|
||||
if (additionalDefinitions.length > 0) {
|
||||
out.push(`${'#'.repeat(Math.min(6, opts.headingLevel))} Subdefinitions`);
|
||||
additionalDefinitions.forEach((definition, index) => {
|
||||
// Render heading
|
||||
out.push(`${'#'.repeat(Math.min(6, opts.headingLevel + 1))} Subdefinition ${index + 1}`);
|
||||
if (additionalDefinitions.length > 0) {
|
||||
out.push(`${'#'.repeat(Math.min(6, opts.headingLevel))} Subdefinitions`);
|
||||
additionalDefinitions.forEach((definition, index) => {
|
||||
// Render heading
|
||||
out.push(`${'#'.repeat(Math.min(6, opts.headingLevel + 1))} Subdefinition ${index + 1}`);
|
||||
|
||||
// Render definition, giving additional heading indention as needed
|
||||
definition.forEach((line) => {
|
||||
out.push(
|
||||
line.replaceAll(/#{1,6}\s(?=.+)/g, '#'.repeat(Math.min(opts.headingLevel + 2, 6)))
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Render as a block
|
||||
// Mapping might need some fixing...
|
||||
out.push(...definitions.map((definition) => definition.join()));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
// Render definition, giving additional heading indention as needed
|
||||
definition.forEach((line) => {
|
||||
out.push(
|
||||
line.replaceAll(/#{1,6}\s(?=.+)/g, '#'.repeat(Math.min(opts.headingLevel + 2, 6)))
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Render as a block
|
||||
// Mapping might need some fixing...
|
||||
out.push(...definitions.map((definition) => definition.join()));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,34 +438,34 @@ function buildBooleanSubschemas(schema: JSONSchema7Definition, opts: Options): s
|
||||
* https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-9
|
||||
*/
|
||||
function buildExtendedMetadata(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
if (schema.default) {
|
||||
if (typeof schema.default === 'string') {
|
||||
out.push(`**Default**: \`"${schema.default}"\``);
|
||||
} else if (typeof schema.default !== 'object') {
|
||||
// Render on single line
|
||||
out.push(`**Default**: \`${schema.default}\``);
|
||||
} else if (Object.keys(schema.default).length == 0) {
|
||||
// Empty object, render on a single line
|
||||
out.push(`**Default**: \`${JSON.stringify(schema.default)}\``);
|
||||
} else {
|
||||
// Object with properties, render in code block
|
||||
out.push(
|
||||
`\n\`\`\`json title='Default'\n${JSON.stringify(schema.default, null, '\t')}\n\`\`\`\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (schema.default) {
|
||||
if (typeof schema.default === 'string') {
|
||||
out.push(`**Default**: \`"${schema.default}"\``);
|
||||
} else if (typeof schema.default !== 'object') {
|
||||
// Render on single line
|
||||
out.push(`**Default**: \`${schema.default}\``);
|
||||
} else if (Object.keys(schema.default).length == 0) {
|
||||
// Empty object, render on a single line
|
||||
out.push(`**Default**: \`${JSON.stringify(schema.default)}\``);
|
||||
} else {
|
||||
// Object with properties, render in code block
|
||||
out.push(
|
||||
`\n\`\`\`json title='Default'\n${JSON.stringify(schema.default, null, '\t')}\n\`\`\`\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (schema.examples) {
|
||||
throw Error('Examples not implemented');
|
||||
}
|
||||
if (schema.examples) {
|
||||
throw Error('Examples not implemented');
|
||||
}
|
||||
|
||||
return out;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,28 +475,28 @@ function buildExtendedMetadata(schema: JSONSchema7Definition, opts: Options): st
|
||||
* https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-9
|
||||
*/
|
||||
function buildDefinitions(schema: JSONSchema7Definition, opts: Options): string[] {
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
if (typeof schema !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const out: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
// Combine definitions together
|
||||
// `definitions` was renamed to `$defs` in Draft 7 but still allowed in either place
|
||||
const definitions = { ...schema.$defs, ...schema.definitions };
|
||||
if (Object.keys(definitions).length > 0) {
|
||||
out.push(`${'#'.repeat(Math.min(opts.headingLevel, 6))} Definitions`);
|
||||
Object.entries(definitions)
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.forEach(([key, value]) => {
|
||||
out.push(`${'#'.repeat(Math.min(opts.headingLevel, 6) + 1)} ${key}`);
|
||||
out.push(
|
||||
...buildSchemaDefinition(value, {
|
||||
...opts,
|
||||
headingLevel: Math.min(opts.headingLevel, 6) + 2,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
return out;
|
||||
// Combine definitions together
|
||||
// `definitions` was renamed to `$defs` in Draft 7 but still allowed in either place
|
||||
const definitions = { ...schema.$defs, ...schema.definitions };
|
||||
if (Object.keys(definitions).length > 0) {
|
||||
out.push(`${'#'.repeat(Math.min(opts.headingLevel, 6))} Definitions`);
|
||||
Object.entries(definitions)
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.forEach(([key, value]) => {
|
||||
out.push(`${'#'.repeat(Math.min(opts.headingLevel, 6) + 1)} ${key}`);
|
||||
out.push(
|
||||
...buildSchemaDefinition(value, {
|
||||
...opts,
|
||||
headingLevel: Math.min(opts.headingLevel, 6) + 2,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@ import { TranslationStatusBuilder } from './lib/translation-status/builder';
|
||||
import locales from '../../locales.json';
|
||||
|
||||
const translationStatusBuilder = new TranslationStatusBuilder({
|
||||
pageSourceDir: '../../src/content/docs',
|
||||
htmlOutputFilePath: '../../dist/contribute/translate-status.html',
|
||||
sourceLanguage: 'en',
|
||||
targetLanguages: Object.values(locales)
|
||||
.reduce((acc, { lang }) => (lang !== 'en' ? [lang, ...acc] : acc), [])
|
||||
.sort(),
|
||||
languageLabels: Object.values(locales)
|
||||
.filter((loc) => loc.lang !== 'en')
|
||||
.reduce((acc, curr) => ({ [curr.lang]: curr.label, ...acc }), {}),
|
||||
githubRepo: process.env.GITHUB_REPOSITORY || 'tauri-apps/tauri-docs',
|
||||
gitHubRef: 'v2',
|
||||
githubToken: process.env.GITHUB_TOKEN,
|
||||
pageSourceDir: '../../src/content/docs',
|
||||
htmlOutputFilePath: '../../dist/contribute/translate-status.html',
|
||||
sourceLanguage: 'en',
|
||||
targetLanguages: Object.values(locales)
|
||||
.reduce((acc, { lang }) => (lang !== 'en' ? [lang, ...acc] : acc), [])
|
||||
.sort(),
|
||||
languageLabels: Object.values(locales)
|
||||
.filter((loc) => loc.lang !== 'en')
|
||||
.reduce((acc, curr) => ({ [curr.lang]: curr.label, ...acc }), {}),
|
||||
githubRepo: process.env.GITHUB_REPOSITORY || 'tauri-apps/tauri-docs',
|
||||
gitHubRef: 'v2',
|
||||
githubToken: process.env.GITHUB_TOKEN,
|
||||
});
|
||||
|
||||
await translationStatusBuilder.run();
|
||||
|
||||
@@ -7,27 +7,27 @@ import pRetry, { AbortError } from 'p-retry';
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export async function githubGet({ url, githubToken = undefined }) {
|
||||
return await pRetry(
|
||||
async () => {
|
||||
const headers = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
};
|
||||
if (githubToken) {
|
||||
headers.Authorization = `token ${githubToken}`;
|
||||
}
|
||||
const response = await fetch(url, { headers });
|
||||
const json = await response.json();
|
||||
return await pRetry(
|
||||
async () => {
|
||||
const headers = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
};
|
||||
if (githubToken) {
|
||||
headers.Authorization = `token ${githubToken}`;
|
||||
}
|
||||
const response = await fetch(url, { headers });
|
||||
const json = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new AbortError(
|
||||
`GitHub API call failed: GET "${url}" returned status ${
|
||||
response.status
|
||||
}: ${JSON.stringify(json)}`
|
||||
);
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new AbortError(
|
||||
`GitHub API call failed: GET "${url}" returned status ${
|
||||
response.status
|
||||
}: ${JSON.stringify(json)}`
|
||||
);
|
||||
}
|
||||
|
||||
return json;
|
||||
},
|
||||
{ retries: 5 }
|
||||
);
|
||||
return json;
|
||||
},
|
||||
{ retries: 5 }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const isCi = process.env.CI;
|
||||
* @param {...any} params
|
||||
*/
|
||||
export function debug(message, ...params) {
|
||||
console.log(message, ...params);
|
||||
console.log(message, ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,7 +16,7 @@ export function debug(message, ...params) {
|
||||
* @param {...any} params
|
||||
*/
|
||||
export function warning(message, ...params) {
|
||||
console.warn(kleur.yellow().bold(`*** WARNING: ${message}`), ...params);
|
||||
console.warn(kleur.yellow().bold(`*** WARNING: ${message}`), ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ export function warning(message, ...params) {
|
||||
* @param {...any} params
|
||||
*/
|
||||
export function error(message, ...params) {
|
||||
console.error(kleur.red().bold(`*** ERROR: ${message}`), ...params);
|
||||
console.error(kleur.red().bold(`*** ERROR: ${message}`), ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ export function error(message, ...params) {
|
||||
* while leaving new paragraphs intact.
|
||||
*/
|
||||
export function dedentMd(...markdown) {
|
||||
return dedent(...markdown).replace(/(\S)\n(?!\n)/g, '$1 ');
|
||||
return dedent(...markdown).replace(/(\S)\n(?!\n)/g, '$1 ');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,27 +52,27 @@ export function dedentMd(...markdown) {
|
||||
* @param {string} template
|
||||
*/
|
||||
export function formatCount(count, template) {
|
||||
/** @param {string} text */
|
||||
const wrapWithCount = (text) => {
|
||||
// If no count was given, we're outputting a single issue in annotations,
|
||||
// so omit count and capitalize the first letter of the issue type description
|
||||
if (count === undefined) return text[0].toUpperCase() + text.slice(1);
|
||||
/** @param {string} text */
|
||||
const wrapWithCount = (text) => {
|
||||
// If no count was given, we're outputting a single issue in annotations,
|
||||
// so omit count and capitalize the first letter of the issue type description
|
||||
if (count === undefined) return text[0].toUpperCase() + text.slice(1);
|
||||
|
||||
// Otherwise, prefix the issue type description with count
|
||||
return `${count} ${text}`;
|
||||
};
|
||||
// Otherwise, prefix the issue type description with count
|
||||
return `${count} ${text}`;
|
||||
};
|
||||
|
||||
const usePlural = count !== undefined && count !== 1;
|
||||
const templateParts = template.split('|');
|
||||
const usedTemplate = templateParts.length === 2 ? templateParts[usePlural ? 1 : 0] : template;
|
||||
return wrapWithCount(usedTemplate.replace(/\(s\)/g, usePlural ? 's' : ''));
|
||||
const usePlural = count !== undefined && count !== 1;
|
||||
const templateParts = template.split('|');
|
||||
const usedTemplate = templateParts.length === 2 ? templateParts[usePlural ? 1 : 0] : template;
|
||||
return wrapWithCount(usedTemplate.replace(/\(s\)/g, usePlural ? 's' : ''));
|
||||
}
|
||||
|
||||
export default {
|
||||
debug,
|
||||
warning,
|
||||
error,
|
||||
dedentMd,
|
||||
formatCount,
|
||||
isCi,
|
||||
debug,
|
||||
warning,
|
||||
error,
|
||||
dedentMd,
|
||||
formatCount,
|
||||
isCi,
|
||||
};
|
||||
|
||||
@@ -13,11 +13,11 @@ import type { PageData, PageIndex, PageTranslationStatus } from './types';
|
||||
export const COMMIT_IGNORE = /(en-only|typo|broken link|i18nReady|i18nIgnore)/i;
|
||||
|
||||
interface PullRequest {
|
||||
html_url: string;
|
||||
title: string;
|
||||
labels: {
|
||||
name: string;
|
||||
}[];
|
||||
html_url: string;
|
||||
title: string;
|
||||
labels: {
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,458 +27,458 @@ interface PullRequest {
|
||||
* This code is designed to be run on every push to the `main` branch.
|
||||
*/
|
||||
export class TranslationStatusBuilder {
|
||||
constructor(config: {
|
||||
pageSourceDir: string;
|
||||
/**
|
||||
* Full path & file name of the HTML file that the translation status should be written to.
|
||||
* If the parent path does not exist yet, it will be created.
|
||||
* */
|
||||
htmlOutputFilePath: string;
|
||||
sourceLanguage: string;
|
||||
targetLanguages: string[];
|
||||
languageLabels: { [key: string]: string };
|
||||
githubRepo: string;
|
||||
gitHubRef: string;
|
||||
githubToken?: string | undefined;
|
||||
}) {
|
||||
this.pageSourceDir = config.pageSourceDir;
|
||||
this.htmlOutputFilePath = path.resolve(config.htmlOutputFilePath);
|
||||
this.sourceLanguage = config.sourceLanguage;
|
||||
this.targetLanguages = config.targetLanguages;
|
||||
this.languageLabels = config.languageLabels;
|
||||
this.githubRepo = config.githubRepo;
|
||||
this.githubRef = config.gitHubRef;
|
||||
this.githubToken = config.githubToken ?? '';
|
||||
this.git = simpleGit({
|
||||
maxConcurrentProcesses: Math.max(2, Math.min(32, os.cpus().length)),
|
||||
});
|
||||
}
|
||||
constructor(config: {
|
||||
pageSourceDir: string;
|
||||
/**
|
||||
* Full path & file name of the HTML file that the translation status should be written to.
|
||||
* If the parent path does not exist yet, it will be created.
|
||||
* */
|
||||
htmlOutputFilePath: string;
|
||||
sourceLanguage: string;
|
||||
targetLanguages: string[];
|
||||
languageLabels: { [key: string]: string };
|
||||
githubRepo: string;
|
||||
gitHubRef: string;
|
||||
githubToken?: string | undefined;
|
||||
}) {
|
||||
this.pageSourceDir = config.pageSourceDir;
|
||||
this.htmlOutputFilePath = path.resolve(config.htmlOutputFilePath);
|
||||
this.sourceLanguage = config.sourceLanguage;
|
||||
this.targetLanguages = config.targetLanguages;
|
||||
this.languageLabels = config.languageLabels;
|
||||
this.githubRepo = config.githubRepo;
|
||||
this.githubRef = config.gitHubRef;
|
||||
this.githubToken = config.githubToken ?? '';
|
||||
this.git = simpleGit({
|
||||
maxConcurrentProcesses: Math.max(2, Math.min(32, os.cpus().length)),
|
||||
});
|
||||
}
|
||||
|
||||
readonly pageSourceDir;
|
||||
readonly htmlOutputFilePath;
|
||||
readonly sourceLanguage;
|
||||
readonly targetLanguages;
|
||||
readonly languageLabels;
|
||||
readonly githubRepo;
|
||||
readonly githubRef;
|
||||
readonly githubToken;
|
||||
readonly git;
|
||||
readonly pageSourceDir;
|
||||
readonly htmlOutputFilePath;
|
||||
readonly sourceLanguage;
|
||||
readonly targetLanguages;
|
||||
readonly languageLabels;
|
||||
readonly githubRepo;
|
||||
readonly githubRef;
|
||||
readonly githubToken;
|
||||
readonly git;
|
||||
|
||||
async run() {
|
||||
// Before we start, validate that this is not a shallow clone of the repo
|
||||
const isShallowRepo = await this.git.revparse(['--is-shallow-repository']);
|
||||
if (isShallowRepo !== 'false') {
|
||||
output.error(dedent`This script cannot operate on a shallow clone of the git repository.
|
||||
async run() {
|
||||
// Before we start, validate that this is not a shallow clone of the repo
|
||||
const isShallowRepo = await this.git.revparse(['--is-shallow-repository']);
|
||||
if (isShallowRepo !== 'false') {
|
||||
output.error(dedent`This script cannot operate on a shallow clone of the git repository.
|
||||
Please add the checkout setting "fetch-depth: 0" to your GitHub workflow:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
`);
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
output.debug(`*** Building translation status`);
|
||||
output.debug(`*** Building translation status`);
|
||||
|
||||
// Ensure that the output directory exists before continuing
|
||||
output.debug(`- Output file path: ${this.htmlOutputFilePath}`);
|
||||
const outputDir = path.dirname(this.htmlOutputFilePath);
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
}
|
||||
// Ensure that the output directory exists before continuing
|
||||
output.debug(`- Output file path: ${this.htmlOutputFilePath}`);
|
||||
const outputDir = path.dirname(this.htmlOutputFilePath);
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Create an index of all Markdown/MDX pages grouped by language,
|
||||
// with information about the last minor & major commit per page
|
||||
output.debug(`- Generating page index...`);
|
||||
const pages = await this.createPageIndex();
|
||||
// Create an index of all Markdown/MDX pages grouped by language,
|
||||
// with information about the last minor & major commit per page
|
||||
output.debug(`- Generating page index...`);
|
||||
const pages = await this.createPageIndex();
|
||||
|
||||
// Determine translation status by source page
|
||||
const statusByPage = this.getTranslationStatusByPage(pages);
|
||||
// Determine translation status by source page
|
||||
const statusByPage = this.getTranslationStatusByPage(pages);
|
||||
|
||||
// Fetch all pull requests
|
||||
const pullRequests = await this.getPullRequests();
|
||||
// Fetch all pull requests
|
||||
const pullRequests = await this.getPullRequests();
|
||||
|
||||
// Render a human-friendly summary
|
||||
output.debug(`- Building HTML file...`);
|
||||
const html = this.renderHtmlStatusPage(statusByPage, pullRequests);
|
||||
// Render a human-friendly summary
|
||||
output.debug(`- Building HTML file...`);
|
||||
const html = this.renderHtmlStatusPage(statusByPage, pullRequests);
|
||||
|
||||
// Write HTML output to file
|
||||
fs.writeFileSync(this.htmlOutputFilePath, html);
|
||||
// Write HTML output to file
|
||||
fs.writeFileSync(this.htmlOutputFilePath, html);
|
||||
|
||||
output.debug('');
|
||||
output.debug('*** Success!');
|
||||
output.debug('');
|
||||
}
|
||||
output.debug('');
|
||||
output.debug('*** Success!');
|
||||
output.debug('');
|
||||
}
|
||||
|
||||
/** Get all pull requests with the `i18n` tag */
|
||||
async getPullRequests() {
|
||||
const pullRequests: PullRequest[] = await githubGet({
|
||||
url: `https://api.github.com/repos/${this.githubRepo}/pulls?state=open&per_page=100`,
|
||||
githubToken: this.githubToken,
|
||||
});
|
||||
/** Get all pull requests with the `i18n` tag */
|
||||
async getPullRequests() {
|
||||
const pullRequests: PullRequest[] = await githubGet({
|
||||
url: `https://api.github.com/repos/${this.githubRepo}/pulls?state=open&per_page=100`,
|
||||
githubToken: this.githubToken,
|
||||
});
|
||||
|
||||
return pullRequests.filter((pr) => pr.labels.find((label) => label.name === 'i18n'));
|
||||
}
|
||||
return pullRequests.filter((pr) => pr.labels.find((label) => label.name === 'i18n'));
|
||||
}
|
||||
|
||||
async createPageIndex(): Promise<PageIndex> {
|
||||
// Initialize a new page index with a stable key order
|
||||
const pages: PageIndex = {
|
||||
[this.sourceLanguage]: {},
|
||||
};
|
||||
this.targetLanguages.forEach((lang) => (pages[lang.toLowerCase()] = {}));
|
||||
async createPageIndex(): Promise<PageIndex> {
|
||||
// Initialize a new page index with a stable key order
|
||||
const pages: PageIndex = {
|
||||
[this.sourceLanguage]: {},
|
||||
};
|
||||
this.targetLanguages.forEach((lang) => (pages[lang.toLowerCase()] = {}));
|
||||
|
||||
// Enumerate all markdown pages with supported languages in pageSourceDir,
|
||||
// retrieve their page data and update them
|
||||
const pagePaths = await glob(`**/*.{md,mdx}`, {
|
||||
cwd: this.pageSourceDir,
|
||||
});
|
||||
const updatedPages = await Promise.all(
|
||||
pagePaths.sort().map(async (pagePath) => {
|
||||
const pathParts = pagePath.split('/');
|
||||
const isLanguageSubpathIncluded = this.targetLanguages
|
||||
.map((el) => el.toLowerCase())
|
||||
.includes(pathParts[0]!);
|
||||
// Enumerate all markdown pages with supported languages in pageSourceDir,
|
||||
// retrieve their page data and update them
|
||||
const pagePaths = await glob(`**/*.{md,mdx}`, {
|
||||
cwd: this.pageSourceDir,
|
||||
});
|
||||
const updatedPages = await Promise.all(
|
||||
pagePaths.sort().map(async (pagePath) => {
|
||||
const pathParts = pagePath.split('/');
|
||||
const isLanguageSubpathIncluded = this.targetLanguages
|
||||
.map((el) => el.toLowerCase())
|
||||
.includes(pathParts[0]!);
|
||||
|
||||
// If the first path of a file does not belong to a language, it will be by default a page of the original language set.
|
||||
const lang = isLanguageSubpathIncluded ? pathParts[0] : this.sourceLanguage;
|
||||
const subpath = pathParts.splice(1).join('/');
|
||||
// If the first path of a file does not belong to a language, it will be by default a page of the original language set.
|
||||
const lang = isLanguageSubpathIncluded ? pathParts[0] : this.sourceLanguage;
|
||||
const subpath = pathParts.splice(1).join('/');
|
||||
|
||||
// Create or update page data for the page
|
||||
return {
|
||||
lang,
|
||||
subpath: isLanguageSubpathIncluded ? subpath : pagePath,
|
||||
pageData: await this.getSinglePageData(pagePath),
|
||||
};
|
||||
})
|
||||
);
|
||||
// Create or update page data for the page
|
||||
return {
|
||||
lang,
|
||||
subpath: isLanguageSubpathIncluded ? subpath : pagePath,
|
||||
pageData: await this.getSinglePageData(pagePath),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
// Write the updated pages to the index
|
||||
updatedPages.forEach((page) => {
|
||||
if (!page) return;
|
||||
const { lang, subpath, pageData } = page;
|
||||
if (!pageData) return;
|
||||
pages[lang!]![subpath] = pageData;
|
||||
});
|
||||
// Write the updated pages to the index
|
||||
updatedPages.forEach((page) => {
|
||||
if (!page) return;
|
||||
const { lang, subpath, pageData } = page;
|
||||
if (!pageData) return;
|
||||
pages[lang!]![subpath] = pageData;
|
||||
});
|
||||
|
||||
return pages;
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the markdown page located in the pageSourceDir subpath `pagePath`
|
||||
* and creates a new page data object based on its frontmatter and git history.
|
||||
*/
|
||||
async getSinglePageData(pagePath: string): Promise<PageData | undefined> {
|
||||
const fullFilePath = `${this.pageSourceDir}/${pagePath}`;
|
||||
/**
|
||||
* Processes the markdown page located in the pageSourceDir subpath `pagePath`
|
||||
* and creates a new page data object based on its frontmatter and git history.
|
||||
*/
|
||||
async getSinglePageData(pagePath: string): Promise<PageData | undefined> {
|
||||
const fullFilePath = `${this.pageSourceDir}/${pagePath}`;
|
||||
|
||||
// Retrieve git history for the current page
|
||||
const gitHistory = await this.getGitHistory(fullFilePath);
|
||||
// Retrieve git history for the current page
|
||||
const gitHistory = await this.getGitHistory(fullFilePath);
|
||||
|
||||
if (!gitHistory) return;
|
||||
if (!gitHistory) return;
|
||||
|
||||
// Retrieve i18nReady flag from frontmatter
|
||||
const frontMatterBlock = tryGetFrontMatterBlock(fullFilePath);
|
||||
const i18nReady = /^\s*i18nReady:\s*true\s*$/m.test(frontMatterBlock);
|
||||
// Retrieve i18nReady flag from frontmatter
|
||||
const frontMatterBlock = tryGetFrontMatterBlock(fullFilePath);
|
||||
const i18nReady = /^\s*i18nReady:\s*true\s*$/m.test(frontMatterBlock);
|
||||
|
||||
return {
|
||||
...(i18nReady ? { i18nReady: true } : {}),
|
||||
lastChange: gitHistory.lastCommitDate,
|
||||
lastCommitMsg: gitHistory.lastCommitMessage,
|
||||
lastMajorChange: gitHistory.lastMajorCommitDate,
|
||||
lastMajorCommitMsg: gitHistory.lastMajorCommitMessage,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...(i18nReady ? { i18nReady: true } : {}),
|
||||
lastChange: gitHistory.lastCommitDate,
|
||||
lastCommitMsg: gitHistory.lastCommitMessage,
|
||||
lastMajorChange: gitHistory.lastMajorCommitDate,
|
||||
lastMajorCommitMsg: gitHistory.lastMajorCommitMessage,
|
||||
};
|
||||
}
|
||||
|
||||
async getGitHistory(filePath: string) {
|
||||
const gitLog = await this.git.log({
|
||||
file: filePath,
|
||||
strictDate: true,
|
||||
});
|
||||
async getGitHistory(filePath: string) {
|
||||
const gitLog = await this.git.log({
|
||||
file: filePath,
|
||||
strictDate: true,
|
||||
});
|
||||
|
||||
const lastCommit = gitLog.latest;
|
||||
if (!lastCommit) {
|
||||
return;
|
||||
// Disabled since we have generated reference files
|
||||
// throw new Error(dedent`Failed to retrieve last commit information for file
|
||||
// "${filePath}". Your working copy should not contain uncommitted new pages
|
||||
// when running this script.`);
|
||||
}
|
||||
const lastCommit = gitLog.latest;
|
||||
if (!lastCommit) {
|
||||
return;
|
||||
// Disabled since we have generated reference files
|
||||
// throw new Error(dedent`Failed to retrieve last commit information for file
|
||||
// "${filePath}". Your working copy should not contain uncommitted new pages
|
||||
// when running this script.`);
|
||||
}
|
||||
|
||||
// Attempt to find the last "major" commit, ignoring any commits that
|
||||
// usually do not require translations to be updated
|
||||
const lastMajorCommit =
|
||||
gitLog.all.find((logEntry) => {
|
||||
return !logEntry.message.match(COMMIT_IGNORE);
|
||||
}) || lastCommit;
|
||||
// Attempt to find the last "major" commit, ignoring any commits that
|
||||
// usually do not require translations to be updated
|
||||
const lastMajorCommit =
|
||||
gitLog.all.find((logEntry) => {
|
||||
return !logEntry.message.match(COMMIT_IGNORE);
|
||||
}) || lastCommit;
|
||||
|
||||
return {
|
||||
lastCommitMessage: lastCommit.message,
|
||||
lastCommitDate: toUtcString(lastCommit.date),
|
||||
lastMajorCommitMessage: lastMajorCommit.message,
|
||||
lastMajorCommitDate: toUtcString(lastMajorCommit.date),
|
||||
};
|
||||
}
|
||||
return {
|
||||
lastCommitMessage: lastCommit.message,
|
||||
lastCommitDate: toUtcString(lastCommit.date),
|
||||
lastMajorCommitMessage: lastMajorCommit.message,
|
||||
lastMajorCommitDate: toUtcString(lastMajorCommit.date),
|
||||
};
|
||||
}
|
||||
|
||||
getTranslationStatusByPage(pages: PageIndex): PageTranslationStatus[] {
|
||||
const sourcePages = pages[this.sourceLanguage];
|
||||
const arrContent: PageTranslationStatus[] = [];
|
||||
getTranslationStatusByPage(pages: PageIndex): PageTranslationStatus[] {
|
||||
const sourcePages = pages[this.sourceLanguage];
|
||||
const arrContent: PageTranslationStatus[] = [];
|
||||
|
||||
Object.keys(sourcePages!).forEach((subpath) => {
|
||||
const sourcePage = sourcePages![subpath]!;
|
||||
if (!sourcePage.i18nReady) return;
|
||||
Object.keys(sourcePages!).forEach((subpath) => {
|
||||
const sourcePage = sourcePages![subpath]!;
|
||||
if (!sourcePage.i18nReady) return;
|
||||
|
||||
const content: PageTranslationStatus = {
|
||||
subpath,
|
||||
sourcePage,
|
||||
githubUrl: this.getPageUrl({ lang: this.sourceLanguage, subpath }),
|
||||
translations: {},
|
||||
};
|
||||
const content: PageTranslationStatus = {
|
||||
subpath,
|
||||
sourcePage,
|
||||
githubUrl: this.getPageUrl({ lang: this.sourceLanguage, subpath }),
|
||||
translations: {},
|
||||
};
|
||||
|
||||
this.targetLanguages.forEach((lang) => {
|
||||
const i18nPage = pages[lang.toLowerCase()]![subpath]!;
|
||||
content.translations[lang] = {
|
||||
page: i18nPage,
|
||||
isMissing: !i18nPage,
|
||||
isOutdated: i18nPage && sourcePage.lastMajorChange > i18nPage.lastMajorChange,
|
||||
githubUrl: this.getPageUrl({ lang, subpath }),
|
||||
sourceHistoryUrl: this.getPageUrl({
|
||||
lang: 'en',
|
||||
subpath,
|
||||
type: 'commits',
|
||||
query: i18nPage ? `?since=${i18nPage.lastMajorChange}` : '',
|
||||
}),
|
||||
};
|
||||
});
|
||||
this.targetLanguages.forEach((lang) => {
|
||||
const i18nPage = pages[lang.toLowerCase()]![subpath]!;
|
||||
content.translations[lang] = {
|
||||
page: i18nPage,
|
||||
isMissing: !i18nPage,
|
||||
isOutdated: i18nPage && sourcePage.lastMajorChange > i18nPage.lastMajorChange,
|
||||
githubUrl: this.getPageUrl({ lang, subpath }),
|
||||
sourceHistoryUrl: this.getPageUrl({
|
||||
lang: 'en',
|
||||
subpath,
|
||||
type: 'commits',
|
||||
query: i18nPage ? `?since=${i18nPage.lastMajorChange}` : '',
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
arrContent.push(content);
|
||||
});
|
||||
arrContent.push(content);
|
||||
});
|
||||
|
||||
return arrContent;
|
||||
}
|
||||
return arrContent;
|
||||
}
|
||||
|
||||
getPageUrl({
|
||||
type = 'blob',
|
||||
lang,
|
||||
subpath,
|
||||
query = '',
|
||||
}: {
|
||||
type?: string;
|
||||
refName?: string;
|
||||
lang: string;
|
||||
subpath: string;
|
||||
query?: string;
|
||||
}) {
|
||||
const noDotSrcDir = this.pageSourceDir.replaceAll(/\.+\//g, '');
|
||||
const isSrcLang = lang === this.sourceLanguage;
|
||||
return `https://github.com/${this.githubRepo}/${type}/${this.githubRef}/${noDotSrcDir}${
|
||||
isSrcLang ? '' : `/${lang}`
|
||||
}/${subpath}${query}`;
|
||||
}
|
||||
getPageUrl({
|
||||
type = 'blob',
|
||||
lang,
|
||||
subpath,
|
||||
query = '',
|
||||
}: {
|
||||
type?: string;
|
||||
refName?: string;
|
||||
lang: string;
|
||||
subpath: string;
|
||||
query?: string;
|
||||
}) {
|
||||
const noDotSrcDir = this.pageSourceDir.replaceAll(/\.+\//g, '');
|
||||
const isSrcLang = lang === this.sourceLanguage;
|
||||
return `https://github.com/${this.githubRepo}/${type}/${this.githubRef}/${noDotSrcDir}${
|
||||
isSrcLang ? '' : `/${lang}`
|
||||
}/${subpath}${query}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the primary HTML output of this script by loading a template from disk,
|
||||
* rendering the individual views to HTML, and inserting them into the template.
|
||||
*/
|
||||
renderHtmlStatusPage(statusByPage: PageTranslationStatus[], prs: PullRequest[]) {
|
||||
// Load HTML template
|
||||
const templateFilePath = path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'template.html'
|
||||
);
|
||||
const html = fs.readFileSync(templateFilePath, { encoding: 'utf8' });
|
||||
/**
|
||||
* Renders the primary HTML output of this script by loading a template from disk,
|
||||
* rendering the individual views to HTML, and inserting them into the template.
|
||||
*/
|
||||
renderHtmlStatusPage(statusByPage: PageTranslationStatus[], prs: PullRequest[]) {
|
||||
// Load HTML template
|
||||
const templateFilePath = path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'template.html'
|
||||
);
|
||||
const html = fs.readFileSync(templateFilePath, { encoding: 'utf8' });
|
||||
|
||||
// Replace placeholders in the template with the rendered views
|
||||
// and return the resulting HTML page
|
||||
return html
|
||||
.replace(
|
||||
'<!-- TranslationStatusByLanguage -->',
|
||||
this.renderTranslationStatusByLanguage(statusByPage)
|
||||
)
|
||||
.replace('<!-- TranslationNeedsReview -->', this.renderTranslationNeedsReview(prs))
|
||||
.replace(
|
||||
'<!-- TranslationStatusByPage -->',
|
||||
this.renderTranslationStatusByPage(statusByPage)
|
||||
);
|
||||
}
|
||||
// Replace placeholders in the template with the rendered views
|
||||
// and return the resulting HTML page
|
||||
return html
|
||||
.replace(
|
||||
'<!-- TranslationStatusByLanguage -->',
|
||||
this.renderTranslationStatusByLanguage(statusByPage)
|
||||
)
|
||||
.replace('<!-- TranslationNeedsReview -->', this.renderTranslationNeedsReview(prs))
|
||||
.replace(
|
||||
'<!-- TranslationStatusByPage -->',
|
||||
this.renderTranslationStatusByPage(statusByPage)
|
||||
);
|
||||
}
|
||||
|
||||
renderTranslationStatusByLanguage(statusByPage: PageTranslationStatus[]) {
|
||||
const lines: string[] = [];
|
||||
renderTranslationStatusByLanguage(statusByPage: PageTranslationStatus[]) {
|
||||
const lines: string[] = [];
|
||||
|
||||
this.targetLanguages.forEach((lang) => {
|
||||
const missing = statusByPage.filter((content) => content.translations[lang]!.isMissing);
|
||||
const outdated = statusByPage.filter((content) => content.translations[lang]!.isOutdated);
|
||||
lines.push('<details>');
|
||||
lines.push(
|
||||
`<summary><strong>` +
|
||||
`${this.languageLabels[lang]} (${lang})` +
|
||||
`</strong><br>` +
|
||||
`<span class="progress-summary">` +
|
||||
`${statusByPage.length - outdated.length - missing.length} done, ` +
|
||||
`${outdated.length} need${outdated.length === 1 ? 's' : ''} updating, ` +
|
||||
`${missing.length} missing` +
|
||||
`</span>` +
|
||||
'<br>' +
|
||||
this.renderProgressBar(statusByPage.length, outdated.length, missing.length) +
|
||||
`</summary>`
|
||||
);
|
||||
lines.push(``);
|
||||
if (outdated.length > 0) {
|
||||
lines.push(`<h5>🔄 Needs updating</h5>`);
|
||||
lines.push(`<ul>`);
|
||||
lines.push(
|
||||
...outdated.map(
|
||||
(content) =>
|
||||
`<li>` +
|
||||
`${this.renderLink(content.githubUrl, content.subpath)} ` +
|
||||
`(${this.renderLink(
|
||||
content.translations[lang]!.githubUrl,
|
||||
'outdated translation'
|
||||
)}, ${this.renderLink(
|
||||
content.translations[lang]!.sourceHistoryUrl,
|
||||
'source change history'
|
||||
)})` +
|
||||
`</li>`
|
||||
)
|
||||
);
|
||||
lines.push(`</ul>`);
|
||||
}
|
||||
if (missing.length > 0) {
|
||||
lines.push(`<h5>❌ Missing</h5>`);
|
||||
lines.push(`<ul>`);
|
||||
lines.push(
|
||||
...missing.map(
|
||||
(content) =>
|
||||
`<li>` +
|
||||
`${this.renderLink(
|
||||
content.githubUrl,
|
||||
content.subpath
|
||||
)} ${this.renderCreatePageButton(lang, content.subpath)}` +
|
||||
`</li>`
|
||||
)
|
||||
);
|
||||
lines.push(`</ul>`);
|
||||
}
|
||||
lines.push(`</details>`);
|
||||
lines.push(``);
|
||||
});
|
||||
this.targetLanguages.forEach((lang) => {
|
||||
const missing = statusByPage.filter((content) => content.translations[lang]!.isMissing);
|
||||
const outdated = statusByPage.filter((content) => content.translations[lang]!.isOutdated);
|
||||
lines.push('<details>');
|
||||
lines.push(
|
||||
`<summary><strong>` +
|
||||
`${this.languageLabels[lang]} (${lang})` +
|
||||
`</strong><br>` +
|
||||
`<span class="progress-summary">` +
|
||||
`${statusByPage.length - outdated.length - missing.length} done, ` +
|
||||
`${outdated.length} need${outdated.length === 1 ? 's' : ''} updating, ` +
|
||||
`${missing.length} missing` +
|
||||
`</span>` +
|
||||
'<br>' +
|
||||
this.renderProgressBar(statusByPage.length, outdated.length, missing.length) +
|
||||
`</summary>`
|
||||
);
|
||||
lines.push(``);
|
||||
if (outdated.length > 0) {
|
||||
lines.push(`<h5>🔄 Needs updating</h5>`);
|
||||
lines.push(`<ul>`);
|
||||
lines.push(
|
||||
...outdated.map(
|
||||
(content) =>
|
||||
`<li>` +
|
||||
`${this.renderLink(content.githubUrl, content.subpath)} ` +
|
||||
`(${this.renderLink(
|
||||
content.translations[lang]!.githubUrl,
|
||||
'outdated translation'
|
||||
)}, ${this.renderLink(
|
||||
content.translations[lang]!.sourceHistoryUrl,
|
||||
'source change history'
|
||||
)})` +
|
||||
`</li>`
|
||||
)
|
||||
);
|
||||
lines.push(`</ul>`);
|
||||
}
|
||||
if (missing.length > 0) {
|
||||
lines.push(`<h5>❌ Missing</h5>`);
|
||||
lines.push(`<ul>`);
|
||||
lines.push(
|
||||
...missing.map(
|
||||
(content) =>
|
||||
`<li>` +
|
||||
`${this.renderLink(
|
||||
content.githubUrl,
|
||||
content.subpath
|
||||
)} ${this.renderCreatePageButton(lang, content.subpath)}` +
|
||||
`</li>`
|
||||
)
|
||||
);
|
||||
lines.push(`</ul>`);
|
||||
}
|
||||
lines.push(`</details>`);
|
||||
lines.push(``);
|
||||
});
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
renderTranslationNeedsReview(prs: PullRequest[]) {
|
||||
const lines: string[] = [];
|
||||
renderTranslationNeedsReview(prs: PullRequest[]) {
|
||||
const lines: string[] = [];
|
||||
|
||||
if (prs.length > 0) {
|
||||
lines.push(`<ul>`);
|
||||
lines.push(
|
||||
...prs.map((pr) => {
|
||||
const title = pr.title.replaceAll('`', '');
|
||||
return `<li>` + this.renderLink(pr.html_url, title) + `</li>`;
|
||||
})
|
||||
);
|
||||
lines.push(`</ul>`);
|
||||
}
|
||||
lines.push(``);
|
||||
if (prs.length > 0) {
|
||||
lines.push(`<ul>`);
|
||||
lines.push(
|
||||
...prs.map((pr) => {
|
||||
const title = pr.title.replaceAll('`', '');
|
||||
return `<li>` + this.renderLink(pr.html_url, title) + `</li>`;
|
||||
})
|
||||
);
|
||||
lines.push(`</ul>`);
|
||||
}
|
||||
lines.push(``);
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
renderTranslationStatusByPage(statusByPage: PageTranslationStatus[]) {
|
||||
const lines: string[] = [];
|
||||
renderTranslationStatusByPage(statusByPage: PageTranslationStatus[]) {
|
||||
const lines: string[] = [];
|
||||
|
||||
lines.push('<div class="table-container"/>');
|
||||
lines.push('<table role="table" class="status-by-page">');
|
||||
lines.push('<div class="table-container"/>');
|
||||
lines.push('<table role="table" class="status-by-page">');
|
||||
|
||||
lines.push('<thead><tr>');
|
||||
lines.push(['Page', ...this.targetLanguages].map((col) => `<th>${col}</th>`).join(''));
|
||||
lines.push('</tr></thead>');
|
||||
lines.push('<thead><tr>');
|
||||
lines.push(['Page', ...this.targetLanguages].map((col) => `<th>${col}</th>`).join(''));
|
||||
lines.push('</tr></thead>');
|
||||
|
||||
lines.push('<tbody>');
|
||||
const spacer = `<tr class="spacer">\n${this.targetLanguages
|
||||
.map(() => `<td></td>`)
|
||||
.join('\n')}\n</tr>`;
|
||||
lines.push(spacer);
|
||||
statusByPage.forEach((content) => {
|
||||
const cols = [];
|
||||
cols.push(this.renderLink(content.githubUrl, content.subpath));
|
||||
cols.push(
|
||||
...this.targetLanguages.map((lang) => {
|
||||
const translation = content.translations[lang]!;
|
||||
if (translation.isMissing)
|
||||
return `<span title="${lang}: Missing"><span aria-hidden="true">❌</span></span>`;
|
||||
if (translation.isOutdated)
|
||||
return `<a href="${translation.githubUrl}" title="${lang}: Needs updating"><span aria-hidden="true">🔄</span></a>`;
|
||||
return `<a href="${translation.githubUrl}" title="${lang}: Completed"><span aria-hidden="true">✔</span></a>`;
|
||||
})
|
||||
);
|
||||
lines.push(`<tr>\n${cols.map((col) => `<td>${col}</td>`).join('\n')}\n</tr>`);
|
||||
});
|
||||
lines.push(spacer);
|
||||
lines.push('</tbody>');
|
||||
lines.push('<tbody>');
|
||||
const spacer = `<tr class="spacer">\n${this.targetLanguages
|
||||
.map(() => `<td></td>`)
|
||||
.join('\n')}\n</tr>`;
|
||||
lines.push(spacer);
|
||||
statusByPage.forEach((content) => {
|
||||
const cols = [];
|
||||
cols.push(this.renderLink(content.githubUrl, content.subpath));
|
||||
cols.push(
|
||||
...this.targetLanguages.map((lang) => {
|
||||
const translation = content.translations[lang]!;
|
||||
if (translation.isMissing)
|
||||
return `<span title="${lang}: Missing"><span aria-hidden="true">❌</span></span>`;
|
||||
if (translation.isOutdated)
|
||||
return `<a href="${translation.githubUrl}" title="${lang}: Needs updating"><span aria-hidden="true">🔄</span></a>`;
|
||||
return `<a href="${translation.githubUrl}" title="${lang}: Completed"><span aria-hidden="true">✔</span></a>`;
|
||||
})
|
||||
);
|
||||
lines.push(`<tr>\n${cols.map((col) => `<td>${col}</td>`).join('\n')}\n</tr>`);
|
||||
});
|
||||
lines.push(spacer);
|
||||
lines.push('</tbody>');
|
||||
|
||||
lines.push('</table>');
|
||||
lines.push('</table>');
|
||||
|
||||
lines.push(`\n<sup>❌ Missing 🔄 Needs updating ✔ Completed</sup>`);
|
||||
lines.push('</div>');
|
||||
lines.push(`\n<sup>❌ Missing 🔄 Needs updating ✔ Completed</sup>`);
|
||||
lines.push('</div>');
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a link to a pre-filled GitHub UI for creating a new file.
|
||||
*
|
||||
* @param lang Language tag to create page for
|
||||
* @param filename Subpath of page to create
|
||||
*/
|
||||
renderCreatePageButton(lang: string, filename: string): string {
|
||||
// We include `lang` twice because GitHub eats the last path segment when setting filename.
|
||||
const createUrl = new URL(
|
||||
`https://github.com/${this.githubRepo}/new/${this.githubRef}/src/content/docs`
|
||||
);
|
||||
createUrl.searchParams.set('filename', lang + '/' + filename);
|
||||
createUrl.searchParams.set('value', '---\ntitle:\ndescription:\n---\n');
|
||||
return this.renderLink(createUrl.href, `Create\xa0page\xa0+`, 'create-button');
|
||||
}
|
||||
/**
|
||||
* Render a link to a pre-filled GitHub UI for creating a new file.
|
||||
*
|
||||
* @param lang Language tag to create page for
|
||||
* @param filename Subpath of page to create
|
||||
*/
|
||||
renderCreatePageButton(lang: string, filename: string): string {
|
||||
// We include `lang` twice because GitHub eats the last path segment when setting filename.
|
||||
const createUrl = new URL(
|
||||
`https://github.com/${this.githubRepo}/new/${this.githubRef}/src/content/docs`
|
||||
);
|
||||
createUrl.searchParams.set('filename', lang + '/' + filename);
|
||||
createUrl.searchParams.set('value', '---\ntitle:\ndescription:\n---\n');
|
||||
return this.renderLink(createUrl.href, `Create\xa0page\xa0+`, 'create-button');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a progress bar with emoji.
|
||||
*/
|
||||
renderProgressBar(
|
||||
total: number,
|
||||
outdated: number,
|
||||
missing: number,
|
||||
{ size = 20 }: { size?: number } = {}
|
||||
) {
|
||||
const outdatedLength = Math.round((outdated / total) * size);
|
||||
const missingLength = Math.round((missing / total) * size);
|
||||
const doneLength = size - outdatedLength - missingLength;
|
||||
return (
|
||||
'<span class="progress-bar" aria-hidden="true">' +
|
||||
[
|
||||
[doneLength, '🟦'],
|
||||
[outdatedLength, '🟧'],
|
||||
[missingLength, '⬜'],
|
||||
]
|
||||
.map(([length, icon]) => Array(length).fill(icon))
|
||||
.flat()
|
||||
.join('') +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Render a progress bar with emoji.
|
||||
*/
|
||||
renderProgressBar(
|
||||
total: number,
|
||||
outdated: number,
|
||||
missing: number,
|
||||
{ size = 20 }: { size?: number } = {}
|
||||
) {
|
||||
const outdatedLength = Math.round((outdated / total) * size);
|
||||
const missingLength = Math.round((missing / total) * size);
|
||||
const doneLength = size - outdatedLength - missingLength;
|
||||
return (
|
||||
'<span class="progress-bar" aria-hidden="true">' +
|
||||
[
|
||||
[doneLength, '🟦'],
|
||||
[outdatedLength, '🟧'],
|
||||
[missingLength, '⬜'],
|
||||
]
|
||||
.map(([length, icon]) => Array(length).fill(icon))
|
||||
.flat()
|
||||
.join('') +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
|
||||
renderLink(href: string, text: string, className = ''): string {
|
||||
return `<a href="${escape(href)}" class="${escape(
|
||||
className
|
||||
)}" target="_blank" rel="noopener noreferrer">${escape(text)}</a>`;
|
||||
}
|
||||
renderLink(href: string, text: string, className = ''): string {
|
||||
return `<a href="${escape(href)}" class="${escape(
|
||||
className
|
||||
)}" target="_blank" rel="noopener noreferrer">${escape(text)}</a>`;
|
||||
}
|
||||
}
|
||||
|
||||
function toUtcString(date: string) {
|
||||
return new Date(date).toISOString();
|
||||
return new Date(date).toISOString();
|
||||
}
|
||||
|
||||
function tryGetFrontMatterBlock(filePath: string): string {
|
||||
const contents = fs.readFileSync(filePath, 'utf8');
|
||||
const matches = contents.match(/^\s*---([\S\s]*?)\n---/);
|
||||
if (!matches) return '';
|
||||
return matches[1];
|
||||
const contents = fs.readFileSync(filePath, 'utf8');
|
||||
const matches = contents.match(/^\s*---([\S\s]*?)\n---/);
|
||||
if (!matches) return '';
|
||||
return matches[1];
|
||||
}
|
||||
|
||||
@@ -1,285 +1,285 @@
|
||||
<!doctype html>
|
||||
<html dir="ltr" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="theme-color" content="hsl(186, 44%, 15%)" media="(prefers-color-scheme: dark)" />
|
||||
<meta name="theme-color" content="hsl(186, 37%, 93%)" media="(prefers-color-scheme: light)" />
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="theme-color" content="hsl(186, 44%, 15%)" media="(prefers-color-scheme: dark)" />
|
||||
<meta name="theme-color" content="hsl(186, 37%, 93%)" media="(prefers-color-scheme: light)" />
|
||||
|
||||
<title>Tauri Docs Translation Status</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Translation progress tracker for the Tauri Docs site. See how much has been translated in your language and get involved!"
|
||||
/>
|
||||
<link rel="canonical" href="https://v2.tauri.app" />
|
||||
<meta property="og:title" content="Tauri Docs Translation Status" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://v2.tauri.app/" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Translation progress tracker for the Tauri Docs site. See how much has been translated in your language and get involved!"
|
||||
/>
|
||||
<title>Tauri Docs Translation Status</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Translation progress tracker for the Tauri Docs site. See how much has been translated in your language and get involved!"
|
||||
/>
|
||||
<link rel="canonical" href="https://v2.tauri.app" />
|
||||
<meta property="og:title" content="Tauri Docs Translation Status" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://v2.tauri.app/" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Translation progress tracker for the Tauri Docs site. See how much has been translated in your language and get involved!"
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
|
||||
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif,
|
||||
Apple Color Emoji, Segoe UI Emoji;
|
||||
--font-body: system-ui, var(--font-fallback);
|
||||
--theme-accent: hsl(186, 100%, 87%);
|
||||
--theme-bg: hsl(186, 13%, 10%);
|
||||
--theme-table-header: hsl(186, 14%, 16%);
|
||||
--theme-table-border: 1px solid hsl(186, 13%, 16%);
|
||||
--theme-table-hover: hsl(186, 13%, 16%);
|
||||
--theme-text: hsl(186, 8%, 77%);
|
||||
--theme-text-bright: hsl(0, 0%, 100%);
|
||||
--overlay-blurple: hsla(186, 60%, 60%, 0.2);
|
||||
}
|
||||
--font-fallback: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif,
|
||||
Apple Color Emoji, Segoe UI Emoji;
|
||||
--font-body: system-ui, var(--font-fallback);
|
||||
--theme-accent: hsl(186, 100%, 87%);
|
||||
--theme-bg: hsl(186, 13%, 10%);
|
||||
--theme-table-header: hsl(186, 14%, 16%);
|
||||
--theme-table-border: 1px solid hsl(186, 13%, 16%);
|
||||
--theme-table-hover: hsl(186, 13%, 16%);
|
||||
--theme-text: hsl(186, 8%, 77%);
|
||||
--theme-text-bright: hsl(0, 0%, 100%);
|
||||
--overlay-blurple: hsla(186, 60%, 60%, 0.2);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--theme-text);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
font-family: var(--font-body);
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
margin-block: 2rem;
|
||||
margin-inline: 1rem;
|
||||
background:
|
||||
linear-gradient(215deg, var(--overlay-blurple), transparent 40%),
|
||||
radial-gradient(var(--overlay-blurple), transparent 40%) no-repeat -60vw -40vh / 105vw
|
||||
200vh,
|
||||
radial-gradient(var(--overlay-blurple), transparent 65%) no-repeat 50% calc(100% + 20rem) /
|
||||
60rem 30rem,
|
||||
var(--theme-bg);
|
||||
}
|
||||
body {
|
||||
color: var(--theme-text);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
font-family: var(--font-body);
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
margin-block: 2rem;
|
||||
margin-inline: 1rem;
|
||||
background:
|
||||
linear-gradient(215deg, var(--overlay-blurple), transparent 40%),
|
||||
radial-gradient(var(--overlay-blurple), transparent 40%) no-repeat -60vw -40vh / 105vw
|
||||
200vh,
|
||||
radial-gradient(var(--overlay-blurple), transparent 65%) no-repeat 50% calc(100% + 20rem) /
|
||||
60rem 30rem,
|
||||
var(--theme-bg);
|
||||
}
|
||||
|
||||
:is(h1, h2, h3, h4, h5, h6) {
|
||||
color: var(--theme-text-bright);
|
||||
margin-bottom: 1rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.3;
|
||||
}
|
||||
:is(h1, h2, h3, h4, h5, h6) {
|
||||
color: var(--theme-text-bright);
|
||||
margin-bottom: 1rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
:is(h2):not(:first-child) {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
:is(h2):not(:first-child) {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
:is(h3, h4):not(:first-child) {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
:is(h3, h4):not(:first-child) {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
:is(h5, h6):not(:first-child) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
:is(h5, h6):not(:first-child) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
max-width: 40ch;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
max-width: 40ch;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 900;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
|
||||
@media (min-width: 37.75em) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 37.75em) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
max-width: 80ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
main {
|
||||
max-width: 80ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.limit-to-viewport {
|
||||
max-width: calc(100vw - 2rem);
|
||||
}
|
||||
.limit-to-viewport {
|
||||
max-width: calc(100vw - 2rem);
|
||||
}
|
||||
|
||||
p + p {
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
p + p {
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--theme-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
a {
|
||||
color: var(--theme-accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h2 a {
|
||||
color: inherit;
|
||||
}
|
||||
h2 a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
p a {
|
||||
color: var(--theme-accent);
|
||||
text-decoration: underline;
|
||||
}
|
||||
p a {
|
||||
color: var(--theme-accent);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--theme-text-bright);
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--theme-text-bright);
|
||||
}
|
||||
|
||||
ul {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
ul {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
details {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
details {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
details summary {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
details summary {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
details summary:hover strong {
|
||||
color: var(--theme-accent-secondary);
|
||||
}
|
||||
details summary:hover strong {
|
||||
color: var(--theme-accent-secondary);
|
||||
}
|
||||
|
||||
details h5 {
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
details h5 {
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
|
||||
details > :last-child {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
details > :last-child {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.create-button {
|
||||
padding: 0.1em 0.5em;
|
||||
background-color: hsl(213deg 89% 64% / 20%);
|
||||
display: inline-block;
|
||||
border-radius: 0.5em;
|
||||
font-weight: bold;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.create-button {
|
||||
padding: 0.1em 0.5em;
|
||||
background-color: hsl(213deg 89% 64% / 20%);
|
||||
display: inline-block;
|
||||
border-radius: 0.5em;
|
||||
font-weight: bold;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.status-by-page {
|
||||
margin-bottom: 1rem;
|
||||
border-collapse: collapse;
|
||||
margin-inline: -1rem;
|
||||
border: var(--theme-table-border);
|
||||
font-size: 0.8125rem;
|
||||
width: 85%;
|
||||
}
|
||||
.status-by-page {
|
||||
margin-bottom: 1rem;
|
||||
border-collapse: collapse;
|
||||
margin-inline: -1rem;
|
||||
border: var(--theme-table-border);
|
||||
font-size: 0.8125rem;
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
gap: 5px;
|
||||
}
|
||||
.table-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.status-by-page th {
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
background: var(--theme-table-header);
|
||||
white-space: nowrap;
|
||||
padding-inline: 0.3rem;
|
||||
}
|
||||
.status-by-page th {
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
background: var(--theme-table-header);
|
||||
white-space: nowrap;
|
||||
padding-inline: 0.3rem;
|
||||
}
|
||||
|
||||
.status-by-page th,
|
||||
.status-by-page td {
|
||||
padding-block: 0.2rem;
|
||||
}
|
||||
.status-by-page th,
|
||||
.status-by-page td {
|
||||
padding-block: 0.2rem;
|
||||
}
|
||||
|
||||
.status-by-page tbody tr:not(.spacer):hover td {
|
||||
background: var(--theme-table-hover);
|
||||
}
|
||||
.status-by-page tbody tr:not(.spacer):hover td {
|
||||
background: var(--theme-table-hover);
|
||||
}
|
||||
|
||||
.status-by-page .spacer td {
|
||||
height: 0.5rem;
|
||||
}
|
||||
.status-by-page .spacer td {
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
.status-by-page th:first-of-type,
|
||||
.status-by-page td:first-of-type {
|
||||
text-align: left;
|
||||
padding-inline-start: 1rem;
|
||||
}
|
||||
.status-by-page th:first-of-type,
|
||||
.status-by-page td:first-of-type {
|
||||
text-align: left;
|
||||
padding-inline-start: 1rem;
|
||||
}
|
||||
|
||||
.status-by-page th:last-of-type,
|
||||
.status-by-page td:last-of-type {
|
||||
text-align: center;
|
||||
padding-inline-end: 1rem;
|
||||
}
|
||||
.status-by-page th:last-of-type,
|
||||
.status-by-page td:last-of-type {
|
||||
text-align: center;
|
||||
padding-inline-end: 1rem;
|
||||
}
|
||||
|
||||
.status-by-page td:not(:first-of-type) {
|
||||
min-width: 2rem;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
}
|
||||
.status-by-page td:not(:first-of-type) {
|
||||
min-width: 2rem;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.status-by-page td:not(:first-of-type) a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.status-by-page td:not(:first-of-type) a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.progress-summary {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.progress-summary {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
.progress-bar {
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
.main-container {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="main-container">
|
||||
<div class="limit-to-viewport">
|
||||
<h1>Tauri Docs Translation Status</h1>
|
||||
<body>
|
||||
<main class="main-container">
|
||||
<div class="limit-to-viewport">
|
||||
<h1>Tauri Docs Translation Status</h1>
|
||||
|
||||
<p>
|
||||
If you're interested in helping us translate
|
||||
<a href="https://v2.tauri.app/">v2.tauri.app</a> into one of the languages listed below,
|
||||
you've come to the right place! This auto-updating page always lists all the content that
|
||||
could use your help right now.
|
||||
</p>
|
||||
<p>
|
||||
If you're interested in helping us translate
|
||||
<a href="https://v2.tauri.app/">v2.tauri.app</a> into one of the languages listed below,
|
||||
you've come to the right place! This auto-updating page always lists all the content that
|
||||
could use your help right now.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Read the
|
||||
<a href="https://github.com/tauri-apps/tauri-docs/blob/v2/.github/TRANSLATING.md"
|
||||
>Translations Guide</a
|
||||
>
|
||||
for how to translate a document. Before starting a new translation, be sure to check the
|
||||
<a href="#needs-review">existing Tauri Docs PRs</a> to see if this page has already been
|
||||
translated, and consider reviewing any open PRs in your language!
|
||||
</p>
|
||||
<p>
|
||||
Read the
|
||||
<a href="https://github.com/tauri-apps/tauri-docs/blob/v2/.github/TRANSLATING.md"
|
||||
>Translations Guide</a
|
||||
>
|
||||
for how to translate a document. Before starting a new translation, be sure to check the
|
||||
<a href="#needs-review">existing Tauri Docs PRs</a> to see if this page has already been
|
||||
translated, and consider reviewing any open PRs in your language!
|
||||
</p>
|
||||
|
||||
<h2 id="by-language">
|
||||
<a href="#by-language">Translation progress by language</a>
|
||||
</h2>
|
||||
<!-- TranslationStatusByLanguage -->
|
||||
<h2 id="by-language">
|
||||
<a href="#by-language">Translation progress by language</a>
|
||||
</h2>
|
||||
<!-- TranslationStatusByLanguage -->
|
||||
|
||||
<h2 id="needs-review">
|
||||
<a href="#needs-review">Translations that need reviews</a>
|
||||
</h2>
|
||||
<!-- TranslationNeedsReview -->
|
||||
<h2 id="needs-review">
|
||||
<a href="#needs-review">Translations that need reviews</a>
|
||||
</h2>
|
||||
<!-- TranslationNeedsReview -->
|
||||
|
||||
<h2 id="by-content">
|
||||
<a href="#by-content">Translation status by content</a>
|
||||
</h2>
|
||||
</div>
|
||||
<!-- This table is not limited to the viewport to allow horizontal scrolling -->
|
||||
<!-- TranslationStatusByPage -->
|
||||
</main>
|
||||
</body>
|
||||
<h2 id="by-content">
|
||||
<a href="#by-content">Translation status by content</a>
|
||||
</h2>
|
||||
</div>
|
||||
<!-- This table is not limited to the viewport to allow horizontal scrolling -->
|
||||
<!-- TranslationStatusByPage -->
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
export type PageIndex = {
|
||||
[language: string]: {
|
||||
[pagePath: string]: PageData;
|
||||
};
|
||||
[language: string]: {
|
||||
[pagePath: string]: PageData;
|
||||
};
|
||||
};
|
||||
|
||||
export type PageData = {
|
||||
lastChange: string;
|
||||
lastCommitMsg: string;
|
||||
lastMajorChange: string;
|
||||
lastMajorCommitMsg: string;
|
||||
i18nReady?: boolean;
|
||||
lastChange: string;
|
||||
lastCommitMsg: string;
|
||||
lastMajorChange: string;
|
||||
lastMajorCommitMsg: string;
|
||||
i18nReady?: boolean;
|
||||
};
|
||||
|
||||
export type PageTranslationStatus = {
|
||||
subpath: string;
|
||||
sourcePage: PageData;
|
||||
githubUrl: string;
|
||||
translations: {
|
||||
[language: string]: {
|
||||
page: PageData;
|
||||
isMissing: boolean;
|
||||
isOutdated: boolean;
|
||||
githubUrl: string;
|
||||
sourceHistoryUrl: string;
|
||||
};
|
||||
};
|
||||
subpath: string;
|
||||
sourcePage: PageData;
|
||||
githubUrl: string;
|
||||
translations: {
|
||||
[language: string]: {
|
||||
page: PageData;
|
||||
isMissing: boolean;
|
||||
isOutdated: boolean;
|
||||
githubUrl: string;
|
||||
sourceHistoryUrl: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,198 +1,198 @@
|
||||
import {
|
||||
Application,
|
||||
DeclarationReflection,
|
||||
Options,
|
||||
PageEvent,
|
||||
Reflection,
|
||||
SignatureReflection,
|
||||
TSConfigReader,
|
||||
type TypeDocOptions,
|
||||
Application,
|
||||
DeclarationReflection,
|
||||
Options,
|
||||
PageEvent,
|
||||
Reflection,
|
||||
SignatureReflection,
|
||||
TSConfigReader,
|
||||
type TypeDocOptions,
|
||||
} from 'typedoc';
|
||||
import {
|
||||
MarkdownPageEvent,
|
||||
MarkdownTheme,
|
||||
MarkdownThemeContext,
|
||||
type MarkdownApplication,
|
||||
type PluginOptions,
|
||||
MarkdownPageEvent,
|
||||
MarkdownTheme,
|
||||
MarkdownThemeContext,
|
||||
type MarkdownApplication,
|
||||
type PluginOptions,
|
||||
} from 'typedoc-plugin-markdown';
|
||||
import { existsSync } from 'node:fs';
|
||||
|
||||
const typeDocConfigBaseOptions: Partial<TypeDocOptions | PluginOptions> = {
|
||||
// TypeDoc options
|
||||
// https://typedoc.org/options/
|
||||
githubPages: false,
|
||||
hideGenerator: true,
|
||||
theme: 'tauri-theme',
|
||||
plugin: ['typedoc-plugin-mdn-links', 'typedoc-plugin-markdown'],
|
||||
readme: 'none',
|
||||
logLevel: 'Warn',
|
||||
parametersFormat: 'table',
|
||||
// typedoc-plugin-markdown options
|
||||
// https://github.com/tgreyuk/typedoc-plugin-markdown/blob/next/packages/typedoc-plugin-markdown/docs/usage/options.md
|
||||
outputFileStrategy: 'modules',
|
||||
flattenOutputFiles: true,
|
||||
entryFileName: 'index.md',
|
||||
hidePageHeader: true,
|
||||
hidePageTitle: true,
|
||||
hideBreadcrumbs: true,
|
||||
useCodeBlocks: true,
|
||||
propertiesFormat: 'table',
|
||||
typeDeclarationFormat: 'table',
|
||||
useHTMLAnchors: true,
|
||||
// TypeDoc options
|
||||
// https://typedoc.org/options/
|
||||
githubPages: false,
|
||||
hideGenerator: true,
|
||||
theme: 'tauri-theme',
|
||||
plugin: ['typedoc-plugin-mdn-links', 'typedoc-plugin-markdown'],
|
||||
readme: 'none',
|
||||
logLevel: 'Warn',
|
||||
parametersFormat: 'table',
|
||||
// typedoc-plugin-markdown options
|
||||
// https://github.com/tgreyuk/typedoc-plugin-markdown/blob/next/packages/typedoc-plugin-markdown/docs/usage/options.md
|
||||
outputFileStrategy: 'modules',
|
||||
flattenOutputFiles: true,
|
||||
entryFileName: 'index.md',
|
||||
hidePageHeader: true,
|
||||
hidePageTitle: true,
|
||||
hideBreadcrumbs: true,
|
||||
useCodeBlocks: true,
|
||||
propertiesFormat: 'table',
|
||||
typeDeclarationFormat: 'table',
|
||||
useHTMLAnchors: true,
|
||||
};
|
||||
|
||||
async function generator() {
|
||||
if (existsSync('../tauri/tooling/api/node_modules')) {
|
||||
const coreJsOptions: Partial<TypeDocOptions> = {
|
||||
entryPoints: ['../tauri/tooling/api/src/index.ts'],
|
||||
tsconfig: '../tauri/tooling/api/tsconfig.json',
|
||||
gitRevision: 'dev',
|
||||
publicPath: '/reference/javascript/api/',
|
||||
basePath: '/reference/javascript/api/',
|
||||
...typeDocConfigBaseOptions,
|
||||
};
|
||||
if (existsSync('../tauri/tooling/api/node_modules')) {
|
||||
const coreJsOptions: Partial<TypeDocOptions> = {
|
||||
entryPoints: ['../tauri/tooling/api/src/index.ts'],
|
||||
tsconfig: '../tauri/tooling/api/tsconfig.json',
|
||||
gitRevision: 'dev',
|
||||
publicPath: '/reference/javascript/api/',
|
||||
basePath: '/reference/javascript/api/',
|
||||
...typeDocConfigBaseOptions,
|
||||
};
|
||||
|
||||
await generateDocs(coreJsOptions);
|
||||
} else {
|
||||
console.log(
|
||||
'Tauri V2 submodule is not initialized, respective API routes will not be rendered.'
|
||||
);
|
||||
}
|
||||
await generateDocs(coreJsOptions);
|
||||
} else {
|
||||
console.log(
|
||||
'Tauri V2 submodule is not initialized, respective API routes will not be rendered.'
|
||||
);
|
||||
}
|
||||
|
||||
const plugins = [
|
||||
'authenticator',
|
||||
'autostart',
|
||||
'barcode-scanner',
|
||||
'biometric',
|
||||
'cli',
|
||||
'clipboard-manager',
|
||||
'deep-link',
|
||||
'dialog',
|
||||
'fs',
|
||||
'global-shortcut',
|
||||
'http',
|
||||
'log',
|
||||
'nfc',
|
||||
'notification',
|
||||
'os',
|
||||
'positioner',
|
||||
'process',
|
||||
'shell',
|
||||
'sql',
|
||||
'store',
|
||||
'stronghold',
|
||||
'updater',
|
||||
'upload',
|
||||
'websocket',
|
||||
'window-state',
|
||||
];
|
||||
const plugins = [
|
||||
'authenticator',
|
||||
'autostart',
|
||||
'barcode-scanner',
|
||||
'biometric',
|
||||
'cli',
|
||||
'clipboard-manager',
|
||||
'deep-link',
|
||||
'dialog',
|
||||
'fs',
|
||||
'global-shortcut',
|
||||
'http',
|
||||
'log',
|
||||
'nfc',
|
||||
'notification',
|
||||
'os',
|
||||
'positioner',
|
||||
'process',
|
||||
'shell',
|
||||
'sql',
|
||||
'store',
|
||||
'stronghold',
|
||||
'updater',
|
||||
'upload',
|
||||
'websocket',
|
||||
'window-state',
|
||||
];
|
||||
|
||||
if (existsSync('../plugins-workspace/node_modules')) {
|
||||
plugins.forEach(async (plugin) => {
|
||||
const pluginJsOptions: Partial<TypeDocOptions> = {
|
||||
entryPoints: [`../plugins-workspace/plugins/${plugin}/guest-js/index.ts`],
|
||||
tsconfig: `../plugins-workspace/plugins/${plugin}/tsconfig.json`,
|
||||
gitRevision: 'v2',
|
||||
publicPath: `/reference/javascript/`,
|
||||
basePath: `/reference/javascript/`,
|
||||
...typeDocConfigBaseOptions,
|
||||
// Must go after to override base
|
||||
entryFileName: `${plugin}.md`,
|
||||
};
|
||||
if (existsSync('../plugins-workspace/node_modules')) {
|
||||
plugins.forEach(async (plugin) => {
|
||||
const pluginJsOptions: Partial<TypeDocOptions> = {
|
||||
entryPoints: [`../plugins-workspace/plugins/${plugin}/guest-js/index.ts`],
|
||||
tsconfig: `../plugins-workspace/plugins/${plugin}/tsconfig.json`,
|
||||
gitRevision: 'v2',
|
||||
publicPath: `/reference/javascript/`,
|
||||
basePath: `/reference/javascript/`,
|
||||
...typeDocConfigBaseOptions,
|
||||
// Must go after to override base
|
||||
entryFileName: `${plugin}.md`,
|
||||
};
|
||||
|
||||
await generateDocs(pluginJsOptions);
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
'Plugins workspace submodule is not initialized, respective API routes will not be rendered.'
|
||||
);
|
||||
}
|
||||
await generateDocs(pluginJsOptions);
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
'Plugins workspace submodule is not initialized, respective API routes will not be rendered.'
|
||||
);
|
||||
}
|
||||
|
||||
if (existsSync('../tauri/tooling/api/node_modules')) {
|
||||
const coreJsOptions: Partial<TypeDocOptions> = {
|
||||
entryPoints: ['../tauri/tooling/api/src/index.ts'],
|
||||
tsconfig: '../tauri/tooling/api/tsconfig.json',
|
||||
gitRevision: 'dev',
|
||||
publicPath: '/reference/javascript/api/',
|
||||
basePath: '/reference/javascript/api/',
|
||||
...typeDocConfigBaseOptions,
|
||||
};
|
||||
if (existsSync('../tauri/tooling/api/node_modules')) {
|
||||
const coreJsOptions: Partial<TypeDocOptions> = {
|
||||
entryPoints: ['../tauri/tooling/api/src/index.ts'],
|
||||
tsconfig: '../tauri/tooling/api/tsconfig.json',
|
||||
gitRevision: 'dev',
|
||||
publicPath: '/reference/javascript/api/',
|
||||
basePath: '/reference/javascript/api/',
|
||||
...typeDocConfigBaseOptions,
|
||||
};
|
||||
|
||||
await generateDocs(coreJsOptions);
|
||||
} else {
|
||||
console.log(
|
||||
'Tauri V2 submodule is not initialized, respective API routes will not be rendered.'
|
||||
);
|
||||
}
|
||||
await generateDocs(coreJsOptions);
|
||||
} else {
|
||||
console.log(
|
||||
'Tauri V2 submodule is not initialized, respective API routes will not be rendered.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/HiDeoo/starlight-typedoc
|
||||
async function generateDocs(options: Partial<TypeDocOptions>) {
|
||||
const outputDir = `../../src/content/docs${options.publicPath}`;
|
||||
const outputDir = `../../src/content/docs${options.publicPath}`;
|
||||
|
||||
const app = await Application.bootstrapWithPlugins(options);
|
||||
app.options.addReader(new TSConfigReader());
|
||||
// @ts-ignore
|
||||
app.renderer.defineTheme('tauri-theme', TauriTheme);
|
||||
const app = await Application.bootstrapWithPlugins(options);
|
||||
app.options.addReader(new TSConfigReader());
|
||||
// @ts-ignore
|
||||
app.renderer.defineTheme('tauri-theme', TauriTheme);
|
||||
|
||||
app.renderer.on(PageEvent.END, (event: PageEvent<DeclarationReflection>) => {
|
||||
pageEventEnd(event);
|
||||
});
|
||||
app.renderer.on(PageEvent.END, (event: PageEvent<DeclarationReflection>) => {
|
||||
pageEventEnd(event);
|
||||
});
|
||||
|
||||
const project = await app.convert();
|
||||
const project = await app.convert();
|
||||
|
||||
if (project) {
|
||||
await app.generateDocs(project, outputDir);
|
||||
}
|
||||
if (project) {
|
||||
await app.generateDocs(project, outputDir);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds frontmatter to the top of the file
|
||||
// Adapted from https://github.com/HiDeoo/starlight-typedoc
|
||||
function pageEventEnd(event: PageEvent<DeclarationReflection>) {
|
||||
if (!event.contents) {
|
||||
return;
|
||||
}
|
||||
const frontmatter = [
|
||||
'---',
|
||||
`title: "${event.model.name}"`,
|
||||
'editUrl: false',
|
||||
'sidebar:',
|
||||
` label: "${event.model.name.replace('@tauri-apps/plugin-', '')}"`,
|
||||
'---',
|
||||
'',
|
||||
event.contents,
|
||||
];
|
||||
event.contents = frontmatter.join('\n');
|
||||
if (!event.contents) {
|
||||
return;
|
||||
}
|
||||
const frontmatter = [
|
||||
'---',
|
||||
`title: "${event.model.name}"`,
|
||||
'editUrl: false',
|
||||
'sidebar:',
|
||||
` label: "${event.model.name.replace('@tauri-apps/plugin-', '')}"`,
|
||||
'---',
|
||||
'',
|
||||
event.contents,
|
||||
];
|
||||
event.contents = frontmatter.join('\n');
|
||||
}
|
||||
class TauriThemeRenderContext extends MarkdownThemeContext {
|
||||
constructor(theme: MarkdownTheme, page: MarkdownPageEvent<Reflection>, options: Options) {
|
||||
super(theme, page, options);
|
||||
this.partials = {
|
||||
...this.partials,
|
||||
// Formats `@source` to be a single line
|
||||
sources: (model: DeclarationReflection | SignatureReflection, options: object) => {
|
||||
if (!model.sources) {
|
||||
return '';
|
||||
}
|
||||
let label = model.sources.length > 1 ? '**Sources**: ' : '**Source**: ';
|
||||
const sources = model.sources.map((source) => `${source.url}`);
|
||||
return label + sources.join(', ');
|
||||
},
|
||||
};
|
||||
}
|
||||
constructor(theme: MarkdownTheme, page: MarkdownPageEvent<Reflection>, options: Options) {
|
||||
super(theme, page, options);
|
||||
this.partials = {
|
||||
...this.partials,
|
||||
// Formats `@source` to be a single line
|
||||
sources: (model: DeclarationReflection | SignatureReflection, options: object) => {
|
||||
if (!model.sources) {
|
||||
return '';
|
||||
}
|
||||
let label = model.sources.length > 1 ? '**Sources**: ' : '**Source**: ';
|
||||
const sources = model.sources.map((source) => `${source.url}`);
|
||||
return label + sources.join(', ');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/HiDeoo/starlight-typedoc/blob/d95072e218004276942a5132ec8a4e3561425903/packages/starlight-typedoc/src/libs/theme.ts#L28
|
||||
override getRelativeUrl = (url: string) => {
|
||||
url = super.getRelativeUrl(url).replaceAll('.md', '').replaceAll('.', '').toLowerCase();
|
||||
return url;
|
||||
};
|
||||
// Adapted from https://github.com/HiDeoo/starlight-typedoc/blob/d95072e218004276942a5132ec8a4e3561425903/packages/starlight-typedoc/src/libs/theme.ts#L28
|
||||
override getRelativeUrl = (url: string) => {
|
||||
url = super.getRelativeUrl(url).replaceAll('.md', '').replaceAll('.', '').toLowerCase();
|
||||
return url;
|
||||
};
|
||||
}
|
||||
|
||||
// Overrides and extensions based on https://github.com/tgreyuk/typedoc-plugin-markdown/blob/next/packages/typedoc-plugin-markdown/docs/usage/customizing.md
|
||||
class TauriTheme extends MarkdownTheme {
|
||||
getRenderContext(page: MarkdownPageEvent<Reflection>): MarkdownThemeContext {
|
||||
return new TauriThemeRenderContext(this, page, this.application.options);
|
||||
}
|
||||
getRenderContext(page: MarkdownPageEvent<Reflection>): MarkdownThemeContext {
|
||||
return new TauriThemeRenderContext(this, page, this.application.options);
|
||||
}
|
||||
}
|
||||
|
||||
generator();
|
||||
|
||||
@@ -2,131 +2,131 @@ import { writeFileSync, mkdirSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const note =
|
||||
'\n# NOTE: This file is auto-generated in packages/releases-generator/build.ts\n# For corrections please edit it directly';
|
||||
'\n# NOTE: This file is auto-generated in packages/releases-generator/build.ts\n# For corrections please edit it directly';
|
||||
const packages = [
|
||||
{
|
||||
name: 'tauri',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/core/tauri/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: '@tauri-apps/api',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/api/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tauri-cli',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/cli/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: '@tauri-apps/cli',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/cli/node/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tauri-bundler',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/bundler/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'wry',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/wry/dev/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/wry/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tao',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tao/dev/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tao/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tauri',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/core/tauri/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: '@tauri-apps/api',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/api/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tauri-cli',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/cli/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: '@tauri-apps/cli',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/cli/node/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tauri-bundler',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/tooling/bundler/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tauri/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'wry',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/wry/dev/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/wry/release/tag',
|
||||
},
|
||||
{
|
||||
name: 'tao',
|
||||
url: 'https://raw.githubusercontent.com/tauri-apps/tao/dev/CHANGELOG.md',
|
||||
tag: 'https://github.com/tauri-apps/tao/release/tag',
|
||||
},
|
||||
];
|
||||
|
||||
const baseDir = '../../src/content/docs/release';
|
||||
|
||||
let latestVersions: {
|
||||
[key: string]: string;
|
||||
[key: string]: string;
|
||||
} = {};
|
||||
|
||||
async function generator() {
|
||||
for (const pkg of packages) {
|
||||
const response = await fetch(pkg.url);
|
||||
const responseText: string = await response.text();
|
||||
const releases = responseText
|
||||
.split('## \\[')
|
||||
.filter((item) => !item.includes('# Changelog'))
|
||||
.map((section) => {
|
||||
const [version, ...c] = section.split('\n');
|
||||
const contents = c.join('\n');
|
||||
return {
|
||||
version: version.replace('\\[', '').replace(']', ''),
|
||||
notes: contents,
|
||||
};
|
||||
})
|
||||
.filter(({ version }) => !version.includes('Not Published'));
|
||||
for (const pkg of packages) {
|
||||
const response = await fetch(pkg.url);
|
||||
const responseText: string = await response.text();
|
||||
const releases = responseText
|
||||
.split('## \\[')
|
||||
.filter((item) => !item.includes('# Changelog'))
|
||||
.map((section) => {
|
||||
const [version, ...c] = section.split('\n');
|
||||
const contents = c.join('\n');
|
||||
return {
|
||||
version: version.replace('\\[', '').replace(']', ''),
|
||||
notes: contents,
|
||||
};
|
||||
})
|
||||
.filter(({ version }) => !version.includes('Not Published'));
|
||||
|
||||
mkdirSync(join(baseDir, pkg.name), { recursive: true });
|
||||
//
|
||||
/*
|
||||
* Write files for each version
|
||||
*/
|
||||
const len = releases.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
/**
|
||||
* Deal with next-prev labels
|
||||
*/
|
||||
const thisVersion = releases[i].version;
|
||||
mkdirSync(join(baseDir, pkg.name), { recursive: true });
|
||||
//
|
||||
/*
|
||||
* Write files for each version
|
||||
*/
|
||||
const len = releases.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
/**
|
||||
* Deal with next-prev labels
|
||||
*/
|
||||
const thisVersion = releases[i].version;
|
||||
|
||||
if (i === 0) {
|
||||
// latest version
|
||||
latestVersions[pkg.name] = `v${thisVersion}`;
|
||||
}
|
||||
//
|
||||
const pageFrontmatter = [
|
||||
note,
|
||||
`title: '${pkg.name}@${thisVersion}'`,
|
||||
`description: '${thisVersion}'`,
|
||||
`slug: 'release/${pkg.name}/v${thisVersion}'`,
|
||||
`tableOfContents: false`,
|
||||
`editUrl: 'https://github.com/tauri-apps/tauri-docs/packages/releases-generator/build.ts'`,
|
||||
'pagefind: false',
|
||||
'sidebar:',
|
||||
` label: ${thisVersion}`,
|
||||
` order: ${semverToInt(thisVersion)}`,
|
||||
];
|
||||
if (i === 0) {
|
||||
// latest version
|
||||
latestVersions[pkg.name] = `v${thisVersion}`;
|
||||
}
|
||||
//
|
||||
const pageFrontmatter = [
|
||||
note,
|
||||
`title: '${pkg.name}@${thisVersion}'`,
|
||||
`description: '${thisVersion}'`,
|
||||
`slug: 'release/${pkg.name}/v${thisVersion}'`,
|
||||
`tableOfContents: false`,
|
||||
`editUrl: 'https://github.com/tauri-apps/tauri-docs/packages/releases-generator/build.ts'`,
|
||||
'pagefind: false',
|
||||
'sidebar:',
|
||||
` label: ${thisVersion}`,
|
||||
` order: ${semverToInt(thisVersion)}`,
|
||||
];
|
||||
|
||||
const frontmatter = ['---', ...pageFrontmatter, '---'].join('\n');
|
||||
//
|
||||
const indexLink = `[Return](/release)`;
|
||||
const viewInGitHub = `<a href="${pkg.tag}/${pkg.name}-v${thisVersion}">View on GitHub</a>`;
|
||||
const linksDiv = `<div style="margin-bottom:3rem; display: flex; justify-content: space-between; align-items: center"><span>${indexLink}</span><span>${viewInGitHub}</span></div>`;
|
||||
//
|
||||
const sidebar = `\nimport ReleaseSidebar from '@components/list/ReleaseSidebar.astro';
|
||||
const frontmatter = ['---', ...pageFrontmatter, '---'].join('\n');
|
||||
//
|
||||
const indexLink = `[Return](/release)`;
|
||||
const viewInGitHub = `<a href="${pkg.tag}/${pkg.name}-v${thisVersion}">View on GitHub</a>`;
|
||||
const linksDiv = `<div style="margin-bottom:3rem; display: flex; justify-content: space-between; align-items: center"><span>${indexLink}</span><span>${viewInGitHub}</span></div>`;
|
||||
//
|
||||
const sidebar = `\nimport ReleaseSidebar from '@components/list/ReleaseSidebar.astro';
|
||||
\n\n<ReleaseSidebar slug="release/${pkg.name}" packageName="${pkg.name}" />\n`;
|
||||
|
||||
writeFileSync(
|
||||
join(baseDir, pkg.name, `v${thisVersion}.mdx`),
|
||||
`${frontmatter}\n${linksDiv}\n${entitify(releases[i].notes)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
writeFileSync(
|
||||
join(baseDir, pkg.name, `v${thisVersion}.mdx`),
|
||||
`${frontmatter}\n${linksDiv}\n${entitify(releases[i].notes)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate index page
|
||||
const extraNote =
|
||||
'# To quickly preview changes, you can edit this file, them make sure you copy the changes over the source build.ts script\n';
|
||||
const indexPage = [
|
||||
'---',
|
||||
note,
|
||||
extraNote,
|
||||
`title: 'Tauri Core Ecosystem Releases'`,
|
||||
`editUrl: 'https://github.com/tauri-apps/tauri-docs/packages/releases-generator/build.ts'`,
|
||||
'tableOfContents: false',
|
||||
'sidebar:',
|
||||
' label: Overview',
|
||||
' order: -1000000',
|
||||
'---',
|
||||
].join('\n');
|
||||
// Generate index page
|
||||
const extraNote =
|
||||
'# To quickly preview changes, you can edit this file, them make sure you copy the changes over the source build.ts script\n';
|
||||
const indexPage = [
|
||||
'---',
|
||||
note,
|
||||
extraNote,
|
||||
`title: 'Tauri Core Ecosystem Releases'`,
|
||||
`editUrl: 'https://github.com/tauri-apps/tauri-docs/packages/releases-generator/build.ts'`,
|
||||
'tableOfContents: false',
|
||||
'sidebar:',
|
||||
' label: Overview',
|
||||
' order: -1000000',
|
||||
'---',
|
||||
].join('\n');
|
||||
|
||||
const indexPageContent = `import { LinkCard, CardGrid } from '@astrojs/starlight/components';\n
|
||||
const indexPageContent = `import { LinkCard, CardGrid } from '@astrojs/starlight/components';\n
|
||||
<CardGrid>
|
||||
<LinkCard title="tauri" href="/release/tauri/${latestVersions['tauri']}" />
|
||||
<LinkCard title="@tauri-apps/api" href="/release/@tauri-apps/api/${latestVersions['@tauri-apps/api']}" />
|
||||
@@ -137,55 +137,55 @@ async function generator() {
|
||||
<LinkCard title="tao" href="/release/tao/${latestVersions['tao']}" />
|
||||
</CardGrid>`;
|
||||
|
||||
writeFileSync(join(baseDir, 'index.mdx'), `${indexPage}\n${indexPageContent}`);
|
||||
writeFileSync(join(baseDir, 'index.mdx'), `${indexPage}\n${indexPageContent}`);
|
||||
}
|
||||
|
||||
function entitify(str: string): string {
|
||||
return str
|
||||
.replace(/[&<>"']/g, function (entity) {
|
||||
switch (entity) {
|
||||
case '&':
|
||||
return '&';
|
||||
case '<':
|
||||
return '<';
|
||||
case '>':
|
||||
return '>';
|
||||
case '"':
|
||||
return '"';
|
||||
case "'":
|
||||
return ''';
|
||||
default:
|
||||
return entity;
|
||||
}
|
||||
})
|
||||
.replace(/\$\{/g, '$\\{');
|
||||
return str
|
||||
.replace(/[&<>"']/g, function (entity) {
|
||||
switch (entity) {
|
||||
case '&':
|
||||
return '&';
|
||||
case '<':
|
||||
return '<';
|
||||
case '>':
|
||||
return '>';
|
||||
case '"':
|
||||
return '"';
|
||||
case "'":
|
||||
return ''';
|
||||
default:
|
||||
return entity;
|
||||
}
|
||||
})
|
||||
.replace(/\$\{/g, '$\\{');
|
||||
}
|
||||
|
||||
const PRE_RELEASE_VALUES: any = {
|
||||
alpha: 1,
|
||||
'beta-rc': 100,
|
||||
beta: 1000,
|
||||
rc: 100000,
|
||||
alpha: 1,
|
||||
'beta-rc': 100,
|
||||
beta: 1000,
|
||||
rc: 100000,
|
||||
};
|
||||
|
||||
function semverToInt(semver: string) {
|
||||
const BASE = 1000000000;
|
||||
let [version, preRelease] = semver.split('-');
|
||||
const [major, minor, patch] = version.split('.').map(Number);
|
||||
let preReleaseValue = 0;
|
||||
if (preRelease) {
|
||||
const match = preRelease.split('.');
|
||||
if (match) {
|
||||
const identifier = match[0];
|
||||
const number = match[1] !== undefined ? parseInt(match[1]) : 0;
|
||||
preReleaseValue = PRE_RELEASE_VALUES[identifier] + number;
|
||||
}
|
||||
}
|
||||
return BASE - (major * 100000000 + minor * 1000000 + patch * 10000 + preReleaseValue);
|
||||
const BASE = 1000000000;
|
||||
let [version, preRelease] = semver.split('-');
|
||||
const [major, minor, patch] = version.split('.').map(Number);
|
||||
let preReleaseValue = 0;
|
||||
if (preRelease) {
|
||||
const match = preRelease.split('.');
|
||||
if (match) {
|
||||
const identifier = match[0];
|
||||
const number = match[1] !== undefined ? parseInt(match[1]) : 0;
|
||||
preReleaseValue = PRE_RELEASE_VALUES[identifier] + number;
|
||||
}
|
||||
}
|
||||
return BASE - (major * 100000000 + minor * 1000000 + patch * 10000 + preReleaseValue);
|
||||
}
|
||||
|
||||
if (process.env.CONTEXT === 'production' || process.env.HEAD?.startsWith('release-pages')) {
|
||||
generator();
|
||||
generator();
|
||||
} else {
|
||||
console.info('Skipping `/release` pages build');
|
||||
console.info('Skipping `/release` pages build');
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
async function chapterNavigation() {
|
||||
let navigating = false;
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (navigating) return;
|
||||
if (e.altKey || e.ctrlKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
if (window.search && document.activeElement === window.search) {
|
||||
return;
|
||||
}
|
||||
let navigating = false;
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (navigating) return;
|
||||
if (e.altKey || e.ctrlKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
if (window.search && document.activeElement === window.search) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
let previousButton = document.querySelector('a[rel="prev"]');
|
||||
if (!previousButton && window.location.pathname !== '/') previousButton = { href: '/' };
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
let previousButton = document.querySelector('a[rel="prev"]');
|
||||
if (!previousButton && window.location.pathname !== '/') previousButton = { href: '/' };
|
||||
|
||||
if (document.referrer.includes(window.location.host))
|
||||
if (previousButton) {
|
||||
window.location.href = previousButton.href;
|
||||
navigating = true;
|
||||
}
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
let nextButton = document.querySelector('a[rel="next"]');
|
||||
if (!nextButton && window.location.pathname === '/') nextButton = { href: '/start/' };
|
||||
if (document.referrer.includes(window.location.host))
|
||||
if (previousButton) {
|
||||
window.location.href = previousButton.href;
|
||||
navigating = true;
|
||||
}
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
let nextButton = document.querySelector('a[rel="next"]');
|
||||
if (!nextButton && window.location.pathname === '/') nextButton = { href: '/start/' };
|
||||
|
||||
if (nextButton) {
|
||||
window.location.href = nextButton.href;
|
||||
navigating = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (nextButton) {
|
||||
window.location.href = nextButton.href;
|
||||
navigating = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
chapterNavigation();
|
||||
chapterNavigation();
|
||||
});
|
||||
|
||||
window.onload = function () {
|
||||
document.body.setAttribute('tabindex', '-1');
|
||||
document.body.focus();
|
||||
document.body.setAttribute('tabindex', '-1');
|
||||
document.body.focus();
|
||||
};
|
||||
|
||||
@@ -9,11 +9,11 @@ import { readFile } from 'fs/promises';
|
||||
|
||||
const md = await createMarkdownProcessor();
|
||||
const res = readFile(
|
||||
join(
|
||||
dirname(dirname(dirname(fileURLToPath(import.meta.url)))),
|
||||
'packages/awesome-tauri/README.md'
|
||||
),
|
||||
'utf-8'
|
||||
join(
|
||||
dirname(dirname(dirname(fileURLToPath(import.meta.url)))),
|
||||
'packages/awesome-tauri/README.md'
|
||||
),
|
||||
'utf-8'
|
||||
);
|
||||
const content = await md.render(await res);
|
||||
const dom = new JSDOM('<!DOCTYPE html>' + content.code);
|
||||
@@ -21,56 +21,56 @@ const document = dom.window.document;
|
||||
let categories = document.querySelectorAll('h3');
|
||||
let cards = [];
|
||||
const sections = {
|
||||
plugins: 'Plugins',
|
||||
'plugins-no-official': 'Plugins',
|
||||
integrations: 'Integrations',
|
||||
articles: 'Articles',
|
||||
guides: 'Guides',
|
||||
tutorials: 'Tutorials',
|
||||
templates: 'Templates',
|
||||
'applications-audio-video': 'Audio & Video',
|
||||
'applications-chatgpt-clients': 'ChatGPT clients',
|
||||
'applications-data': 'Data',
|
||||
'applications-developer-tools': 'Developer tools',
|
||||
'applications-email-feeds': 'Email & Feeds',
|
||||
'applications-file-management': 'File management',
|
||||
'applications-finance': 'Finance',
|
||||
'applications-gaming': 'Gaming',
|
||||
'applications-information': 'Information',
|
||||
'applications-learning': 'Learning',
|
||||
'applications-networking': 'Networking',
|
||||
'applications-office-writing': 'Office & Writing',
|
||||
'applications-productivity': 'Productivity',
|
||||
'applications-search': 'Search',
|
||||
'applications-security': 'Security',
|
||||
'applications-social-media': 'Social media',
|
||||
'applications-utilities': 'Utilities',
|
||||
plugins: 'Plugins',
|
||||
'plugins-no-official': 'Plugins',
|
||||
integrations: 'Integrations',
|
||||
articles: 'Articles',
|
||||
guides: 'Guides',
|
||||
tutorials: 'Tutorials',
|
||||
templates: 'Templates',
|
||||
'applications-audio-video': 'Audio & Video',
|
||||
'applications-chatgpt-clients': 'ChatGPT clients',
|
||||
'applications-data': 'Data',
|
||||
'applications-developer-tools': 'Developer tools',
|
||||
'applications-email-feeds': 'Email & Feeds',
|
||||
'applications-file-management': 'File management',
|
||||
'applications-finance': 'Finance',
|
||||
'applications-gaming': 'Gaming',
|
||||
'applications-information': 'Information',
|
||||
'applications-learning': 'Learning',
|
||||
'applications-networking': 'Networking',
|
||||
'applications-office-writing': 'Office & Writing',
|
||||
'applications-productivity': 'Productivity',
|
||||
'applications-search': 'Search',
|
||||
'applications-security': 'Security',
|
||||
'applications-social-media': 'Social media',
|
||||
'applications-utilities': 'Utilities',
|
||||
};
|
||||
|
||||
for (const header of categories) {
|
||||
if (header.textContent === sections[section]) {
|
||||
let list = header.nextSibling.nextSibling as HTMLElement;
|
||||
for (const entry: HTMLLinkElement of list.children) {
|
||||
if (section.includes('-no-official')) {
|
||||
let img = entry.children[1];
|
||||
if (img && img.src && img.src.includes('official')) continue;
|
||||
img = entry.children[2];
|
||||
if (img && img.src && img.src.includes('official')) continue;
|
||||
}
|
||||
cards.push({
|
||||
href: entry.children[0].href,
|
||||
name: entry.children[0].textContent,
|
||||
description: entry.textContent.split(' - ')[1],
|
||||
});
|
||||
}
|
||||
}
|
||||
if (header.textContent === sections[section]) {
|
||||
let list = header.nextSibling.nextSibling as HTMLElement;
|
||||
for (const entry: HTMLLinkElement of list.children) {
|
||||
if (section.includes('-no-official')) {
|
||||
let img = entry.children[1];
|
||||
if (img && img.src && img.src.includes('official')) continue;
|
||||
img = entry.children[2];
|
||||
if (img && img.src && img.src.includes('official')) continue;
|
||||
}
|
||||
cards.push({
|
||||
href: entry.children[0].href,
|
||||
name: entry.children[0].textContent,
|
||||
description: entry.textContent.split(' - ')[1],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
<CardGrid>
|
||||
{
|
||||
cards.map((card) => (
|
||||
<LinkCard title={card.name} description={card.description} href={card.href} />
|
||||
))
|
||||
}
|
||||
{
|
||||
cards.map((card) => (
|
||||
<LinkCard title={card.name} description={card.description} href={card.href} />
|
||||
))
|
||||
}
|
||||
</CardGrid>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
interface Props {
|
||||
placeholder?: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
const { placeholder = 'Search features and community resources...' } = Astro.props;
|
||||
|
||||
@@ -14,49 +14,49 @@ const { placeholder = 'Search features and community resources...' } = Astro.pro
|
||||
---
|
||||
|
||||
<card-search>
|
||||
<div id="search-input" class="pagefind-ui pagefind-ui--reset">
|
||||
<form
|
||||
class="pagefind-ui__form"
|
||||
role="search"
|
||||
aria-label="search_label"
|
||||
action="javascript:void(0);"
|
||||
>
|
||||
<input
|
||||
data-wrapper="search-feature-list"
|
||||
class="pagefind-ui__search-input"
|
||||
id="search"
|
||||
aria-label="search"
|
||||
placeholder={placeholder}
|
||||
title={placeholder}
|
||||
autocapitalize="none"
|
||||
enterkeyhint="search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div id="search-input" class="pagefind-ui pagefind-ui--reset">
|
||||
<form
|
||||
class="pagefind-ui__form"
|
||||
role="search"
|
||||
aria-label="search_label"
|
||||
action="javascript:void(0);"
|
||||
>
|
||||
<input
|
||||
data-wrapper="search-feature-list"
|
||||
class="pagefind-ui__search-input"
|
||||
id="search"
|
||||
aria-label="search"
|
||||
placeholder={placeholder}
|
||||
title={placeholder}
|
||||
autocapitalize="none"
|
||||
enterkeyhint="search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
|
||||
<button class="pagefind-ui__search-clear pagefind-ui__suppressed">clear</button>
|
||||
</form>
|
||||
</div>
|
||||
<slot />
|
||||
<button class="pagefind-ui__search-clear pagefind-ui__suppressed">clear</button>
|
||||
</form>
|
||||
</div>
|
||||
<slot />
|
||||
</card-search>
|
||||
|
||||
<script>
|
||||
class CardSearch extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const form = this.querySelector<HTMLFormElement>('form.pagefind-ui__form')!;
|
||||
const searchBar = this.querySelector<HTMLInputElement>('input.pagefind-ui__search-input')!;
|
||||
const clear = this.querySelector<HTMLButtonElement>('button.pagefind-ui__search-clear')!;
|
||||
const inputs = Array.from(this.children).filter((el) => el.classList.contains('card-grid'));
|
||||
const headings = Array.from(this.children).filter(
|
||||
(el) => el instanceof HTMLHeadingElement || el instanceof HTMLParagraphElement
|
||||
);
|
||||
// Create "nothing found" for each heading
|
||||
headings.forEach((heading, i) => {
|
||||
const wrn = document.createElement('p');
|
||||
wrn.classList.add('hidden', 'warning');
|
||||
wrn.id = `warn-${i}`;
|
||||
wrn.innerHTML = `
|
||||
class CardSearch extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const form = this.querySelector<HTMLFormElement>('form.pagefind-ui__form')!;
|
||||
const searchBar = this.querySelector<HTMLInputElement>('input.pagefind-ui__search-input')!;
|
||||
const clear = this.querySelector<HTMLButtonElement>('button.pagefind-ui__search-clear')!;
|
||||
const inputs = Array.from(this.children).filter((el) => el.classList.contains('card-grid'));
|
||||
const headings = Array.from(this.children).filter(
|
||||
(el) => el instanceof HTMLHeadingElement || el instanceof HTMLParagraphElement
|
||||
);
|
||||
// Create "nothing found" for each heading
|
||||
headings.forEach((heading, i) => {
|
||||
const wrn = document.createElement('p');
|
||||
wrn.classList.add('hidden', 'warning');
|
||||
wrn.id = `warn-${i}`;
|
||||
wrn.innerHTML = `
|
||||
<style>
|
||||
.warning {
|
||||
font-style: italic;
|
||||
@@ -69,170 +69,170 @@ const { placeholder = 'Search features and community resources...' } = Astro.pro
|
||||
</style>
|
||||
<span>No results found in ${heading.textContent}</span>
|
||||
`;
|
||||
heading.insertAdjacentElement('afterend', wrn);
|
||||
});
|
||||
// Select all "nothing found" created before
|
||||
const warnings = document.querySelectorAll('[id^="warn-"]');
|
||||
heading.insertAdjacentElement('afterend', wrn);
|
||||
});
|
||||
// Select all "nothing found" created before
|
||||
const warnings = document.querySelectorAll('[id^="warn-"]');
|
||||
|
||||
// Prevent page reload
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
// Prevent page reload
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
// Prevent reload on 'Enter', and enable clean input on 'Escape'
|
||||
form.addEventListener('keydown', (e) => {
|
||||
clear.classList.remove('pagefind-ui__suppressed');
|
||||
if (e.key === 'Escape') {
|
||||
reset();
|
||||
} else if (e.key === 'Enter') e.preventDefault();
|
||||
});
|
||||
searchBar.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') e.preventDefault();
|
||||
});
|
||||
// Prevent reload on 'Enter', and enable clean input on 'Escape'
|
||||
form.addEventListener('keydown', (e) => {
|
||||
clear.classList.remove('pagefind-ui__suppressed');
|
||||
if (e.key === 'Escape') {
|
||||
reset();
|
||||
} else if (e.key === 'Enter') e.preventDefault();
|
||||
});
|
||||
searchBar.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') e.preventDefault();
|
||||
});
|
||||
|
||||
// Search
|
||||
searchBar.addEventListener('keyup', () => {
|
||||
searchFilter();
|
||||
});
|
||||
// Clear search button 'X'
|
||||
clear.addEventListener('click', () => {
|
||||
clear.classList.add('pagefind-ui__suppressed');
|
||||
reset();
|
||||
});
|
||||
// Search
|
||||
searchBar.addEventListener('keyup', () => {
|
||||
searchFilter();
|
||||
});
|
||||
// Clear search button 'X'
|
||||
clear.addEventListener('click', () => {
|
||||
clear.classList.add('pagefind-ui__suppressed');
|
||||
reset();
|
||||
});
|
||||
|
||||
function reset() {
|
||||
searchBar.value = '';
|
||||
searchFilter();
|
||||
}
|
||||
function reset() {
|
||||
searchBar.value = '';
|
||||
searchFilter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to search and filter based on input
|
||||
*/
|
||||
function searchFilter() {
|
||||
const query = searchBar.value.toUpperCase();
|
||||
/**
|
||||
* Function to search and filter based on input
|
||||
*/
|
||||
function searchFilter() {
|
||||
const query = searchBar.value.toUpperCase();
|
||||
|
||||
inputs.forEach((elements, i) => {
|
||||
const cards = Array.from(elements.children);
|
||||
let total = cards.length;
|
||||
inputs.forEach((elements, i) => {
|
||||
const cards = Array.from(elements.children);
|
||||
let total = cards.length;
|
||||
|
||||
cards.forEach((el) => {
|
||||
const htmlElement = el as HTMLElement;
|
||||
const span = el.querySelector('span');
|
||||
const txtValue = span?.textContent || span?.innerText;
|
||||
if (!txtValue) return;
|
||||
cards.forEach((el) => {
|
||||
const htmlElement = el as HTMLElement;
|
||||
const span = el.querySelector('span');
|
||||
const txtValue = span?.textContent || span?.innerText;
|
||||
if (!txtValue) return;
|
||||
|
||||
// Filter list
|
||||
if (txtValue.toUpperCase().indexOf(query) > -1) {
|
||||
total++;
|
||||
htmlElement.style.display = '';
|
||||
} else {
|
||||
total--;
|
||||
htmlElement.style.display = 'none';
|
||||
}
|
||||
// Filter list
|
||||
if (txtValue.toUpperCase().indexOf(query) > -1) {
|
||||
total++;
|
||||
htmlElement.style.display = '';
|
||||
} else {
|
||||
total--;
|
||||
htmlElement.style.display = 'none';
|
||||
}
|
||||
|
||||
// Show warning if none found
|
||||
if (total === 0) {
|
||||
warnings[i].classList.remove('hidden');
|
||||
} else {
|
||||
warnings[i].classList.add('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define('card-search', CardSearch);
|
||||
// Show warning if none found
|
||||
if (total === 0) {
|
||||
warnings[i].classList.remove('hidden');
|
||||
} else {
|
||||
warnings[i].classList.add('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define('card-search', CardSearch);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--pagefind-ui-border-width: 1px;
|
||||
--pagefind-ui-scale: 0.8;
|
||||
--pagefind-ui-tag: #eeeeee;
|
||||
--pagefind-ui-border-radius: 8px;
|
||||
--pagefind-ui-image-border-radius: 8px;
|
||||
--pagefind-ui-image-box-ratio: 3 / 2;
|
||||
}
|
||||
.pagefind-ui {
|
||||
width: 100%;
|
||||
color: var(--sl-color-gray-2);
|
||||
font-family: var(--__sl-font);
|
||||
margin-block: 2rem 1rem;
|
||||
}
|
||||
.pagefind-ui__form {
|
||||
position: relative;
|
||||
}
|
||||
.pagefind-ui__form::before {
|
||||
background-color: var(--sl-color-gray-2);
|
||||
width: calc(18px * var(--pagefind-ui-scale));
|
||||
height: calc(18px * var(--pagefind-ui-scale));
|
||||
top: calc(23px * var(--pagefind-ui-scale));
|
||||
left: calc(20px * var(--pagefind-ui-scale));
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
opacity: 0.7;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");
|
||||
-webkit-mask-size: 100%;
|
||||
mask-size: 100%;
|
||||
z-index: 9;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pagefind-ui__search-input {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: flex;
|
||||
font-weight: 400;
|
||||
height: calc(64px * var(--pagefind-ui-scale));
|
||||
padding: 0 calc(70px * var(--pagefind-ui-scale)) 0 calc(54px * var(--pagefind-ui-scale));
|
||||
background-color: var(--sl-color-black);
|
||||
border: var(--pagefind-ui-border-width) solid var(--sl-color-gray-5);
|
||||
border-radius: var(--pagefind-ui-border-radius);
|
||||
font-size: calc(21px * var(--pagefind-ui-scale));
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
color: var(--sl-color-white);
|
||||
width: 100%;
|
||||
}
|
||||
:root {
|
||||
--pagefind-ui-border-width: 1px;
|
||||
--pagefind-ui-scale: 0.8;
|
||||
--pagefind-ui-tag: #eeeeee;
|
||||
--pagefind-ui-border-radius: 8px;
|
||||
--pagefind-ui-image-border-radius: 8px;
|
||||
--pagefind-ui-image-box-ratio: 3 / 2;
|
||||
}
|
||||
.pagefind-ui {
|
||||
width: 100%;
|
||||
color: var(--sl-color-gray-2);
|
||||
font-family: var(--__sl-font);
|
||||
margin-block: 2rem 1rem;
|
||||
}
|
||||
.pagefind-ui__form {
|
||||
position: relative;
|
||||
}
|
||||
.pagefind-ui__form::before {
|
||||
background-color: var(--sl-color-gray-2);
|
||||
width: calc(18px * var(--pagefind-ui-scale));
|
||||
height: calc(18px * var(--pagefind-ui-scale));
|
||||
top: calc(23px * var(--pagefind-ui-scale));
|
||||
left: calc(20px * var(--pagefind-ui-scale));
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
opacity: 0.7;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.7549 11.255H11.9649L11.6849 10.985C12.6649 9.845 13.2549 8.365 13.2549 6.755C13.2549 3.165 10.3449 0.255005 6.75488 0.255005C3.16488 0.255005 0.254883 3.165 0.254883 6.755C0.254883 10.345 3.16488 13.255 6.75488 13.255C8.36488 13.255 9.84488 12.665 10.9849 11.685L11.2549 11.965V12.755L16.2549 17.745L17.7449 16.255L12.7549 11.255ZM6.75488 11.255C4.26488 11.255 2.25488 9.245 2.25488 6.755C2.25488 4.26501 4.26488 2.255 6.75488 2.255C9.24488 2.255 11.2549 4.26501 11.2549 6.755C11.2549 9.245 9.24488 11.255 6.75488 11.255Z' fill='%23000000'/%3E%3C/svg%3E%0A");
|
||||
-webkit-mask-size: 100%;
|
||||
mask-size: 100%;
|
||||
z-index: 9;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pagefind-ui__search-input {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: flex;
|
||||
font-weight: 400;
|
||||
height: calc(64px * var(--pagefind-ui-scale));
|
||||
padding: 0 calc(70px * var(--pagefind-ui-scale)) 0 calc(54px * var(--pagefind-ui-scale));
|
||||
background-color: var(--sl-color-black);
|
||||
border: var(--pagefind-ui-border-width) solid var(--sl-color-gray-5);
|
||||
border-radius: var(--pagefind-ui-border-radius);
|
||||
font-size: calc(21px * var(--pagefind-ui-scale));
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
color: var(--sl-color-white);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagefind-ui__search-input::placeholder {
|
||||
color: var(--sl-color-gray-3);
|
||||
opacity: 1; /* Firefox */
|
||||
}
|
||||
.pagefind-ui__search-input::placeholder {
|
||||
color: var(--sl-color-gray-3);
|
||||
opacity: 1; /* Firefox */
|
||||
}
|
||||
|
||||
.pagefind-ui__search-clear {
|
||||
position: absolute;
|
||||
top: calc(3px * var(--pagefind-ui-scale));
|
||||
right: calc(3px * var(--pagefind-ui-scale));
|
||||
height: calc(58px * var(--pagefind-ui-scale));
|
||||
color: var(--sl-color-gray-2);
|
||||
font-size: calc(14px * var(--pagefind-ui-scale));
|
||||
cursor: pointer;
|
||||
border-radius: var(--pagefind-ui-border-radius);
|
||||
width: calc(60px * var(--pagefind-ui-scale));
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
.pagefind-ui__search-clear {
|
||||
position: absolute;
|
||||
top: calc(3px * var(--pagefind-ui-scale));
|
||||
right: calc(3px * var(--pagefind-ui-scale));
|
||||
height: calc(58px * var(--pagefind-ui-scale));
|
||||
color: var(--sl-color-gray-2);
|
||||
font-size: calc(14px * var(--pagefind-ui-scale));
|
||||
cursor: pointer;
|
||||
border-radius: var(--pagefind-ui-border-radius);
|
||||
width: calc(60px * var(--pagefind-ui-scale));
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pagefind-ui__search-clear:focus {
|
||||
outline: 1px solid var(--sl-color-accent);
|
||||
}
|
||||
.pagefind-ui__search-clear::before {
|
||||
content: '';
|
||||
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
center / 50% no-repeat;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
center / 50% no-repeat;
|
||||
background-color: var(--sl-color-text-accent);
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.pagefind-ui__suppressed {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pagefind-ui__search-clear:focus {
|
||||
outline: 1px solid var(--sl-color-accent);
|
||||
}
|
||||
.pagefind-ui__search-clear::before {
|
||||
content: '';
|
||||
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
center / 50% no-repeat;
|
||||
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m13.41 12 6.3-6.29a1 1 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1 1 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 .33 1.64 1 1 0 0 0 1.09-.22l6.29-6.3 6.29 6.3a1 1 0 0 0 1.64-.33 1 1 0 0 0-.22-1.09L13.41 12Z'/%3E%3C/svg%3E")
|
||||
center / 50% no-repeat;
|
||||
background-color: var(--sl-color-text-accent);
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.pagefind-ui__suppressed {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,42 +3,42 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||
import { Code } from '@astrojs/starlight/components';
|
||||
|
||||
interface Props {
|
||||
npm?: string;
|
||||
yarn?: string;
|
||||
pnpm?: string;
|
||||
cargo?: string;
|
||||
npm?: string;
|
||||
yarn?: string;
|
||||
pnpm?: string;
|
||||
cargo?: string;
|
||||
}
|
||||
|
||||
const { npm, yarn, pnpm, cargo } = Astro.props;
|
||||
---
|
||||
|
||||
<Tabs>
|
||||
{
|
||||
npm && (
|
||||
<TabItem label="npm">
|
||||
<Code code={npm} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
yarn && (
|
||||
<TabItem label="Yarn">
|
||||
<Code code={yarn} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
pnpm && (
|
||||
<TabItem label="pnpm">
|
||||
<Code code={pnpm} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
cargo && (
|
||||
<TabItem label="Cargo">
|
||||
<Code code={cargo} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
npm && (
|
||||
<TabItem label="npm">
|
||||
<Code code={npm} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
yarn && (
|
||||
<TabItem label="Yarn">
|
||||
<Code code={yarn} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
pnpm && (
|
||||
<TabItem label="pnpm">
|
||||
<Code code={pnpm} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
{
|
||||
cargo && (
|
||||
<TabItem label="Cargo">
|
||||
<Code code={cargo} lang="sh" theme="css-variables" frame="none" />
|
||||
</TabItem>
|
||||
)
|
||||
}
|
||||
</Tabs>
|
||||
|
||||
@@ -4,5 +4,5 @@ const enabled = process.env.TAURI_DEBUG && Astro.slots.has('default');
|
||||
---
|
||||
|
||||
<Card title="Demo">
|
||||
{enabled ? <slot /> : <p>Try it in the Tauri Docs app (coming soon)</p>}
|
||||
{enabled ? <slot /> : <p>Try it in the Tauri Docs app (coming soon)</p>}
|
||||
</Card>
|
||||
|
||||
@@ -7,8 +7,8 @@ const CONTENT_SET_ID = '54faa8e2-cd0d-4997-9a3c-d9fed28f358a';
|
||||
---
|
||||
|
||||
<FeelbackReaction
|
||||
contentSetId={CONTENT_SET_ID}
|
||||
key={Astro.url.pathname}
|
||||
layout="list"
|
||||
preset="feeling"
|
||||
contentSetId={CONTENT_SET_ID}
|
||||
key={Astro.url.pathname}
|
||||
layout="list"
|
||||
preset="feeling"
|
||||
/>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,19 +5,19 @@ const baseUrl = 'https://github.com/tauri-apps/tauri-docs/tree/v2';
|
||||
---
|
||||
|
||||
<Card title="Contribute" icon="pencil">
|
||||
<p>
|
||||
This is a stub and is waiting for contributions. Get involved by
|
||||
<a href={baseUrl}>visiting us on GitHub</a> or <a href="https://discord.com/invite/tauri"
|
||||
>joining us on Discord</a
|
||||
>.
|
||||
</p>
|
||||
<p>
|
||||
This is a stub and is waiting for contributions. Get involved by
|
||||
<a href={baseUrl}>visiting us on GitHub</a> or <a href="https://discord.com/invite/tauri"
|
||||
>joining us on Discord</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
{
|
||||
Astro.slots.has('default') && (
|
||||
<>
|
||||
<div>Here are some ideas to get you started:</div>
|
||||
<slot />
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
Astro.slots.has('default') && (
|
||||
<>
|
||||
<div>Here are some ideas to get you started:</div>
|
||||
<slot />
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Card>
|
||||
|
||||
@@ -7,30 +7,30 @@ interface Props extends HTMLAttributes<'a'> {}
|
||||
---
|
||||
|
||||
<div>
|
||||
<a class="not-content" {...Astro.props}>Tauri 1.0 Upgrade Guide <Icon name="rocket" /></a>
|
||||
<a class="not-content" {...Astro.props}>Tauri 1.0 Upgrade Guide <Icon name="rocket" /></a>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
display: inline-block;
|
||||
}
|
||||
div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
border: 1px solid var(--sl-color-orange-low);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
box-shadow: var(--sl-shadow-sm);
|
||||
color: var(--sl-color-gray-1) !important;
|
||||
font-weight: 600;
|
||||
line-height: var(--sl-line-height-headings);
|
||||
}
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
border: 1px solid var(--sl-color-orange-low);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
box-shadow: var(--sl-shadow-sm);
|
||||
color: var(--sl-color-gray-1) !important;
|
||||
font-weight: 600;
|
||||
line-height: var(--sl-line-height-headings);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: var(--sl-color-orange-low);
|
||||
border-color: var(--sl-color-orange-high);
|
||||
}
|
||||
a:hover {
|
||||
background: var(--sl-color-orange-low);
|
||||
border-color: var(--sl-color-orange-high);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
---
|
||||
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
type Entry = {
|
||||
name: string;
|
||||
description: string;
|
||||
href: string;
|
||||
name: string;
|
||||
description: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
const list: Entry[] = [
|
||||
{
|
||||
name: 'Have something to share?',
|
||||
description: 'Open a pull request to show us your amazing resource',
|
||||
href: 'https://github.com/tauri-apps/tauri-docs/pulls',
|
||||
},
|
||||
{
|
||||
name: 'Github OAuth with Lucia',
|
||||
description: 'Authenticate users with a simple JS server',
|
||||
href: 'https://lucia-auth.com/guidebook/github-oauth-native/tauri',
|
||||
},
|
||||
{
|
||||
name: 'Have something to share?',
|
||||
description: 'Open a pull request to show us your amazing resource',
|
||||
href: 'https://github.com/tauri-apps/tauri-docs/pulls',
|
||||
},
|
||||
{
|
||||
name: 'Github OAuth with Lucia',
|
||||
description: 'Authenticate users with a simple JS server',
|
||||
href: 'https://lucia-auth.com/guidebook/github-oauth-native/tauri',
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<CardGrid>
|
||||
{
|
||||
list
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((item) => <LinkCard title={item.name} href={item.href} description={item.description} />)
|
||||
}
|
||||
{
|
||||
list
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((item) => <LinkCard title={item.name} href={item.href} description={item.description} />)
|
||||
}
|
||||
</CardGrid>
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
---
|
||||
import config from 'virtual:starlight/user-config';
|
||||
import {
|
||||
stripLeadingAndTrailingSlashes,
|
||||
ensureTrailingSlash,
|
||||
stripLeadingAndTrailingSlashes,
|
||||
ensureTrailingSlash,
|
||||
} from 'node_modules/@astrojs/starlight/utils/path';
|
||||
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
import { routes, type Route } from 'node_modules/@astrojs/starlight/utils/routing';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Slug relative to /src - e.g "/zh-cn/features"
|
||||
*
|
||||
* Note: leading and trailing slashes are dropped "/features/" === "features"
|
||||
*/
|
||||
slug: string;
|
||||
/**
|
||||
* Filter out pages by title - case insensitive
|
||||
*/
|
||||
filterOutByTitle?: string[];
|
||||
/**
|
||||
* Filter out pages by file name - case insensitive
|
||||
*/
|
||||
filterOutByFileName?: string[];
|
||||
/**
|
||||
* Force alphabetical order - by default it sorts by `frontmatter.sidebar.order`, then alphabetically.
|
||||
*
|
||||
* Use this to ignore sidebar order
|
||||
*/
|
||||
sortAlphabetically?: boolean;
|
||||
/**
|
||||
* Slug relative to /src - e.g "/zh-cn/features"
|
||||
*
|
||||
* Note: leading and trailing slashes are dropped "/features/" === "features"
|
||||
*/
|
||||
slug: string;
|
||||
/**
|
||||
* Filter out pages by title - case insensitive
|
||||
*/
|
||||
filterOutByTitle?: string[];
|
||||
/**
|
||||
* Filter out pages by file name - case insensitive
|
||||
*/
|
||||
filterOutByFileName?: string[];
|
||||
/**
|
||||
* Force alphabetical order - by default it sorts by `frontmatter.sidebar.order`, then alphabetically.
|
||||
*
|
||||
* Use this to ignore sidebar order
|
||||
*/
|
||||
sortAlphabetically?: boolean;
|
||||
}
|
||||
|
||||
function hasSidebarOrder(page: Route): number | undefined {
|
||||
return page.entry.data.sidebar.order;
|
||||
return page.entry.data.sidebar.order;
|
||||
}
|
||||
|
||||
function alphaSort(a: Route, b: Route): number {
|
||||
return a.entry.data.title.localeCompare(b.entry.data.title);
|
||||
return a.entry.data.title.localeCompare(b.entry.data.title);
|
||||
}
|
||||
|
||||
function compareOrder(a: Route, b: Route): boolean {
|
||||
return a.entry.data.sidebar.order > b.entry.data.sidebar.order;
|
||||
return a.entry.data.sidebar.order > b.entry.data.sidebar.order;
|
||||
}
|
||||
|
||||
let { slug } = Astro.props;
|
||||
@@ -53,7 +53,7 @@ let [currentPageLocale] = stripLeadingAndTrailingSlashes(Astro.url.pathname).spl
|
||||
|
||||
// Ensure currentPageLocale is a locale when it's page is on default locale
|
||||
if (!localesList.includes(currentPageLocale)) {
|
||||
currentPageLocale = defaultLocale;
|
||||
currentPageLocale = defaultLocale;
|
||||
}
|
||||
|
||||
const locale = currentPageLocale;
|
||||
@@ -62,7 +62,7 @@ const pageLang = ensureTrailingSlash(locale);
|
||||
// Ensure the locale is ignore if passed on `slug`
|
||||
let [sliceLocale] = stripLeadingAndTrailingSlashes(slug).split('/');
|
||||
if (localesList.includes(sliceLocale)) {
|
||||
slug = slug.slice(sliceLocale.length + 1);
|
||||
slug = slug.slice(sliceLocale.length + 1);
|
||||
}
|
||||
// Localize `slug` to the current page locale
|
||||
slug = locale === defaultLocale ? slug : pageLang + slug;
|
||||
@@ -71,14 +71,14 @@ let fallbackList: Route[] = [];
|
||||
let mainList: Route[] = [];
|
||||
|
||||
routes.forEach((page) => {
|
||||
// `page.slug` is the slug of the current page being looped, `slug` is a prop
|
||||
if (page.slug.startsWith(slug)) {
|
||||
if (page.isFallback) {
|
||||
fallbackList.push(page);
|
||||
} else if (page.slug !== slug) {
|
||||
mainList.push(page);
|
||||
}
|
||||
}
|
||||
// `page.slug` is the slug of the current page being looped, `slug` is a prop
|
||||
if (page.slug.startsWith(slug)) {
|
||||
if (page.isFallback) {
|
||||
fallbackList.push(page);
|
||||
} else if (page.slug !== slug) {
|
||||
mainList.push(page);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -86,86 +86,86 @@ routes.forEach((page) => {
|
||||
*/
|
||||
|
||||
if (filterOutByTitle.length > 0) {
|
||||
fallbackList = fallbackList.filter(
|
||||
(page) => !filterOutByTitle.some((val) => page.entry.data.title.includes(val))
|
||||
);
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByTitle.some((val) => page.entry.data.title.includes(val))
|
||||
);
|
||||
fallbackList = fallbackList.filter(
|
||||
(page) => !filterOutByTitle.some((val) => page.entry.data.title.includes(val))
|
||||
);
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByTitle.some((val) => page.entry.data.title.includes(val))
|
||||
);
|
||||
}
|
||||
|
||||
if (filterOutByFileName.length > 0) {
|
||||
fallbackList = fallbackList.filter(
|
||||
(page) => !filterOutByFileName.some((val) => page.entry.id.includes(val))
|
||||
);
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByFileName.some((val) => page.entry.id.includes(val))
|
||||
);
|
||||
fallbackList = fallbackList.filter(
|
||||
(page) => !filterOutByFileName.some((val) => page.entry.id.includes(val))
|
||||
);
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByFileName.some((val) => page.entry.id.includes(val))
|
||||
);
|
||||
}
|
||||
|
||||
if (!sortAlphabetically) {
|
||||
// dumb luck this works, now why?
|
||||
const sortVal = locale === defaultLocale ? 1 : -1;
|
||||
// Sort list following sidebar order
|
||||
mainList.sort((a, b) => {
|
||||
if (!hasSidebarOrder(a) && !hasSidebarOrder(b)) {
|
||||
return alphaSort(a, b);
|
||||
}
|
||||
if (compareOrder(a, b)) {
|
||||
return sortVal;
|
||||
} else {
|
||||
return -sortVal;
|
||||
}
|
||||
});
|
||||
// Sort list following sidebar order
|
||||
fallbackList.sort((a, b) => {
|
||||
if (!hasSidebarOrder(a) && !hasSidebarOrder(b)) {
|
||||
return alphaSort(a, b);
|
||||
}
|
||||
if (compareOrder(a, b)) {
|
||||
return -sortVal;
|
||||
} else {
|
||||
return sortVal;
|
||||
}
|
||||
});
|
||||
// dumb luck this works, now why?
|
||||
const sortVal = locale === defaultLocale ? 1 : -1;
|
||||
// Sort list following sidebar order
|
||||
mainList.sort((a, b) => {
|
||||
if (!hasSidebarOrder(a) && !hasSidebarOrder(b)) {
|
||||
return alphaSort(a, b);
|
||||
}
|
||||
if (compareOrder(a, b)) {
|
||||
return sortVal;
|
||||
} else {
|
||||
return -sortVal;
|
||||
}
|
||||
});
|
||||
// Sort list following sidebar order
|
||||
fallbackList.sort((a, b) => {
|
||||
if (!hasSidebarOrder(a) && !hasSidebarOrder(b)) {
|
||||
return alphaSort(a, b);
|
||||
}
|
||||
if (compareOrder(a, b)) {
|
||||
return -sortVal;
|
||||
} else {
|
||||
return sortVal;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Sort alphabetically
|
||||
mainList.sort((a, b) => alphaSort(a, b));
|
||||
fallbackList.sort((a, b) => alphaSort(a, b));
|
||||
// Sort alphabetically
|
||||
mainList.sort((a, b) => alphaSort(a, b));
|
||||
fallbackList.sort((a, b) => alphaSort(a, b));
|
||||
}
|
||||
---
|
||||
|
||||
<CardGrid>
|
||||
{
|
||||
mainList.map((item) => (
|
||||
<LinkCard
|
||||
title={item.entry.data.title}
|
||||
href={`/${item.slug}`}
|
||||
description={item.entry.data.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
{
|
||||
locale !== defaultLocale &&
|
||||
fallbackList.map((item) => (
|
||||
<LinkCard
|
||||
class="fallback-badge"
|
||||
title={item.entry.data.title}
|
||||
href={`/${item.slug}`}
|
||||
description={item.entry.data.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
{
|
||||
mainList.map((item) => (
|
||||
<LinkCard
|
||||
title={item.entry.data.title}
|
||||
href={`/${item.slug}`}
|
||||
description={item.entry.data.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
{
|
||||
locale !== defaultLocale &&
|
||||
fallbackList.map((item) => (
|
||||
<LinkCard
|
||||
class="fallback-badge"
|
||||
title={item.entry.data.title}
|
||||
href={`/${item.slug}`}
|
||||
description={item.entry.data.description}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</CardGrid>
|
||||
|
||||
<style>
|
||||
.fallback-badge:after {
|
||||
/* now how can this match the defaultLocale? */
|
||||
/* try with attr() */
|
||||
content: 'EN';
|
||||
vertical-align: super;
|
||||
font-size: 0.75em;
|
||||
font-weight: 700;
|
||||
margin-left: 1ch;
|
||||
}
|
||||
.fallback-badge:after {
|
||||
/* now how can this match the defaultLocale? */
|
||||
/* try with attr() */
|
||||
content: 'EN';
|
||||
vertical-align: super;
|
||||
font-size: 0.75em;
|
||||
font-weight: 700;
|
||||
margin-left: 1ch;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,24 +5,24 @@ import { Icon } from '@astrojs/starlight/components';
|
||||
import semver from 'semver';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Package name
|
||||
*/
|
||||
packageName: string;
|
||||
/**
|
||||
* Slug relative to /src - e.g "/zh-cn/features"
|
||||
*
|
||||
* Note: leading and trailing slashes are dropped "/features/" === "features"
|
||||
*/
|
||||
slug: string;
|
||||
/**
|
||||
* Filter out pages by title - case insensitive
|
||||
*/
|
||||
filterOutByTitle?: string[];
|
||||
/**
|
||||
* Filter out pages by file name - case insensitive
|
||||
*/
|
||||
filterOutByFileName?: string[];
|
||||
/**
|
||||
* Package name
|
||||
*/
|
||||
packageName: string;
|
||||
/**
|
||||
* Slug relative to /src - e.g "/zh-cn/features"
|
||||
*
|
||||
* Note: leading and trailing slashes are dropped "/features/" === "features"
|
||||
*/
|
||||
slug: string;
|
||||
/**
|
||||
* Filter out pages by title - case insensitive
|
||||
*/
|
||||
filterOutByTitle?: string[];
|
||||
/**
|
||||
* Filter out pages by file name - case insensitive
|
||||
*/
|
||||
filterOutByFileName?: string[];
|
||||
}
|
||||
|
||||
let { slug } = Astro.props;
|
||||
@@ -33,11 +33,11 @@ slug = stripLeadingAndTrailingSlashes(slug.toLowerCase());
|
||||
let mainList: Route[] = [];
|
||||
|
||||
routes.forEach((page) => {
|
||||
// `page.slug` is the slug of the current page being looped,
|
||||
// `slug` is this component prop
|
||||
if (page.slug.startsWith(slug + '/')) {
|
||||
mainList.push(page);
|
||||
}
|
||||
// `page.slug` is the slug of the current page being looped,
|
||||
// `slug` is this component prop
|
||||
if (page.slug.startsWith(slug + '/')) {
|
||||
mainList.push(page);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -45,237 +45,237 @@ routes.forEach((page) => {
|
||||
*/
|
||||
|
||||
if (filterOutByTitle.length > 0) {
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByTitle.some((val) => page.entry.data.title.includes(val))
|
||||
);
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByTitle.some((val) => page.entry.data.title.includes(val))
|
||||
);
|
||||
}
|
||||
|
||||
if (filterOutByFileName.length > 0) {
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByFileName.some((val) => page.entry.id.includes(val))
|
||||
);
|
||||
mainList = mainList.filter(
|
||||
(page) => !filterOutByFileName.some((val) => page.entry.id.includes(val))
|
||||
);
|
||||
}
|
||||
|
||||
function sortVersions(a: Route, b: Route): number {
|
||||
const t1 = a.entry.data.title;
|
||||
const t2 = b.entry.data.title;
|
||||
const [package1, version1] = t1.split('@').filter((w) => w.length > 0);
|
||||
const [package2, version2] = t2.split('@').filter((w) => w.length > 0);
|
||||
if (package1 === package2) {
|
||||
return semver.lt(version1, version2) ? -1 : semver.gt(version1, version2) ? 1 : 0;
|
||||
} else {
|
||||
return package1.localeCompare(package2);
|
||||
}
|
||||
const t1 = a.entry.data.title;
|
||||
const t2 = b.entry.data.title;
|
||||
const [package1, version1] = t1.split('@').filter((w) => w.length > 0);
|
||||
const [package2, version2] = t2.split('@').filter((w) => w.length > 0);
|
||||
if (package1 === package2) {
|
||||
return semver.lt(version1, version2) ? -1 : semver.gt(version1, version2) ? 1 : 0;
|
||||
} else {
|
||||
return package1.localeCompare(package2);
|
||||
}
|
||||
}
|
||||
mainList.sort((a, b) => sortVersions(b, a));
|
||||
---
|
||||
|
||||
<div class="parent">
|
||||
<div class="sidenav">
|
||||
<div class="sidenav-title">
|
||||
<p>Changelogs: <br />{packageName}</p>
|
||||
</div>
|
||||
<div class="sidenav-content">
|
||||
{
|
||||
mainList.map((item) => (
|
||||
<>
|
||||
<a href={`/${item.slug}`}> {item.entry.data.description}</a>
|
||||
</>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidenav">
|
||||
<div class="sidenav-title">
|
||||
<p>Changelogs: <br />{packageName}</p>
|
||||
</div>
|
||||
<div class="sidenav-content">
|
||||
{
|
||||
mainList.map((item) => (
|
||||
<>
|
||||
<a href={`/${item.slug}`}> {item.entry.data.description}</a>
|
||||
</>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mobile-release-list>
|
||||
<nav aria-labelledby="mobile-release-list">
|
||||
<details>
|
||||
<summary id="mobile-release-list" class="sl-flex">
|
||||
<div class="toggle sl-flex">
|
||||
Release List:
|
||||
<span class="display-current">{packageName}</span>
|
||||
<Icon name={'right-caret'} class="caret" size="1rem" />
|
||||
</div>
|
||||
</summary>
|
||||
<div class="dropdown">
|
||||
<ul>
|
||||
{
|
||||
mainList.map((item) => (
|
||||
<li>
|
||||
<a href={`/${item.slug}`}> {item.entry.data.description}</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
</nav>
|
||||
<nav aria-labelledby="mobile-release-list">
|
||||
<details>
|
||||
<summary id="mobile-release-list" class="sl-flex">
|
||||
<div class="toggle sl-flex">
|
||||
Release List:
|
||||
<span class="display-current">{packageName}</span>
|
||||
<Icon name={'right-caret'} class="caret" size="1rem" />
|
||||
</div>
|
||||
</summary>
|
||||
<div class="dropdown">
|
||||
<ul>
|
||||
{
|
||||
mainList.map((item) => (
|
||||
<li>
|
||||
<a href={`/${item.slug}`}> {item.entry.data.description}</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
</nav>
|
||||
</mobile-release-list>
|
||||
|
||||
<script>
|
||||
// Taken from starlight's mobile TOC
|
||||
class MobileReleaseList extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const details = this.querySelector('details');
|
||||
if (!details) return;
|
||||
const closeToC = () => {
|
||||
details.open = false;
|
||||
};
|
||||
// Taken from starlight's mobile TOC
|
||||
class MobileReleaseList extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const details = this.querySelector('details');
|
||||
if (!details) return;
|
||||
const closeToC = () => {
|
||||
details.open = false;
|
||||
};
|
||||
|
||||
// Close the table of contents when a user clicks outside of it.
|
||||
window.addEventListener('click', (e) => {
|
||||
if (!details.contains(e.target as Node)) closeToC();
|
||||
});
|
||||
// Or when they press the escape key.
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && details.open) {
|
||||
const hasFocus = details.contains(document.activeElement);
|
||||
closeToC();
|
||||
if (hasFocus) {
|
||||
const summary = details.querySelector('summary');
|
||||
if (summary) summary.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Close the table of contents when a user clicks outside of it.
|
||||
window.addEventListener('click', (e) => {
|
||||
if (!details.contains(e.target as Node)) closeToC();
|
||||
});
|
||||
// Or when they press the escape key.
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && details.open) {
|
||||
const hasFocus = details.contains(document.activeElement);
|
||||
closeToC();
|
||||
if (hasFocus) {
|
||||
const summary = details.querySelector('summary');
|
||||
if (summary) summary.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('mobile-release-list', MobileReleaseList);
|
||||
customElements.define('mobile-release-list', MobileReleaseList);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.parent {
|
||||
position: relative;
|
||||
}
|
||||
:root {
|
||||
--release-navbar-width: 12rem;
|
||||
--sl-content-width: 35rem !important;
|
||||
}
|
||||
.parent {
|
||||
position: relative;
|
||||
}
|
||||
:root {
|
||||
--release-navbar-width: 12rem;
|
||||
--sl-content-width: 35rem !important;
|
||||
}
|
||||
|
||||
.sidenav-title {
|
||||
display: block;
|
||||
padding-block: 0.5rem;
|
||||
text-align: center;
|
||||
background-color: var(--sl-color-gray-5);
|
||||
border: 1px solid var(--sl-color-gray-6);
|
||||
}
|
||||
.sidenav {
|
||||
display: none;
|
||||
width: fit-content;
|
||||
top: 0;
|
||||
right: calc(var(--release-navbar-width) * -1);
|
||||
box-shadow: var(--sl-shadow-md);
|
||||
font-size: var(--sl-text-xs);
|
||||
font-family: var(--__sl-font-mono);
|
||||
background-color: var(--sl-color-bg-sidebar);
|
||||
}
|
||||
.sidenav-title {
|
||||
display: block;
|
||||
padding-block: 0.5rem;
|
||||
text-align: center;
|
||||
background-color: var(--sl-color-gray-5);
|
||||
border: 1px solid var(--sl-color-gray-6);
|
||||
}
|
||||
.sidenav {
|
||||
display: none;
|
||||
width: fit-content;
|
||||
top: 0;
|
||||
right: calc(var(--release-navbar-width) * -1);
|
||||
box-shadow: var(--sl-shadow-md);
|
||||
font-size: var(--sl-text-xs);
|
||||
font-family: var(--__sl-font-mono);
|
||||
background-color: var(--sl-color-bg-sidebar);
|
||||
}
|
||||
|
||||
.sl-markdown-content {
|
||||
margin: auto;
|
||||
background-color: red;
|
||||
}
|
||||
@media (min-width: 72rem) {
|
||||
.sidenav {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
.sl-markdown-content {
|
||||
margin: auto;
|
||||
background-color: red;
|
||||
}
|
||||
@media (min-width: 72rem) {
|
||||
.sidenav {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.sidenav-content {
|
||||
padding-inline: 16px 8px;
|
||||
min-width: fit-content;
|
||||
row-gap: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
.sidenav-content {
|
||||
padding-inline: 16px 8px;
|
||||
min-width: fit-content;
|
||||
row-gap: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
/* Taken from starlight's mobile TOC */
|
||||
nav {
|
||||
width: fit-content;
|
||||
}
|
||||
@media (min-width: 72rem) {
|
||||
nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
/* Mobile */
|
||||
/* Taken from starlight's mobile TOC */
|
||||
nav {
|
||||
width: fit-content;
|
||||
}
|
||||
@media (min-width: 72rem) {
|
||||
nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
summary {
|
||||
padding-bottom: 1rem;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
font-size: var(--sl-text-xs);
|
||||
outline-offset: var(--sl-outline-offset-inside);
|
||||
}
|
||||
summary::marker,
|
||||
summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
summary {
|
||||
padding-bottom: 1rem;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
font-size: var(--sl-text-xs);
|
||||
outline-offset: var(--sl-outline-offset-inside);
|
||||
}
|
||||
summary::marker,
|
||||
summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
z-index: 3;
|
||||
flex-shrink: 0;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border: 1px solid var(--sl-color-gray-5);
|
||||
border-radius: 0.5rem;
|
||||
padding-block: 0.5rem;
|
||||
padding-inline-start: 0.75rem;
|
||||
padding-inline-end: 0.5rem;
|
||||
background-color: var(--sl-color-gray-6);
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
details[open] .toggle {
|
||||
color: var(--sl-color-white);
|
||||
border-color: var(--sl-color-accent);
|
||||
}
|
||||
details .toggle:hover {
|
||||
color: var(--sl-color-white);
|
||||
border-color: var(--sl-color-gray-2);
|
||||
}
|
||||
details[open] .caret {
|
||||
transform: rotateZ(90deg);
|
||||
}
|
||||
.display-current {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: var(--sl-color-white);
|
||||
}
|
||||
.dropdown {
|
||||
--border: 1px;
|
||||
z-index: 2;
|
||||
row-gap: 1em;
|
||||
position: absolute;
|
||||
border-top-left-radius: 0.5rem;
|
||||
padding-inline: 0.75rem;
|
||||
padding-top: 1em;
|
||||
margin-top: -1em !important;
|
||||
border: var(--border) solid var(--sl-color-gray-5);
|
||||
max-height: calc(85vh - var(--sl-nav-height) - var(--sl-mobile-toc-height));
|
||||
overflow-y: auto;
|
||||
background-color: var(--sl-color-black);
|
||||
box-shadow: var(--sl-shadow-md);
|
||||
overscroll-behavior: contain;
|
||||
background-color: var(--sl-color-bg-sidebar);
|
||||
}
|
||||
.toggle {
|
||||
z-index: 3;
|
||||
flex-shrink: 0;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border: 1px solid var(--sl-color-gray-5);
|
||||
border-radius: 0.5rem;
|
||||
padding-block: 0.5rem;
|
||||
padding-inline-start: 0.75rem;
|
||||
padding-inline-end: 0.5rem;
|
||||
background-color: var(--sl-color-gray-6);
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
details[open] .toggle {
|
||||
color: var(--sl-color-white);
|
||||
border-color: var(--sl-color-accent);
|
||||
}
|
||||
details .toggle:hover {
|
||||
color: var(--sl-color-white);
|
||||
border-color: var(--sl-color-gray-2);
|
||||
}
|
||||
details[open] .caret {
|
||||
transform: rotateZ(90deg);
|
||||
}
|
||||
.display-current {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
color: var(--sl-color-white);
|
||||
}
|
||||
.dropdown {
|
||||
--border: 1px;
|
||||
z-index: 2;
|
||||
row-gap: 1em;
|
||||
position: absolute;
|
||||
border-top-left-radius: 0.5rem;
|
||||
padding-inline: 0.75rem;
|
||||
padding-top: 1em;
|
||||
margin-top: -1em !important;
|
||||
border: var(--border) solid var(--sl-color-gray-5);
|
||||
max-height: calc(85vh - var(--sl-nav-height) - var(--sl-mobile-toc-height));
|
||||
overflow-y: auto;
|
||||
background-color: var(--sl-color-black);
|
||||
box-shadow: var(--sl-shadow-md);
|
||||
overscroll-behavior: contain;
|
||||
background-color: var(--sl-color-bg-sidebar);
|
||||
}
|
||||
|
||||
ul {
|
||||
all: unset;
|
||||
list-style: none;
|
||||
}
|
||||
li {
|
||||
all: unset;
|
||||
}
|
||||
a {
|
||||
display: block;
|
||||
padding-block: 0.5rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
ul {
|
||||
all: unset;
|
||||
list-style: none;
|
||||
}
|
||||
li {
|
||||
all: unset;
|
||||
}
|
||||
a {
|
||||
display: block;
|
||||
padding-block: 0.5rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,13 +11,13 @@ const year = new Date().getFullYear();
|
||||
<p>© {year} Tauri Contributors. CC-BY / MIT</p>
|
||||
|
||||
<style>
|
||||
p {
|
||||
text-align: center;
|
||||
color: var(--sl-color-gray-2);
|
||||
font-size: var(--sl-text-sm);
|
||||
}
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid var(--sl-color-hairline);
|
||||
}
|
||||
p {
|
||||
text-align: center;
|
||||
color: var(--sl-color-gray-2);
|
||||
font-size: var(--sl-text-sm);
|
||||
}
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid var(--sl-color-hairline);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,96 +6,96 @@ const { labels } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="page sl-flex">
|
||||
<header class="header"><slot name="header" /></header>
|
||||
<nav class="sidebar" aria-label={labels['sidebarNav.accessibleLabel']}>
|
||||
<MobileMenuToggle {...Astro.props} />
|
||||
<div
|
||||
id="starlight__sidebar"
|
||||
class={Astro.props.entry.slug === '' || Astro.props.locale === Astro.props.entry.slug
|
||||
? 'sidebar-pane lp-hide'
|
||||
: 'sidebar-pane'}
|
||||
>
|
||||
<div class="sidebar-content sl-flex">
|
||||
<Sidebar {...Astro.props} />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="main-frame"><slot /></div>
|
||||
<header class="header"><slot name="header" /></header>
|
||||
<nav class="sidebar" aria-label={labels['sidebarNav.accessibleLabel']}>
|
||||
<MobileMenuToggle {...Astro.props} />
|
||||
<div
|
||||
id="starlight__sidebar"
|
||||
class={Astro.props.entry.slug === '' || Astro.props.locale === Astro.props.entry.slug
|
||||
? 'sidebar-pane lp-hide'
|
||||
: 'sidebar-pane'}
|
||||
>
|
||||
<div class="sidebar-content sl-flex">
|
||||
<Sidebar {...Astro.props} />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="main-frame"><slot /></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.page {
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.page {
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
@media (min-width: 50rem) {
|
||||
.lp-hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (min-width: 50rem) {
|
||||
.lp-hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
z-index: var(--sl-z-index-navbar);
|
||||
position: fixed;
|
||||
inset-inline-start: 0;
|
||||
inset-block-start: 0;
|
||||
width: 100%;
|
||||
height: var(--sl-nav-height);
|
||||
border-bottom: 1px solid var(--sl-color-hairline-shade);
|
||||
padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
|
||||
padding-inline-end: var(--sl-nav-pad-x);
|
||||
background-color: var(--sl-color-bg-nav);
|
||||
}
|
||||
.header {
|
||||
z-index: var(--sl-z-index-navbar);
|
||||
position: fixed;
|
||||
inset-inline-start: 0;
|
||||
inset-block-start: 0;
|
||||
width: 100%;
|
||||
height: var(--sl-nav-height);
|
||||
border-bottom: 1px solid var(--sl-color-hairline-shade);
|
||||
padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
|
||||
padding-inline-end: var(--sl-nav-pad-x);
|
||||
background-color: var(--sl-color-bg-nav);
|
||||
}
|
||||
|
||||
:global([data-has-sidebar]) .header {
|
||||
padding-inline-end: calc(var(--sl-nav-gap) + var(--sl-nav-pad-x) + var(--sl-menu-button-size));
|
||||
}
|
||||
:global([data-has-sidebar]) .header {
|
||||
padding-inline-end: calc(var(--sl-nav-gap) + var(--sl-nav-pad-x) + var(--sl-menu-button-size));
|
||||
}
|
||||
|
||||
.sidebar-pane {
|
||||
visibility: var(--sl-sidebar-visibility, hidden);
|
||||
position: fixed;
|
||||
z-index: var(--sl-z-index-menu);
|
||||
inset-block: var(--sl-nav-height) 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
background-color: var(--sl-color-black);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.sidebar-pane {
|
||||
visibility: var(--sl-sidebar-visibility, hidden);
|
||||
position: fixed;
|
||||
z-index: var(--sl-z-index-menu);
|
||||
inset-block: var(--sl-nav-height) 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
background-color: var(--sl-color-black);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
:global([aria-expanded='true']) ~ .sidebar-pane {
|
||||
--sl-sidebar-visibility: visible;
|
||||
}
|
||||
:global([aria-expanded='true']) ~ .sidebar-pane {
|
||||
--sl-sidebar-visibility: visible;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
height: 100%;
|
||||
min-height: max-content;
|
||||
padding: 1rem var(--sl-sidebar-pad-x) 0;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
.sidebar-content {
|
||||
height: 100%;
|
||||
min-height: max-content;
|
||||
padding: 1rem var(--sl-sidebar-pad-x) 0;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 50rem) {
|
||||
.sidebar-content::after {
|
||||
content: '';
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 50rem) {
|
||||
.sidebar-content::after {
|
||||
content: '';
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.main-frame {
|
||||
padding-top: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height));
|
||||
padding-inline-start: var(--sl-content-inline-start);
|
||||
}
|
||||
.main-frame {
|
||||
padding-top: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height));
|
||||
padding-inline-start: var(--sl-content-inline-start);
|
||||
}
|
||||
|
||||
@media (min-width: 50rem) {
|
||||
:global([data-has-sidebar]) .header {
|
||||
padding-inline-end: var(--sl-nav-pad-x);
|
||||
}
|
||||
.sidebar-pane {
|
||||
--sl-sidebar-visibility: visible;
|
||||
width: var(--sl-sidebar-width);
|
||||
background-color: var(--sl-color-bg-sidebar);
|
||||
border-inline-end: 1px solid var(--sl-color-hairline-shade);
|
||||
}
|
||||
}
|
||||
@media (min-width: 50rem) {
|
||||
:global([data-has-sidebar]) .header {
|
||||
padding-inline-end: var(--sl-nav-pad-x);
|
||||
}
|
||||
.sidebar-pane {
|
||||
--sl-sidebar-visibility: visible;
|
||||
width: var(--sl-sidebar-width);
|
||||
background-color: var(--sl-color-bg-sidebar);
|
||||
border-inline-end: 1px solid var(--sl-color-hairline-shade);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,107 +12,107 @@ import { AstroError } from 'astro/errors';
|
||||
// 2. Create a new derived set of `Astro.props` that only contains one set of sidebar entries
|
||||
// 3. Check if the current page being rendered is current page to determine if this sidebar group should be selected
|
||||
const multiSidebarConfig: [string, boolean, Props][] = Astro.props.sidebar.map((entry) => {
|
||||
if (entry.type !== 'group') {
|
||||
throw new AstroError(
|
||||
`\`${entry.label}\` cannot be used with multiple Starlight sidebars.
|
||||
if (entry.type !== 'group') {
|
||||
throw new AstroError(
|
||||
`\`${entry.label}\` cannot be used with multiple Starlight sidebars.
|
||||
|
||||
Each top-level \`sidebar\` item in the Starlight config must be either a group or autogenerated.
|
||||
|
||||
See https://starlight.astro.build/guides/sidebar/#groups and https://starlight.astro.build/guides/sidebar/#autogenerated-groups`
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Recursively check if a group of sidebar entries contains the current page
|
||||
const findIfIsCurrent = (entry: (typeof Astro.props.sidebar)[number]): boolean => {
|
||||
if (entry.type === 'link') {
|
||||
return entry.isCurrent;
|
||||
}
|
||||
return entry.entries.some((item) => findIfIsCurrent(item));
|
||||
};
|
||||
// Recursively check if a group of sidebar entries contains the current page
|
||||
const findIfIsCurrent = (entry: (typeof Astro.props.sidebar)[number]): boolean => {
|
||||
if (entry.type === 'link') {
|
||||
return entry.isCurrent;
|
||||
}
|
||||
return entry.entries.some((item) => findIfIsCurrent(item));
|
||||
};
|
||||
|
||||
const isCurrentPage = findIfIsCurrent(entry);
|
||||
const isCurrentPage = findIfIsCurrent(entry);
|
||||
|
||||
return [entry.label, isCurrentPage, { ...Astro.props, sidebar: [...entry.entries] }];
|
||||
return [entry.label, isCurrentPage, { ...Astro.props, sidebar: [...entry.entries] }];
|
||||
});
|
||||
let foundCurrentPage = false;
|
||||
for (const page of multiSidebarConfig) {
|
||||
if (page[1]) {
|
||||
foundCurrentPage = true;
|
||||
break;
|
||||
}
|
||||
if (page[1]) {
|
||||
foundCurrentPage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundCurrentPage && multiSidebarConfig.length > 0) {
|
||||
multiSidebarConfig[0][1] = true;
|
||||
multiSidebarConfig[0][1] = true;
|
||||
}
|
||||
if (!multiSidebarConfig.some(([_label, isCurrentPage, _config]) => isCurrentPage)) {
|
||||
multiSidebarConfig[0][1] = true;
|
||||
multiSidebarConfig[0][1] = true;
|
||||
}
|
||||
---
|
||||
|
||||
<div class="__collapse">
|
||||
{
|
||||
multiSidebarConfig.map(([label, isCurrentPage, config]) => (
|
||||
<>
|
||||
<input type="radio" name="sidebar" role="tab" aria-label={label} checked={isCurrentPage} />
|
||||
<div class="__collapse-content">
|
||||
<Default {...config}>
|
||||
<slot />
|
||||
</Default>
|
||||
</div>
|
||||
</>
|
||||
))
|
||||
}
|
||||
{
|
||||
multiSidebarConfig.map(([label, isCurrentPage, config]) => (
|
||||
<>
|
||||
<input type="radio" name="sidebar" role="tab" aria-label={label} checked={isCurrentPage} />
|
||||
<div class="__collapse-content">
|
||||
<Default {...config}>
|
||||
<slot />
|
||||
</Default>
|
||||
</div>
|
||||
</>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<style>
|
||||
.__collapse {
|
||||
display: grid;
|
||||
}
|
||||
.__collapse > input {
|
||||
/* Layout */
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
grid-row-start: 1;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
min-height: fit-content;
|
||||
.__collapse {
|
||||
display: grid;
|
||||
}
|
||||
.__collapse > input {
|
||||
/* Layout */
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
grid-row-start: 1;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
min-height: fit-content;
|
||||
|
||||
/* Styles */
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.2em 0.5rem;
|
||||
line-height: 1.4;
|
||||
font-size: var(--sl-text-lg);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
margin-bottom: var(--sl-nav-pad-y);
|
||||
}
|
||||
/* Styles */
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.2em 0.5rem;
|
||||
line-height: 1.4;
|
||||
font-size: var(--sl-text-lg);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
margin-bottom: var(--sl-nav-pad-y);
|
||||
}
|
||||
|
||||
.__collapse > input::after {
|
||||
content: attr(aria-label);
|
||||
}
|
||||
.__collapse > input::after {
|
||||
content: attr(aria-label);
|
||||
}
|
||||
|
||||
.__collapse > input:checked {
|
||||
color: var(--sl-color-text-invert);
|
||||
background-color: var(--sl-color-text-accent);
|
||||
}
|
||||
.__collapse > input:checked {
|
||||
color: var(--sl-color-text-invert);
|
||||
background-color: var(--sl-color-text-accent);
|
||||
}
|
||||
|
||||
.__collapse > .__collapse-content {
|
||||
display: none;
|
||||
grid-column-start: 1;
|
||||
grid-column-end: span 999;
|
||||
grid-row-start: 2;
|
||||
border-top: 1px solid var(--sl-color-gray-5);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
.__collapse > input:checked + .__collapse-content {
|
||||
display: block;
|
||||
}
|
||||
.__collapse > .__collapse-content {
|
||||
display: none;
|
||||
grid-column-start: 1;
|
||||
grid-column-end: span 999;
|
||||
grid-row-start: 2;
|
||||
border-top: 1px solid var(--sl-color-gray-5);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
.__collapse > input:checked + .__collapse-content {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<style is:global>
|
||||
.top-level {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.sidebar-pane {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.top-level {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.sidebar-pane {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,150 +10,150 @@ import { Icon } from '@astrojs/starlight/components';
|
||||
const curLocale = Astro.props.locale;
|
||||
|
||||
type Link = {
|
||||
title: string;
|
||||
value: string;
|
||||
transfer: boolean;
|
||||
title: string;
|
||||
value: string;
|
||||
transfer: boolean;
|
||||
};
|
||||
|
||||
const links: Link[] = [
|
||||
{
|
||||
title: 'Guides',
|
||||
value: '/start/',
|
||||
transfer: true,
|
||||
},
|
||||
{
|
||||
title: 'References',
|
||||
value: '/reference/acl/',
|
||||
transfer: true,
|
||||
},
|
||||
{
|
||||
title: 'Blog',
|
||||
value: '/blog',
|
||||
transfer: false,
|
||||
},
|
||||
{
|
||||
title: 'Releases',
|
||||
value: '/release/',
|
||||
transfer: true,
|
||||
},
|
||||
{
|
||||
title: 'Guides',
|
||||
value: '/start/',
|
||||
transfer: true,
|
||||
},
|
||||
{
|
||||
title: 'References',
|
||||
value: '/reference/acl/',
|
||||
transfer: true,
|
||||
},
|
||||
{
|
||||
title: 'Blog',
|
||||
value: '/blog',
|
||||
transfer: false,
|
||||
},
|
||||
{
|
||||
title: 'Releases',
|
||||
value: '/release/',
|
||||
transfer: true,
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<>
|
||||
<Default {...Astro.props}><slot /></Default>
|
||||
<Default {...Astro.props}><slot /></Default>
|
||||
|
||||
<starlight-select class="mobile">
|
||||
<label>
|
||||
<select aria-label="Menu">
|
||||
<option value="" disabled selected>Menu</option>
|
||||
{
|
||||
links.map((link) => (
|
||||
<option
|
||||
value={link.transfer && curLocale ? `/${curLocale}${link.value}` : link.value}
|
||||
set:html={link.title}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
<Icon name="down-caret" class="icon caret" />
|
||||
</label>
|
||||
</starlight-select>
|
||||
<starlight-select class="mobile">
|
||||
<label>
|
||||
<select aria-label="Menu">
|
||||
<option value="" disabled selected>Menu</option>
|
||||
{
|
||||
links.map((link) => (
|
||||
<option
|
||||
value={link.transfer && curLocale ? `/${curLocale}${link.value}` : link.value}
|
||||
set:html={link.title}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
<Icon name="down-caret" class="icon caret" />
|
||||
</label>
|
||||
</starlight-select>
|
||||
</>
|
||||
|
||||
<script>
|
||||
class StarlightLanguageSelect extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const select = this.querySelector('select');
|
||||
if (select) {
|
||||
select.addEventListener('change', (e) => {
|
||||
if (e.currentTarget instanceof HTMLSelectElement) {
|
||||
window.location.pathname = e.currentTarget.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define('starlight-select', StarlightLanguageSelect);
|
||||
class StarlightLanguageSelect extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
const select = this.querySelector('select');
|
||||
if (select) {
|
||||
select.addEventListener('change', (e) => {
|
||||
if (e.currentTarget instanceof HTMLSelectElement) {
|
||||
window.location.pathname = e.currentTarget.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define('starlight-select', StarlightLanguageSelect);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.desktop {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding-inline-start: 1rem;
|
||||
}
|
||||
@media (min-width: 72rem) {
|
||||
.desktop {
|
||||
display: flex;
|
||||
}
|
||||
.mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.desktop {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding-inline-start: 1rem;
|
||||
}
|
||||
@media (min-width: 72rem) {
|
||||
.desktop {
|
||||
display: flex;
|
||||
}
|
||||
.mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--sl-color-white);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
a {
|
||||
color: var(--sl-color-white);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* From https://github.com/withastro/starlight/blob/main/packages/starlight/components/Select.astro */
|
||||
label {
|
||||
--sl-label-icon-size: 0.875rem;
|
||||
--sl-caret-size: 1.25rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: var(--sl-color-gray-1);
|
||||
}
|
||||
/* From https://github.com/withastro/starlight/blob/main/packages/starlight/components/Select.astro */
|
||||
label {
|
||||
--sl-label-icon-size: 0.875rem;
|
||||
--sl-caret-size: 1.25rem;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
color: var(--sl-color-gray-1);
|
||||
}
|
||||
|
||||
label:hover {
|
||||
color: var(--sl-color-gray-2);
|
||||
}
|
||||
label:hover {
|
||||
color: var(--sl-color-gray-2);
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.label-icon {
|
||||
font-size: var(--sl-label-icon-size);
|
||||
inset-inline-start: 0;
|
||||
}
|
||||
.label-icon {
|
||||
font-size: var(--sl-label-icon-size);
|
||||
inset-inline-start: 0;
|
||||
}
|
||||
|
||||
.caret {
|
||||
font-size: var(--sl-caret-size);
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
.caret {
|
||||
font-size: var(--sl-caret-size);
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
|
||||
select {
|
||||
border: 0;
|
||||
padding-block: 0.625rem;
|
||||
padding-inline: calc(var(--sl-label-icon-size) + 0.25rem) calc(var(--sl-caret-size) + 0.25rem);
|
||||
width: var(--sl-select-width);
|
||||
background-color: transparent;
|
||||
text-overflow: ellipsis;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
}
|
||||
select {
|
||||
border: 0;
|
||||
padding-block: 0.625rem;
|
||||
padding-inline: calc(var(--sl-label-icon-size) + 0.25rem) calc(var(--sl-caret-size) + 0.25rem);
|
||||
width: var(--sl-select-width);
|
||||
background-color: transparent;
|
||||
text-overflow: ellipsis;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: var(--sl-color-bg-nav);
|
||||
color: var(--sl-color-gray-1);
|
||||
}
|
||||
option {
|
||||
background-color: var(--sl-color-bg-nav);
|
||||
color: var(--sl-color-gray-1);
|
||||
}
|
||||
|
||||
@media (min-width: 50rem) {
|
||||
select {
|
||||
font-size: var(--sl-text-sm);
|
||||
}
|
||||
}
|
||||
starlight-select {
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (min-width: 50rem) {
|
||||
select {
|
||||
font-size: var(--sl-text-sm);
|
||||
}
|
||||
}
|
||||
starlight-select {
|
||||
margin-left: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,6 +3,6 @@ import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
|
||||
import { blogSchema } from 'starlight-blog/schema';
|
||||
|
||||
export const collections = {
|
||||
docs: defineCollection({ schema: docsSchema({ extend: blogSchema() }) }),
|
||||
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
|
||||
docs: defineCollection({ schema: docsSchema({ extend: blogSchema() }) }),
|
||||
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
|
||||
};
|
||||
|
||||
@@ -11,19 +11,19 @@ If you're looking for a quick technical overview and to start building an app th
|
||||
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard
|
||||
title="Tauri Philosophy"
|
||||
href="/about/philosophy"
|
||||
description="Learn more about the approach behind Tauri"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Governance"
|
||||
href="/about/governance"
|
||||
description="Understand how the Tauri governance structure is setup"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Trademark"
|
||||
href="/about/trademark"
|
||||
description="Guidelines for using the Tauri trademark"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Tauri Philosophy"
|
||||
href="/about/philosophy"
|
||||
description="Learn more about the approach behind Tauri"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Governance"
|
||||
href="/about/governance"
|
||||
description="Understand how the Tauri governance structure is setup"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Trademark"
|
||||
href="/about/trademark"
|
||||
description="Guidelines for using the Tauri trademark"
|
||||
/>
|
||||
</CardGrid>
|
||||
|
||||
@@ -18,10 +18,10 @@ After 113 pull requests and nearly two months of work, the Tauri team is pleased
|
||||
You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
/>
|
||||
|
||||
## What's New in 1.1.0
|
||||
@@ -79,20 +79,20 @@ In the 1.0 releases Tauri supports the `JSON` configuration format by default, a
|
||||
|
||||
```json title=tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"devPath": "http://localhost:8000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"devPath": "http://localhost:8000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json5
|
||||
{
|
||||
build: {
|
||||
// devServer URL (comments are allowed!)
|
||||
devPath: 'http://localhost:8000',
|
||||
distDir: '../dist',
|
||||
},
|
||||
build: {
|
||||
// devServer URL (comments are allowed!)
|
||||
devPath: 'http://localhost:8000',
|
||||
distDir: '../dist',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ The Tauri team is happy to announce the 1.2.0 release. It includes a security fi
|
||||
Make sure to update both NPM and Cargo dependencies to the 1.2.0 release. You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
/>
|
||||
|
||||
## What's in 1.2.0
|
||||
|
||||
@@ -20,10 +20,10 @@ The Tauri team is excited to announce the 1.3 release. This version includes sec
|
||||
Make sure to update both NPM and Cargo dependencies to the 1.3.0 release. You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
/>
|
||||
|
||||
## What's in 1.3.0
|
||||
|
||||
@@ -20,10 +20,10 @@ The Tauri team is excited to announce the 1.4 release. This version includes sev
|
||||
Make sure to update both NPM and Cargo dependencies to the 1.4.0 release. You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
/>
|
||||
|
||||
## What's in 1.4.0
|
||||
|
||||
@@ -20,10 +20,10 @@ The Tauri team is excited to announce the 1.5 release. This version includes sev
|
||||
Make sure to update both NPM and Cargo dependencies to the 1.5.0 release. You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
/>
|
||||
|
||||
## What's in 1.5.0
|
||||
|
||||
@@ -18,10 +18,10 @@ The Tauri team is happy to announce the 1.6 release. This version includes sever
|
||||
Make sure to update both NPM and Cargo dependencies to the 1.6.0 release. You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn upgrade @tauri-apps/cli @tauri-apps/api --latest"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
cargo="cargo update"
|
||||
/>
|
||||
|
||||
## What's in 1.6.0
|
||||
|
||||
@@ -20,10 +20,10 @@ A new alpha release for the 2.0 has been published. This release includes all ch
|
||||
Make sure to update both NPM and Cargo dependencies to the latest alpha release. You can update the NPM dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
yarn="yarn upgrade @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
pnpm="pnpm update @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
cargo='cargo add tauri@2.0.0-alpha.4
|
||||
npm="npm install @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
yarn="yarn upgrade @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
pnpm="pnpm update @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
cargo='cargo add tauri@2.0.0-alpha.4
|
||||
cargo add tauri-build@2.0.0-alpha.2 --build
|
||||
cargo install tauri-cli --version "^2.0.0-alpha"'
|
||||
/>
|
||||
@@ -120,7 +120,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
```js
|
||||
import { invoke } from '@tauri-apps/api/tauri';
|
||||
invoke('plugin:example|ping', { value: 'Tauri' }).then(({ value }) =>
|
||||
console.log('Response', value)
|
||||
console.log('Response', value)
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ Tauri mobile is here! The first alpha release 2.0.0-alpha.0 has been published.
|
||||
Make sure to update both NPM and Cargo dependencies to the 2.0.0-alpha.0 release. You can update the dependencies with:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
yarn="yarn upgrade @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
pnpm="pnpm update @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
cargo='cargo add tauri@2.0.0-alpha.0
|
||||
npm="npm install @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
yarn="yarn upgrade @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
pnpm="pnpm update @tauri-apps/cli@next @tauri-apps/api@next"
|
||||
cargo='cargo add tauri@2.0.0-alpha.0
|
||||
cargo add tauri-build@2.0.0-alpha.0 --build
|
||||
cargo install tauri-cli --version "^2.0.0-alpha"'
|
||||
/>
|
||||
|
||||
@@ -15,14 +15,14 @@ Inter-Process Communication (IPC) allows isolated processes to communicate secur
|
||||
Learn more above the specific IPC patterns in the following guides:
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard
|
||||
title="Brownfield"
|
||||
href="/concept/inter-process-communication/brownfield/"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Isolation"
|
||||
href="/concept/inter-process-communication/isolation/"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Brownfield"
|
||||
href="/concept/inter-process-communication/brownfield/"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Isolation"
|
||||
href="/concept/inter-process-communication/isolation/"
|
||||
/>
|
||||
</CardGrid>
|
||||
|
||||
Tauri uses a particular style of Inter-Process Communication called [Asynchronous Message Passing], where processes exchange _requests_ and _responses_ serialized using some simple data representation. Message Passing should sound familiar to anyone with web development experience, as this paradigm is used for client-server communication on the internet.
|
||||
|
||||
@@ -7,49 +7,49 @@ import Rater from '@theme/Rater';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Bridge.svg')} alt="Bridge" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Highly configurable</li>
|
||||
<li>No Rust skills required</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Some WebAPIs unavailable</li>
|
||||
<li>Challenge to implement</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Bridge.svg')} alt="Bridge" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Highly configurable</li>
|
||||
<li>No Rust skills required</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Some WebAPIs unavailable</li>
|
||||
<li>Challenge to implement</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
@@ -93,97 +93,97 @@ Here's what you need to add to your tauri.conf.json file:
|
||||
|
||||
```json
|
||||
{
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": false,
|
||||
"clipboard": {
|
||||
"all": false,
|
||||
"readText": false,
|
||||
"writeText": false
|
||||
},
|
||||
"dialog": {
|
||||
"all": false,
|
||||
"ask": false,
|
||||
"confirm": false,
|
||||
"message": false,
|
||||
"open": false,
|
||||
"save": false
|
||||
},
|
||||
"fs": {
|
||||
"all": false,
|
||||
"copyFile": false,
|
||||
"createDir": false,
|
||||
"readDir": false,
|
||||
"readFile": false,
|
||||
"removeDir": false,
|
||||
"removeFile": false,
|
||||
"renameFile": false,
|
||||
"scope": [],
|
||||
"writeFile": false
|
||||
},
|
||||
"globalShortcut": {
|
||||
"all": false
|
||||
},
|
||||
"http": {
|
||||
"all": false,
|
||||
"request": false,
|
||||
"scope": []
|
||||
},
|
||||
"notification": {
|
||||
"all": false
|
||||
},
|
||||
"os": {
|
||||
"all": false
|
||||
},
|
||||
"path": {
|
||||
"all": false
|
||||
},
|
||||
"process": {
|
||||
"all": false,
|
||||
"exit": false,
|
||||
"relaunch": false,
|
||||
"relaunchDangerousAllowSymlinkMacos": false
|
||||
},
|
||||
"protocol": {
|
||||
"all": false,
|
||||
"asset": false,
|
||||
"assetScope": []
|
||||
},
|
||||
"shell": {
|
||||
"all": false,
|
||||
"execute": false,
|
||||
"open": false,
|
||||
"scope": [],
|
||||
"sidecar": false
|
||||
},
|
||||
"window": {
|
||||
"all": false,
|
||||
"center": false,
|
||||
"close": false,
|
||||
"create": false,
|
||||
"hide": false,
|
||||
"maximize": false,
|
||||
"minimize": false,
|
||||
"print": false,
|
||||
"requestUserAttention": false,
|
||||
"setAlwaysOnTop": false,
|
||||
"setDecorations": false,
|
||||
"setFocus": false,
|
||||
"setFullscreen": false,
|
||||
"setIcon": false,
|
||||
"setMaxSize": false,
|
||||
"setMinSize": false,
|
||||
"setPosition": false,
|
||||
"setResizable": false,
|
||||
"setSize": false,
|
||||
"setSkipTaskbar": false,
|
||||
"setTitle": false,
|
||||
"show": false,
|
||||
"startDragging": false,
|
||||
"unmaximize": false,
|
||||
"unminimize": false
|
||||
}
|
||||
}
|
||||
}
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": false,
|
||||
"clipboard": {
|
||||
"all": false,
|
||||
"readText": false,
|
||||
"writeText": false
|
||||
},
|
||||
"dialog": {
|
||||
"all": false,
|
||||
"ask": false,
|
||||
"confirm": false,
|
||||
"message": false,
|
||||
"open": false,
|
||||
"save": false
|
||||
},
|
||||
"fs": {
|
||||
"all": false,
|
||||
"copyFile": false,
|
||||
"createDir": false,
|
||||
"readDir": false,
|
||||
"readFile": false,
|
||||
"removeDir": false,
|
||||
"removeFile": false,
|
||||
"renameFile": false,
|
||||
"scope": [],
|
||||
"writeFile": false
|
||||
},
|
||||
"globalShortcut": {
|
||||
"all": false
|
||||
},
|
||||
"http": {
|
||||
"all": false,
|
||||
"request": false,
|
||||
"scope": []
|
||||
},
|
||||
"notification": {
|
||||
"all": false
|
||||
},
|
||||
"os": {
|
||||
"all": false
|
||||
},
|
||||
"path": {
|
||||
"all": false
|
||||
},
|
||||
"process": {
|
||||
"all": false,
|
||||
"exit": false,
|
||||
"relaunch": false,
|
||||
"relaunchDangerousAllowSymlinkMacos": false
|
||||
},
|
||||
"protocol": {
|
||||
"all": false,
|
||||
"asset": false,
|
||||
"assetScope": []
|
||||
},
|
||||
"shell": {
|
||||
"all": false,
|
||||
"execute": false,
|
||||
"open": false,
|
||||
"scope": [],
|
||||
"sidecar": false
|
||||
},
|
||||
"window": {
|
||||
"all": false,
|
||||
"center": false,
|
||||
"close": false,
|
||||
"create": false,
|
||||
"hide": false,
|
||||
"maximize": false,
|
||||
"minimize": false,
|
||||
"print": false,
|
||||
"requestUserAttention": false,
|
||||
"setAlwaysOnTop": false,
|
||||
"setDecorations": false,
|
||||
"setFocus": false,
|
||||
"setFullscreen": false,
|
||||
"setIcon": false,
|
||||
"setMaxSize": false,
|
||||
"setMinSize": false,
|
||||
"setPosition": false,
|
||||
"setResizable": false,
|
||||
"setSize": false,
|
||||
"setSkipTaskbar": false,
|
||||
"setTitle": false,
|
||||
"show": false,
|
||||
"startDragging": false,
|
||||
"unmaximize": false,
|
||||
"unminimize": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -7,49 +7,49 @@ import Rater from '@theme/Rater';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="2" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Cloudbridge.svg')} alt="Cloudbridge" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>All available features</li>
|
||||
<li>No Rust skills required</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Largest bundle size</li>
|
||||
<li>Hard to separate concerns</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="1" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="2" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Cloudbridge.svg')} alt="Cloudbridge" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>All available features</li>
|
||||
<li>No Rust skills required</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Largest bundle size</li>
|
||||
<li>Hard to separate concerns</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
@@ -7,49 +7,49 @@ import Rater from '@theme/Rater';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="2" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Cloudish.svg')} alt="Cloudish" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Similar to a SPA web-app</li>
|
||||
<li>No Rust skills required</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>No access to Rust API</li>
|
||||
<li>Uses a localhost server</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="2" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Cloudish.svg')} alt="Cloudish" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Similar to a SPA web-app</li>
|
||||
<li>No Rust skills required</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>No access to Rust API</li>
|
||||
<li>Uses a localhost server</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
@@ -12,48 +12,48 @@ This pattern is not available for now.
|
||||
import Rater from '@theme/Rater';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/GLUI.svg')} alt="GLUI" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Framebuffer FTW</li>
|
||||
<li>Window events rigged</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Broken on your machine</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/GLUI.svg')} alt="GLUI" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Framebuffer FTW</li>
|
||||
<li>Window events rigged</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Broken on your machine</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
@@ -7,49 +7,49 @@ import Rater from '@theme/Rater';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Hermit.svg')} alt="Hermit" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Quick to make</li>
|
||||
<li>Smallest size</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>No remote resources</li>
|
||||
<li>No access to API</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="0" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Hermit.svg')} alt="Hermit" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Quick to make</li>
|
||||
<li>Smallest size</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>No remote resources</li>
|
||||
<li>No access to API</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
@@ -7,49 +7,49 @@ import Rater from '@theme/Rater';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="2" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Lockdown.svg')} alt="Lockdown" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Highest security rating</li>
|
||||
<li>Elegant and powerful</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Rust skills required</li>
|
||||
<li>No remote resources</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="2" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Lockdown.svg')} alt="Lockdown" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Highest security rating</li>
|
||||
<li>Elegant and powerful</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Rust skills required</li>
|
||||
<li>No remote resources</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
@@ -7,48 +7,48 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import Rater from '@theme/Rater';
|
||||
|
||||
<div className="row">
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Multiwin.svg')} alt="Multiwin" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Windows can be spawned or destroyed at runtime</li>
|
||||
<li>Separation of concerns</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Somewhat complex</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Ease of Use</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Extensibility</td>
|
||||
<td>
|
||||
<Rater value="4" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Performance</td>
|
||||
<td>
|
||||
<Rater value="3" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Security</td>
|
||||
<td>
|
||||
<Rater value="5" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div className="col col--4 pattern-logo">
|
||||
<img src={useBaseUrl('img/recipes/Multiwin.svg')} alt="Multiwin" />
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
Pros:
|
||||
<ul>
|
||||
<li>Windows can be spawned or destroyed at runtime</li>
|
||||
<li>Separation of concerns</li>
|
||||
</ul>
|
||||
Cons:
|
||||
<ul>
|
||||
<li>Somewhat complex</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
@@ -13,34 +13,34 @@ import { CardGrid, LinkCard } from '@astrojs/starlight/components';
|
||||
Tauri has a variety of topics that are considered to be core concepts, things any developer should be aware of when developing their applications. Here's a variety of topics that you should get more intimately familiar with if you want to get the most out of the framework.
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard
|
||||
title="Tauri Architecture"
|
||||
href="/concept/architecture/"
|
||||
description="Architecture and ecosystem."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Inter-Process Communication (IPC)"
|
||||
href="/concept/inter-process-communication/"
|
||||
description="The inner workings on the IPC."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Security"
|
||||
href="/security"
|
||||
description="How Tauri enforces security practices."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Process Model"
|
||||
href="/concept/process-model/"
|
||||
description="Which processes Tauri manages and why."
|
||||
/>
|
||||
<LinkCard
|
||||
title="App Size"
|
||||
href="/concept/size/"
|
||||
description="How to make your app as small as possible."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Rendering"
|
||||
href="/concept/rendering/"
|
||||
description="What a renderer is in Tauri."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Tauri Architecture"
|
||||
href="/concept/architecture/"
|
||||
description="Architecture and ecosystem."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Inter-Process Communication (IPC)"
|
||||
href="/concept/inter-process-communication/"
|
||||
description="The inner workings on the IPC."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Security"
|
||||
href="/security"
|
||||
description="How Tauri enforces security practices."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Process Model"
|
||||
href="/concept/process-model/"
|
||||
description="Which processes Tauri manages and why."
|
||||
/>
|
||||
<LinkCard
|
||||
title="App Size"
|
||||
href="/concept/size/"
|
||||
description="How to make your app as small as possible."
|
||||
/>
|
||||
<LinkCard
|
||||
title="Rendering"
|
||||
href="/concept/rendering/"
|
||||
description="What a renderer is in Tauri."
|
||||
/>
|
||||
</CardGrid>
|
||||
|
||||
@@ -106,10 +106,10 @@ By default, the inspector is only enabled in development and debug builds unless
|
||||
To create a debug build, run the `tauri build --debug` command.
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri build -- --debug"
|
||||
yarn="yarn tauri build --debug"
|
||||
pnpm="pnpm tauri build --debug"
|
||||
cargo="cargo tauri build --debug"
|
||||
npm="npm run tauri build -- --debug"
|
||||
yarn="yarn tauri build --debug"
|
||||
pnpm="pnpm tauri build --debug"
|
||||
cargo="cargo tauri build --debug"
|
||||
/>
|
||||
|
||||
Like the normal build and dev processes, building takes some time the first time you run this command but is significantly faster on subsequent runs.
|
||||
|
||||
@@ -23,36 +23,36 @@ Create a `.vscode/launch.json` file and paste the below JSON contents into it:
|
||||
|
||||
```json title=".vscode/launch.json"
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Development Debug",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path=./src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
]
|
||||
},
|
||||
// task for the `beforeDevCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:dev"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Production Debug",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
|
||||
},
|
||||
// task for the `beforeBuildCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:build"
|
||||
}
|
||||
]
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Development Debug",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path=./src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
]
|
||||
},
|
||||
// task for the `beforeDevCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:dev"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Production Debug",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
|
||||
},
|
||||
// task for the `beforeBuildCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:build"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -62,29 +62,29 @@ Note that it does not use the Tauri CLI, so exclusive CLI features are not execu
|
||||
|
||||
```json title=".vscode/tasks.json"
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "ui:dev",
|
||||
"type": "shell",
|
||||
// `dev` keeps running in the background
|
||||
// ideally you should also configure a `problemMatcher`
|
||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
||||
"isBackground": true,
|
||||
// change this to your `beforeDevCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["dev"]
|
||||
},
|
||||
{
|
||||
"label": "ui:build",
|
||||
"type": "shell",
|
||||
// change this to your `beforeBuildCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["build"]
|
||||
}
|
||||
]
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "ui:dev",
|
||||
"type": "shell",
|
||||
// `dev` keeps running in the background
|
||||
// ideally you should also configure a `problemMatcher`
|
||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
||||
"isBackground": true,
|
||||
// change this to your `beforeDevCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["dev"]
|
||||
},
|
||||
{
|
||||
"label": "ui:build",
|
||||
"type": "shell",
|
||||
// change this to your `beforeBuildCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["build"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -41,10 +41,10 @@ To bootstrap a new plugin project, run `plugin new`. If you do not need the NPM
|
||||
After installing, you can run the following to create a plugin project:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri plugin new [name]"
|
||||
yarn="yarn tauri plugin new [name]"
|
||||
pnpm="pnpm tauri plugin new [name]"
|
||||
cargo="cargo tauri plugin new [name]"
|
||||
npm="npm run tauri plugin new [name]"
|
||||
yarn="yarn tauri plugin new [name]"
|
||||
pnpm="pnpm tauri plugin new [name]"
|
||||
cargo="cargo tauri plugin new [name]"
|
||||
/>
|
||||
|
||||
This will initialize the plugin at the directory `tauri-plugin-[name]` and, depending on the used CLI flags, the resulting project will look like this:
|
||||
|
||||
@@ -41,30 +41,30 @@ First, let's create our Tauri `distDir` that we know we will need once building
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello Tauri!</title>
|
||||
<style>
|
||||
body {
|
||||
/* Add a nice colorscheme */
|
||||
background-color: #222831;
|
||||
color: #ececec;
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello Tauri!</title>
|
||||
<style>
|
||||
body {
|
||||
/* Add a nice colorscheme */
|
||||
background-color: #222831;
|
||||
color: #ececec;
|
||||
|
||||
/* Make the body the exact size of the window */
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
/* Make the body the exact size of the window */
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
|
||||
/* Vertically and horizontally center children of the body tag */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello, Tauri!</h1>
|
||||
</body>
|
||||
/* Vertically and horizontally center children of the body tag */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello, Tauri!</h1>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
@@ -150,26 +150,26 @@ here.
|
||||
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"distDir": "dist"
|
||||
},
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"identifier": "studio.tauri.hello_tauri_webdriver",
|
||||
"icon": ["icon.png"]
|
||||
},
|
||||
"allowlist": {
|
||||
"all": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
}
|
||||
]
|
||||
}
|
||||
"build": {
|
||||
"distDir": "dist"
|
||||
},
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"identifier": "studio.tauri.hello_tauri_webdriver",
|
||||
"icon": ["icon.png"]
|
||||
},
|
||||
"allowlist": {
|
||||
"all": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"width": 800,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -187,7 +187,7 @@ will also run our WebDriver tests with a release profile. Run `cargo run --relea
|
||||
see the following application pop up.
|
||||
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Image src={HelloTauriWebdriver} alt="Hello Tauri Webdriver" />
|
||||
<Image src={HelloTauriWebdriver} alt="Hello Tauri Webdriver" />
|
||||
</div>
|
||||
|
||||
_Note: If you are modifying the application and want to use the Devtools, then run it without `--release` and "Inspect
|
||||
|
||||
@@ -38,17 +38,17 @@ guide on how to set it up from scratch.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "selenium",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"mocha": "^9.0.3",
|
||||
"selenium-webdriver": "^4.0.0-beta.4"
|
||||
}
|
||||
"name": "selenium",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"mocha": "^9.0.3",
|
||||
"selenium-webdriver": "^4.0.0-beta.4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -62,8 +62,8 @@ that we will be using to run the tests. [Mocha] as the testing framework, [Chai]
|
||||
If you want to install the dependencies from scratch, just run the following command.
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install mocha chai selenium-webdriver"
|
||||
yarn="yarn add mocha chai selenium-webdriver"
|
||||
npm="npm install mocha chai selenium-webdriver"
|
||||
yarn="yarn add mocha chai selenium-webdriver"
|
||||
/>
|
||||
|
||||
I suggest also adding a `"test": "mocha"` item in the `package.json` `"scripts"` key so that running Mocha can be called
|
||||
@@ -90,13 +90,13 @@ const { Builder, By, Capabilities } = require('selenium-webdriver');
|
||||
|
||||
// create the path to the expected application binary
|
||||
const application = path.resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'target',
|
||||
'release',
|
||||
'hello-tauri-webdriver'
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'target',
|
||||
'release',
|
||||
'hello-tauri-webdriver'
|
||||
);
|
||||
|
||||
// keep track of the webdriver instance we create
|
||||
@@ -106,61 +106,61 @@ let driver;
|
||||
let tauriDriver;
|
||||
|
||||
before(async function () {
|
||||
// set timeout to 2 minutes to allow the program to build if it needs to
|
||||
this.timeout(120000);
|
||||
// set timeout to 2 minutes to allow the program to build if it needs to
|
||||
this.timeout(120000);
|
||||
|
||||
// ensure the program has been built
|
||||
spawnSync('cargo', ['build', '--release']);
|
||||
// ensure the program has been built
|
||||
spawnSync('cargo', ['build', '--release']);
|
||||
|
||||
// start tauri-driver
|
||||
tauriDriver = spawn(
|
||||
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
|
||||
[],
|
||||
{ stdio: [null, process.stdout, process.stderr] }
|
||||
);
|
||||
// start tauri-driver
|
||||
tauriDriver = spawn(
|
||||
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
|
||||
[],
|
||||
{ stdio: [null, process.stdout, process.stderr] }
|
||||
);
|
||||
|
||||
const capabilities = new Capabilities();
|
||||
capabilities.set('tauri:options', { application });
|
||||
capabilities.setBrowserName('wry');
|
||||
const capabilities = new Capabilities();
|
||||
capabilities.set('tauri:options', { application });
|
||||
capabilities.setBrowserName('wry');
|
||||
|
||||
// start the webdriver client
|
||||
driver = await new Builder()
|
||||
.withCapabilities(capabilities)
|
||||
.usingServer('http://127.0.0.1:4444/')
|
||||
.build();
|
||||
// start the webdriver client
|
||||
driver = await new Builder()
|
||||
.withCapabilities(capabilities)
|
||||
.usingServer('http://127.0.0.1:4444/')
|
||||
.build();
|
||||
});
|
||||
|
||||
after(async function () {
|
||||
// stop the webdriver session
|
||||
await driver.quit();
|
||||
// stop the webdriver session
|
||||
await driver.quit();
|
||||
|
||||
// kill the tauri-driver process
|
||||
tauriDriver.kill();
|
||||
// kill the tauri-driver process
|
||||
tauriDriver.kill();
|
||||
});
|
||||
|
||||
describe('Hello Tauri', () => {
|
||||
it('should be cordial', async () => {
|
||||
const text = await driver.findElement(By.css('body > h1')).getText();
|
||||
expect(text).to.match(/^[hH]ello/);
|
||||
});
|
||||
it('should be cordial', async () => {
|
||||
const text = await driver.findElement(By.css('body > h1')).getText();
|
||||
expect(text).to.match(/^[hH]ello/);
|
||||
});
|
||||
|
||||
it('should be excited', async () => {
|
||||
const text = await driver.findElement(By.css('body > h1')).getText();
|
||||
expect(text).to.match(/!$/);
|
||||
});
|
||||
it('should be excited', async () => {
|
||||
const text = await driver.findElement(By.css('body > h1')).getText();
|
||||
expect(text).to.match(/!$/);
|
||||
});
|
||||
|
||||
it('should be easy on the eyes', async () => {
|
||||
// selenium returns color css values as rgb(r, g, b)
|
||||
const text = await driver
|
||||
.findElement(By.css('body'))
|
||||
.getCssValue('background-color');
|
||||
it('should be easy on the eyes', async () => {
|
||||
// selenium returns color css values as rgb(r, g, b)
|
||||
const text = await driver
|
||||
.findElement(By.css('body'))
|
||||
.getCssValue('background-color');
|
||||
|
||||
const rgb = text.match(/^rgb\((?<r>\d+), (?<g>\d+), (?<b>\d+)\)$/).groups;
|
||||
expect(rgb).to.have.all.keys('r', 'g', 'b');
|
||||
const rgb = text.match(/^rgb\((?<r>\d+), (?<g>\d+), (?<b>\d+)\)$/).groups;
|
||||
expect(rgb).to.have.all.keys('r', 'g', 'b');
|
||||
|
||||
const luma = 0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b;
|
||||
expect(luma).to.be.lessThan(100);
|
||||
});
|
||||
const luma = 0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b;
|
||||
expect(luma).to.be.lessThan(100);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -38,20 +38,20 @@ guide on setting it up from scratch.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "webdriverio",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "wdio run wdio.conf.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wdio/cli": "^7.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wdio/local-runner": "^7.9.1",
|
||||
"@wdio/mocha-framework": "^7.9.1",
|
||||
"@wdio/spec-reporter": "^7.9.0"
|
||||
}
|
||||
"name": "webdriverio",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "wdio run wdio.conf.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wdio/cli": "^7.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wdio/local-runner": "^7.9.1",
|
||||
"@wdio/mocha-framework": "^7.9.1",
|
||||
"@wdio/spec-reporter": "^7.9.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -91,36 +91,36 @@ const { spawn, spawnSync } = require('child_process');
|
||||
let tauriDriver;
|
||||
|
||||
exports.config = {
|
||||
specs: ['./develop/tests/specs/**/*.js'],
|
||||
maxInstances: 1,
|
||||
capabilities: [
|
||||
{
|
||||
maxInstances: 1,
|
||||
'tauri:options': {
|
||||
application: '../../target/release/hello-tauri-webdriver',
|
||||
},
|
||||
},
|
||||
],
|
||||
reporters: ['spec'],
|
||||
framework: 'mocha',
|
||||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
timeout: 60000,
|
||||
},
|
||||
specs: ['./develop/tests/specs/**/*.js'],
|
||||
maxInstances: 1,
|
||||
capabilities: [
|
||||
{
|
||||
maxInstances: 1,
|
||||
'tauri:options': {
|
||||
application: '../../target/release/hello-tauri-webdriver',
|
||||
},
|
||||
},
|
||||
],
|
||||
reporters: ['spec'],
|
||||
framework: 'mocha',
|
||||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
timeout: 60000,
|
||||
},
|
||||
|
||||
// ensure the rust project is built since we expect this binary to exist for the webdriver sessions
|
||||
onPrepare: () => spawnSync('cargo', ['build', '--release']),
|
||||
// ensure the rust project is built since we expect this binary to exist for the webdriver sessions
|
||||
onPrepare: () => spawnSync('cargo', ['build', '--release']),
|
||||
|
||||
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
|
||||
beforeSession: () =>
|
||||
(tauriDriver = spawn(
|
||||
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
|
||||
[],
|
||||
{ stdio: [null, process.stdout, process.stderr] }
|
||||
)),
|
||||
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
|
||||
beforeSession: () =>
|
||||
(tauriDriver = spawn(
|
||||
path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'),
|
||||
[],
|
||||
{ stdio: [null, process.stdout, process.stderr] }
|
||||
)),
|
||||
|
||||
// clean up the `tauri-driver` process we spawned at the start of the session
|
||||
afterSession: () => tauriDriver.kill(),
|
||||
// clean up the `tauri-driver` process we spawned at the start of the session
|
||||
afterSession: () => tauriDriver.kill(),
|
||||
};
|
||||
```
|
||||
|
||||
@@ -138,35 +138,35 @@ run them as it sees fit. Let's create our spec now in the directory we specified
|
||||
```js
|
||||
// calculates the luma from a hex color `#abcdef`
|
||||
function luma(hex) {
|
||||
if (hex.startsWith('#')) {
|
||||
hex = hex.substring(1);
|
||||
}
|
||||
if (hex.startsWith('#')) {
|
||||
hex = hex.substring(1);
|
||||
}
|
||||
|
||||
const rgb = parseInt(hex, 16);
|
||||
const r = (rgb >> 16) & 0xff;
|
||||
const g = (rgb >> 8) & 0xff;
|
||||
const b = (rgb >> 0) & 0xff;
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
const rgb = parseInt(hex, 16);
|
||||
const r = (rgb >> 16) & 0xff;
|
||||
const g = (rgb >> 8) & 0xff;
|
||||
const b = (rgb >> 0) & 0xff;
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
}
|
||||
|
||||
describe('Hello Tauri', () => {
|
||||
it('should be cordial', async () => {
|
||||
const header = await $('body > h1');
|
||||
const text = await header.getText();
|
||||
expect(text).toMatch(/^[hH]ello/);
|
||||
});
|
||||
it('should be cordial', async () => {
|
||||
const header = await $('body > h1');
|
||||
const text = await header.getText();
|
||||
expect(text).toMatch(/^[hH]ello/);
|
||||
});
|
||||
|
||||
it('should be excited', async () => {
|
||||
const header = await $('body > h1');
|
||||
const text = await header.getText();
|
||||
expect(text).toMatch(/!$/);
|
||||
});
|
||||
it('should be excited', async () => {
|
||||
const header = await $('body > h1');
|
||||
const text = await header.getText();
|
||||
expect(text).toMatch(/!$/);
|
||||
});
|
||||
|
||||
it('should be easy on the eyes', async () => {
|
||||
const body = await $('body');
|
||||
const backgroundColor = await body.getCSSProperty('background-color');
|
||||
expect(luma(backgroundColor.parsed.hex)).toBeLessThan(100);
|
||||
});
|
||||
it('should be easy on the eyes', async () => {
|
||||
const body = await $('body');
|
||||
const backgroundColor = await body.getCSSProperty('background-color');
|
||||
expect(luma(backgroundColor.parsed.hex)).toBeLessThan(100);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -60,15 +60,15 @@ can look at https://github.com/chippers/hello_tauri.
|
||||
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Setup" href="/start/develop/tests/webdriver/example/" />
|
||||
<LinkCard
|
||||
title="Selenium"
|
||||
href="/start/develop/tests/webdriver/example/selenium"
|
||||
/>
|
||||
<LinkCard
|
||||
title="WebdriverIO"
|
||||
href="/start/develop/tests/webdriver/example/webdriverio"
|
||||
/>
|
||||
<LinkCard title="Setup" href="/start/develop/tests/webdriver/example/" />
|
||||
<LinkCard
|
||||
title="Selenium"
|
||||
href="/start/develop/tests/webdriver/example/selenium"
|
||||
/>
|
||||
<LinkCard
|
||||
title="WebdriverIO"
|
||||
href="/start/develop/tests/webdriver/example/webdriverio"
|
||||
/>
|
||||
</CardGrid>
|
||||
|
||||
## Continuous Integration (CI)
|
||||
@@ -76,8 +76,8 @@ import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
The above examples also comes with a CI script to test with GitHub actions, but you may still be interested in the below WebDriver CI guide as it explains the concept a bit more.
|
||||
|
||||
<LinkCard
|
||||
title="Continuous Integration (CI)"
|
||||
href="/start/develop/tests/webdriver/ci"
|
||||
title="Continuous Integration (CI)"
|
||||
href="/start/develop/tests/webdriver/ci"
|
||||
/>
|
||||
|
||||
[webdriver]: https://www.w3.org/TR/webdriver/
|
||||
|
||||
@@ -119,8 +119,8 @@ If the command returns an error, the promise will reject, otherwise, it resolves
|
||||
|
||||
```js
|
||||
invoke('my_custom_command')
|
||||
.then((message) => console.log(message))
|
||||
.catch((error) => console.error(error));
|
||||
.then((message) => console.log(message))
|
||||
.catch((error) => console.error(error));
|
||||
```
|
||||
|
||||
As mentioned above, everything returned from commands must implement [`serde::Serialize`], including errors.
|
||||
@@ -231,7 +231,7 @@ Since invoking the command from JavaScript already returns a promise, it works j
|
||||
|
||||
```js
|
||||
invoke('my_custom_command', { value: 'Hello, Async!' }).then(() =>
|
||||
console.log('Completed!')
|
||||
console.log('Completed!')
|
||||
);
|
||||
```
|
||||
|
||||
@@ -379,12 +379,12 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
// Invocation from JavaScript
|
||||
invoke('my_custom_command', {
|
||||
number: 42,
|
||||
number: 42,
|
||||
})
|
||||
.then((res) =>
|
||||
console.log(`Message: ${res.message}, Other Val: ${res.other_val}`)
|
||||
)
|
||||
.catch((e) => console.error(e));
|
||||
.then((res) =>
|
||||
console.log(`Message: ${res.message}, Other Val: ${res.other_val}`)
|
||||
)
|
||||
.catch((e) => console.error(e));
|
||||
```
|
||||
|
||||
[`async_runtime::spawn`]: https://docs.rs/tauri/2.0.0-beta/tauri/async_runtime/fn.spawn.html
|
||||
|
||||
@@ -24,10 +24,10 @@ Every framework has its own development tooling. It is outside of the scope of t
|
||||
### 2. Start Tauri Development Window
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri dev"
|
||||
yarn="yarn tauri dev"
|
||||
pnpm="pnpm tauri dev"
|
||||
cargo="cargo tauri dev"
|
||||
npm="npm run tauri dev"
|
||||
yarn="yarn tauri dev"
|
||||
pnpm="pnpm tauri dev"
|
||||
cargo="cargo tauri dev"
|
||||
/>
|
||||
|
||||
The first time you run this command, the Rust package manager takes several minutes to download and build all the required packages. Since they are cached, subsequent builds are much faster, as only your code needs rebuilding.
|
||||
|
||||
@@ -17,15 +17,15 @@ Here is a sample to illustrate the configuration. This is not a complete `tauri.
|
||||
|
||||
```json title="src-tauri/tauri.conf.json"
|
||||
{
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"externalBin": [
|
||||
"/absolute/path/to/sidecar",
|
||||
"relative/path/to/binary",
|
||||
"binaries/my-sidecar"
|
||||
]
|
||||
}
|
||||
}
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"externalBin": [
|
||||
"/absolute/path/to/sidecar",
|
||||
"relative/path/to/binary",
|
||||
"binaries/my-sidecar"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -59,23 +59,23 @@ const fs = require('fs');
|
||||
|
||||
let extension = '';
|
||||
if (process.platform === 'win32') {
|
||||
extension = '.exe';
|
||||
extension = '.exe';
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const rustInfo = (await execa('rustc', ['-vV'])).stdout;
|
||||
const targetTriple = /host: (\S+)/g.exec(rustInfo)[1];
|
||||
if (!targetTriple) {
|
||||
console.error('Failed to determine platform target triple');
|
||||
}
|
||||
fs.renameSync(
|
||||
`src-tauri/binaries/sidecar${extension}`,
|
||||
`src-tauri/binaries/sidecar-${targetTriple}${extension}`
|
||||
);
|
||||
const rustInfo = (await execa('rustc', ['-vV'])).stdout;
|
||||
const targetTriple = /host: (\S+)/g.exec(rustInfo)[1];
|
||||
if (!targetTriple) {
|
||||
console.error('Failed to determine platform target triple');
|
||||
}
|
||||
fs.renameSync(
|
||||
`src-tauri/binaries/sidecar${extension}`,
|
||||
`src-tauri/binaries/sidecar-${targetTriple}${extension}`
|
||||
);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
throw e;
|
||||
throw e;
|
||||
});
|
||||
```
|
||||
|
||||
@@ -130,38 +130,38 @@ First, define the arguments that need to be passed to the sidecar command in `sr
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={14-31}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
{
|
||||
"identifier": "shell:allow-execute",
|
||||
"allow": [
|
||||
{
|
||||
"args": [
|
||||
"arg1",
|
||||
"-a",
|
||||
"--arg2",
|
||||
{
|
||||
"validator": "\\S+"
|
||||
}
|
||||
],
|
||||
"cmd": "",
|
||||
"name": "binaries/my-sidecar",
|
||||
"sidecar": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"shell:allow-open"
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
{
|
||||
"identifier": "shell:allow-execute",
|
||||
"allow": [
|
||||
{
|
||||
"args": [
|
||||
"arg1",
|
||||
"-a",
|
||||
"--arg2",
|
||||
{
|
||||
"validator": "\\S+"
|
||||
}
|
||||
],
|
||||
"cmd": "",
|
||||
"name": "binaries/my-sidecar",
|
||||
"sidecar": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"shell:allow-open"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -192,10 +192,10 @@ import { Command } from '@tauri-apps/plugin-shell';
|
||||
// `binaries/my-sidecar` is the EXACT value specified on `tauri.conf.json > tauri > bundle > externalBin`
|
||||
// notice that the args array matches EXACTLY what is specified on `tauri.conf.json`.
|
||||
const command = Command.sidecar('binaries/my-sidecar', [
|
||||
'arg1',
|
||||
'-a',
|
||||
'--arg2',
|
||||
'any-string-that-matches-the-validator',
|
||||
'arg1',
|
||||
'-a',
|
||||
'--arg2',
|
||||
'any-string-that-matches-the-validator',
|
||||
]);
|
||||
const output = await command.execute();
|
||||
```
|
||||
|
||||
@@ -16,25 +16,25 @@ import CommandTabs from '@components/CommandTabs.astro';
|
||||
If you are using the `tauri` package:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn up @tauri-apps/cli @tauri-apps/api"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn up @tauri-apps/cli @tauri-apps/api"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
/>
|
||||
|
||||
You can also detect what the latest version of Tauri is on the command line, using:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm outdated @tauri-apps/cli"
|
||||
yarn="yarn outdated @tauri-apps/cli"
|
||||
pnpm="pnpm outdated @tauri-apps/cli"
|
||||
npm="npm outdated @tauri-apps/cli"
|
||||
yarn="yarn outdated @tauri-apps/cli"
|
||||
pnpm="pnpm outdated @tauri-apps/cli"
|
||||
/>
|
||||
|
||||
Alternatively, if you are using the `vue-cli-plugin-tauri` approach:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install vue-cli-plugin-tauri@latest"
|
||||
yarn="yarn up vue-cli-plugin-tauri"
|
||||
pnpm="pnpm update vue-cli-plugin-tauri --latest"
|
||||
npm="npm install vue-cli-plugin-tauri@latest"
|
||||
yarn="yarn up vue-cli-plugin-tauri"
|
||||
pnpm="pnpm update vue-cli-plugin-tauri --latest"
|
||||
/>
|
||||
|
||||
## Update Cargo Packages
|
||||
|
||||
@@ -27,35 +27,35 @@ hero:
|
||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<div class="hero-bg">
|
||||
<div class="bg-logo"></div>
|
||||
<div class="bg-grad"></div>
|
||||
<div class="bg-grad-red"></div>
|
||||
<div class="bg-logo"></div>
|
||||
<div class="bg-grad"></div>
|
||||
<div class="bg-grad-red"></div>
|
||||
</div>
|
||||
|
||||
<CardGrid stagger>
|
||||
<Card title="Frontend Independiente" icon="rocket">
|
||||
Trae tu stack web existente a Tauri o comienza ese nuevo proyecto de en
|
||||
sueño. Tauri soporta cualquier framework frontend, por lo que no necesitas
|
||||
cambiar tu stack.
|
||||
</Card>
|
||||
<Card title="Multiplataforma" icon="rocket">
|
||||
Construye tu aplicación para Linux, macOS, Windows, Android e iOS - todo
|
||||
desde una sola base de código.
|
||||
</Card>
|
||||
<Card title="Comunicación Entre Procesos" icon="rocket">
|
||||
Escribe tu frontend en JavaScript, la lógica de la aplicación en Rust, e
|
||||
integra profundamente en el sistema con Swift y Kotlin.
|
||||
</Card>
|
||||
<Card title="Máxima Seguridad" icon="rocket">
|
||||
Frente a la mente del equipo de Tauri que impulsa nuestras mayores
|
||||
prioridades y mayores innovaciones.
|
||||
</Card>
|
||||
<Card title="Tamaño Mínimo" icon="rocket">
|
||||
Al usar el renderizador web nativo del sistema operativo, el tamaño de una
|
||||
aplicación Tauri puede ser tan pequeño como 600KB.
|
||||
</Card>
|
||||
<Card title="Impulsado por Rust" icon="rocket">
|
||||
Con el rendimiento y la seguridad en el centro, Rust es el lenguaje para la
|
||||
próxima generación de aplicaciones.
|
||||
</Card>
|
||||
<Card title="Frontend Independiente" icon="rocket">
|
||||
Trae tu stack web existente a Tauri o comienza ese nuevo proyecto de en
|
||||
sueño. Tauri soporta cualquier framework frontend, por lo que no necesitas
|
||||
cambiar tu stack.
|
||||
</Card>
|
||||
<Card title="Multiplataforma" icon="rocket">
|
||||
Construye tu aplicación para Linux, macOS, Windows, Android e iOS - todo
|
||||
desde una sola base de código.
|
||||
</Card>
|
||||
<Card title="Comunicación Entre Procesos" icon="rocket">
|
||||
Escribe tu frontend en JavaScript, la lógica de la aplicación en Rust, e
|
||||
integra profundamente en el sistema con Swift y Kotlin.
|
||||
</Card>
|
||||
<Card title="Máxima Seguridad" icon="rocket">
|
||||
Frente a la mente del equipo de Tauri que impulsa nuestras mayores
|
||||
prioridades y mayores innovaciones.
|
||||
</Card>
|
||||
<Card title="Tamaño Mínimo" icon="rocket">
|
||||
Al usar el renderizador web nativo del sistema operativo, el tamaño de una
|
||||
aplicación Tauri puede ser tan pequeño como 600KB.
|
||||
</Card>
|
||||
<Card title="Impulsado por Rust" icon="rocket">
|
||||
Con el rendimiento y la seguridad en el centro, Rust es el lenguaje para la
|
||||
próxima generación de aplicaciones.
|
||||
</Card>
|
||||
</CardGrid>
|
||||
|
||||
@@ -93,8 +93,8 @@ import { ask } from '@tauri-apps/plugin-dialog';
|
||||
|
||||
// Crea un diálogo de Sí/No
|
||||
const answer = await ask('This action cannot be reverted. Are you sure?', {
|
||||
title: 'Tauri',
|
||||
type: 'warning',
|
||||
title: 'Tauri',
|
||||
type: 'warning',
|
||||
});
|
||||
|
||||
console.log(answer);
|
||||
@@ -112,8 +112,8 @@ import { confirm } from '@tauri-apps/plugin-dialog';
|
||||
|
||||
// Crea un diálogo de confirmación Ok/Cancelar
|
||||
const confirmation = await confirm(
|
||||
'This action cannot be reverted. Are you sure?',
|
||||
{ title: 'Tauri', type: 'warning' }
|
||||
'This action cannot be reverted. Are you sure?',
|
||||
{ title: 'Tauri', type: 'warning' }
|
||||
);
|
||||
|
||||
console.log(confirmation);
|
||||
@@ -146,8 +146,8 @@ import { open } from '@tauri-apps/plugin-dialog';
|
||||
|
||||
// Abre un diálogo
|
||||
const file = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
multiple: false,
|
||||
directory: false,
|
||||
});
|
||||
console.log(file);
|
||||
// Imprime la ruta y el nombre del archivo en la consola
|
||||
@@ -163,12 +163,12 @@ Abre un diálogo de guardar archivo/directorio.
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
// Indica para guardar un 'My Filter' con extensión .png o .jpeg
|
||||
const path = await save({
|
||||
filters: [
|
||||
{
|
||||
name: 'My Filter',
|
||||
extensions: ['png', 'jpeg'],
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
name: 'My Filter',
|
||||
extensions: ['png', 'jpeg'],
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log(path);
|
||||
// Imprime la ruta escogida
|
||||
|
||||
@@ -13,10 +13,10 @@ Tauri viene con el objetivo de ser extensible. En esta página encontrarás:
|
||||
- **[Recursos de la Comunidad](#recursos-de-la-comunidad)**: Más plugins y fórmulas creadas por la comunidad de Tauri
|
||||
|
||||
<Search>
|
||||
## Características
|
||||
<FeaturesList />
|
||||
## Recursos de la comunidad
|
||||
<CommunityList />
|
||||
## Características
|
||||
<FeaturesList />
|
||||
## Recursos de la comunidad
|
||||
<CommunityList />
|
||||
</Search>
|
||||
|
||||
:::tip[¿Tienes algo genial que compartir?]
|
||||
|
||||
@@ -18,21 +18,21 @@ Si un framework no aparece en esta lista puede que funcione con Tauri sin necesi
|
||||
## JavaScript
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Next.js" href="/start/frontend/nextjs" />
|
||||
<LinkCard title="Nuxt" href="/start/frontend/nuxt" />
|
||||
<LinkCard title="Qwik" href="/start/frontend/qwik" />
|
||||
<LinkCard title="Svelte" href="/start/frontend/svelte" />
|
||||
<LinkCard title="Vite" href="/start/frontend/vite" />
|
||||
<LinkCard title="Webpack" href="/start/frontend/webpack" />
|
||||
<LinkCard title="Next.js" href="/start/frontend/nextjs" />
|
||||
<LinkCard title="Nuxt" href="/start/frontend/nuxt" />
|
||||
<LinkCard title="Qwik" href="/start/frontend/qwik" />
|
||||
<LinkCard title="Svelte" href="/start/frontend/svelte" />
|
||||
<LinkCard title="Vite" href="/start/frontend/vite" />
|
||||
<LinkCard title="Webpack" href="/start/frontend/webpack" />
|
||||
</CardGrid>
|
||||
|
||||
## Rust
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Leptos" href="/start/frontend/leptos" />
|
||||
<LinkCard title="Sycamore" href="/start/frontend/sycamore" />
|
||||
<LinkCard title="Trunk" href="/start/frontend/trunk" />
|
||||
<LinkCard title="Yew" href="/start/frontend/yew" />
|
||||
<LinkCard title="Leptos" href="/start/frontend/leptos" />
|
||||
<LinkCard title="Sycamore" href="/start/frontend/sycamore" />
|
||||
<LinkCard title="Trunk" href="/start/frontend/trunk" />
|
||||
<LinkCard title="Yew" href="/start/frontend/yew" />
|
||||
</CardGrid>
|
||||
|
||||
## Checklist de Configuración
|
||||
|
||||
@@ -19,9 +19,9 @@ Next.js es un framework para React. Aprende más sobre Next.js en https://nextjs
|
||||
1. Instala `internal-ip` para el desarrollo móvil:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install --save-dev internal-ip"
|
||||
yarn="yarn add -D internal-ip"
|
||||
pnpm="pnpm add -D internal-ip"
|
||||
npm="npm install --save-dev internal-ip"
|
||||
yarn="yarn add -D internal-ip"
|
||||
pnpm="pnpm add -D internal-ip"
|
||||
/>
|
||||
|
||||
2. Actualiza la configuración de Tauri:
|
||||
@@ -32,12 +32,12 @@ Next.js es un framework para React. Aprende más sobre Next.js en https://nextjs
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -47,12 +47,12 @@ Next.js es un framework para React. Aprende más sobre Next.js en https://nextjs
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -62,12 +62,12 @@ Next.js es un framework para React. Aprende más sobre Next.js en https://nextjs
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -80,24 +80,24 @@ Next.js es un framework para React. Aprende más sobre Next.js en https://nextjs
|
||||
// next.conf.ts
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
module.exports = async (phase, { defaultConfig }) => {
|
||||
let internalHost = null;
|
||||
// En modo de desarrollo usamos internal-ip para servir los archivos
|
||||
if (!isProd) {
|
||||
const { internalIpV4 } = await import('internal-ip');
|
||||
internalHost = await internalIpV4();
|
||||
}
|
||||
const nextConfig = {
|
||||
// Aségurate de que Next.js use SSG en lugar de SSR
|
||||
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
|
||||
output: 'export',
|
||||
// Nota: Esta función experimental es necesaria para usar NextJS Image en modo SSG.
|
||||
// Consulta https://nextjs.org/docs/messages/export-image-api para ver diferentes soluciones.
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
// Configura assetPrefix o el servidor no resolverá correctamente tus archivos.
|
||||
assetPrefix: isProd ? null : `http://${internalHost}:3000`,
|
||||
};
|
||||
return nextConfig;
|
||||
let internalHost = null;
|
||||
// En modo de desarrollo usamos internal-ip para servir los archivos
|
||||
if (!isProd) {
|
||||
const { internalIpV4 } = await import('internal-ip');
|
||||
internalHost = await internalIpV4();
|
||||
}
|
||||
const nextConfig = {
|
||||
// Aségurate de que Next.js use SSG en lugar de SSR
|
||||
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
|
||||
output: 'export',
|
||||
// Nota: Esta función experimental es necesaria para usar NextJS Image en modo SSG.
|
||||
// Consulta https://nextjs.org/docs/messages/export-image-api para ver diferentes soluciones.
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
// Configura assetPrefix o el servidor no resolverá correctamente tus archivos.
|
||||
assetPrefix: isProd ? null : `http://${internalHost}:3000`,
|
||||
};
|
||||
return nextConfig;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -25,12 +25,12 @@ Aprende más sobre Nuxt en https://nuxt.com. Esta guía es precisa a partir de N
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -40,12 +40,12 @@ Aprende más sobre Nuxt en https://nuxt.com. Esta guía es precisa a partir de N
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -55,12 +55,12 @@ Aprende más sobre Nuxt en https://nuxt.com. Esta guía es precisa a partir de N
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -72,31 +72,31 @@ Aprende más sobre Nuxt en https://nuxt.com. Esta guía es precisa a partir de N
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
// (opcional) Habilita las herramientas de desarrollo de Nuxt
|
||||
devtools: { enabled: true },
|
||||
// Habilita SSG
|
||||
ssr: false,
|
||||
vite: {
|
||||
// Mejor soporte para la salida de Tauri CLI
|
||||
clearScreen: false,
|
||||
// Habilita las variables de entorno
|
||||
// Las variables de entorno adicionales se pueden encontrar en
|
||||
// https://tauri.app/2/reference/environment-variables/
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
server: {
|
||||
// Tauri requiere un puerto consistente
|
||||
strictPort: true,
|
||||
// Habilita el servidor de desarrollo para pueda ser accedido por otros dispositivos para el desarrollo móvil
|
||||
host: '0.0.0.0',
|
||||
hmr: {
|
||||
// Usa un websocket para la recarga rápida en móviles
|
||||
protocol: 'ws',
|
||||
// Asegúrate de que esté disponible en la red
|
||||
host: '0.0.0.0',
|
||||
// Usa un puerto específico para hmr
|
||||
port: 5183,
|
||||
},
|
||||
},
|
||||
},
|
||||
// (opcional) Habilita las herramientas de desarrollo de Nuxt
|
||||
devtools: { enabled: true },
|
||||
// Habilita SSG
|
||||
ssr: false,
|
||||
vite: {
|
||||
// Mejor soporte para la salida de Tauri CLI
|
||||
clearScreen: false,
|
||||
// Habilita las variables de entorno
|
||||
// Las variables de entorno adicionales se pueden encontrar en
|
||||
// https://tauri.app/2/reference/environment-variables/
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
server: {
|
||||
// Tauri requiere un puerto consistente
|
||||
strictPort: true,
|
||||
// Habilita el servidor de desarrollo para pueda ser accedido por otros dispositivos para el desarrollo móvil
|
||||
host: '0.0.0.0',
|
||||
hmr: {
|
||||
// Usa un websocket para la recarga rápida en móviles
|
||||
protocol: 'ws',
|
||||
// Asegúrate de que esté disponible en la red
|
||||
host: '0.0.0.0',
|
||||
// Usa un puerto específico para hmr
|
||||
port: 5183,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -19,15 +19,15 @@ Trunk es una herramienta de empaquetado de aplicaciones web WASM para Rust. Obt
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "trunk serve",
|
||||
"beforeBuildCommand": "trunk build",
|
||||
"devPath": "http://localhost:8080",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "trunk serve",
|
||||
"beforeBuildCommand": "trunk build",
|
||||
"devPath": "http://localhost:8080",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -73,10 +73,10 @@ Par défaut, l'inspecteur n'est activé que dans les versions de développement
|
||||
Pour créer une version de débogage, exécutez la commande `tauri build --debug`.
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri build -- --debug"
|
||||
yarn="yarn tauri build --debug"
|
||||
pnpm="pnpm tauri build --debug"
|
||||
cargo="cargo tauri build --debug"
|
||||
npm="npm run tauri build -- --debug"
|
||||
yarn="yarn tauri build --debug"
|
||||
pnpm="pnpm tauri build --debug"
|
||||
cargo="cargo tauri build --debug"
|
||||
/>
|
||||
|
||||
Comme les processus de construction et de développement normaux, la construction prend un certain temps la première fois que vous exécutez cette commande, mais est beaucoup plus rapide lors des exécutions suivantes. L'application groupée finale a la console de développement activée et est placée dans `src-tauri/target/debug/bundle`.
|
||||
|
||||
@@ -6,13 +6,13 @@ description: Conseils et astuces pour votre débogage
|
||||
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard
|
||||
title="Débogage de l'application"
|
||||
href="/fr/develop/Debug/application//"
|
||||
/>
|
||||
<LinkCard title="Débogage dans VS Code" href="/fr/develop/Debug/vscode" />
|
||||
<LinkCard
|
||||
title="Débogage dans RustRover"
|
||||
href="/fr/develop/Debug/rustrover"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Débogage de l'application"
|
||||
href="/fr/develop/Debug/application//"
|
||||
/>
|
||||
<LinkCard title="Débogage dans VS Code" href="/fr/develop/Debug/vscode" />
|
||||
<LinkCard
|
||||
title="Débogage dans RustRover"
|
||||
href="/fr/develop/Debug/rustrover"
|
||||
/>
|
||||
</CardGrid>
|
||||
|
||||
@@ -14,36 +14,36 @@ Créez un fichier `.vscode/launch.json` et collez-y le contenu JSON ci-dessous :
|
||||
|
||||
```json title=".vscode/launch.json"
|
||||
{
|
||||
// Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
|
||||
// Survolez pour afficher les descriptions des attributs existants.
|
||||
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Débogage de la production de Tauri",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path=./src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
]
|
||||
},
|
||||
// La tâche pour `beforeDevCommand` si elle est utilisée, doit être configurée dans `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:dev"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug de production de Tauri",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
|
||||
},
|
||||
// La tâche pour `beforeBuildCommand` si elle est utilisée, doit être configurée dans `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:build"
|
||||
}
|
||||
]
|
||||
// Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
|
||||
// Survolez pour afficher les descriptions des attributs existants.
|
||||
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Débogage de la production de Tauri",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path=./src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
]
|
||||
},
|
||||
// La tâche pour `beforeDevCommand` si elle est utilisée, doit être configurée dans `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:dev"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug de production de Tauri",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
|
||||
},
|
||||
// La tâche pour `beforeBuildCommand` si elle est utilisée, doit être configurée dans `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:build"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -53,29 +53,29 @@ Notez qu'il n'utilise pas la CLI Tauri, donc les fonctionnalités CLI exclusives
|
||||
|
||||
```json title=".vscode/tasks.json"
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "ui:dev",
|
||||
"type": "shell",
|
||||
// `dev` keeps running in the background
|
||||
// ideally you should also configure a `problemMatcher`
|
||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
||||
"isBackground": true,
|
||||
// change this to your `beforeDevCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["dev"]
|
||||
},
|
||||
{
|
||||
"label": "ui:build",
|
||||
"type": "shell",
|
||||
// change this to your `beforeBuildCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["build"]
|
||||
}
|
||||
]
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "ui:dev",
|
||||
"type": "shell",
|
||||
// `dev` keeps running in the background
|
||||
// ideally you should also configure a `problemMatcher`
|
||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
||||
"isBackground": true,
|
||||
// change this to your `beforeDevCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["dev"]
|
||||
},
|
||||
{
|
||||
"label": "ui:build",
|
||||
"type": "shell",
|
||||
// change this to your `beforeBuildCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["build"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ Chaque framework possède ses propres outils de développement. Il n'entre pas d
|
||||
### 2. Démarrer la fenêtre de développement de Tauri
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri dev"
|
||||
yarn="yarn tauri dev"
|
||||
pnpm="pnpm tauri dev"
|
||||
cargo="cargo tauri dev"
|
||||
npm="npm run tauri dev"
|
||||
yarn="yarn tauri dev"
|
||||
pnpm="pnpm tauri dev"
|
||||
cargo="cargo tauri dev"
|
||||
/>
|
||||
|
||||
La première fois que vous exécutez cette commande, le gestionnaire de packages Rust prend plusieurs minutes pour télécharger et créer tous les packages requis. Comme ils sont mis en cache, les builds suivants sont beaucoup plus rapides, car seul votre code a besoin d'être reconstruit.
|
||||
|
||||
@@ -6,12 +6,12 @@ description: Concepts de base pour le développement avec Tauri
|
||||
import { LinkCard, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard
|
||||
title="Development Cycle"
|
||||
href="/fr/guides/develop/development-cycle/"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Mise à jour des dépendances"
|
||||
href="/fr/guides/develop/updating-dependencies"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Development Cycle"
|
||||
href="/fr/guides/develop/development-cycle/"
|
||||
/>
|
||||
<LinkCard
|
||||
title="Mise à jour des dépendances"
|
||||
href="/fr/guides/develop/updating-dependencies"
|
||||
/>
|
||||
</CardGrid>
|
||||
|
||||
@@ -9,25 +9,25 @@ import CommandTabs from '@components/CommandTabs.astro';
|
||||
Si vous utilisez le package `tauri` :
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn up @tauri-apps/cli @tauri-apps/api"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
npm="npm install @tauri-apps/cli@latest @tauri-apps/api@latest"
|
||||
yarn="yarn up @tauri-apps/cli @tauri-apps/api"
|
||||
pnpm="pnpm update @tauri-apps/cli @tauri-apps/api --latest"
|
||||
/>
|
||||
|
||||
Vous pouvez également détecter la dernière version de Tauri sur la ligne de commande, en utilisant :
|
||||
|
||||
<CommandTabs
|
||||
npm="npm outdated @tauri-apps/cli"
|
||||
yarn="yarn outdated @tauri-apps/cli"
|
||||
pnpm="pnpm outdated @tauri-apps/cli"
|
||||
npm="npm outdated @tauri-apps/cli"
|
||||
yarn="yarn outdated @tauri-apps/cli"
|
||||
pnpm="pnpm outdated @tauri-apps/cli"
|
||||
/>
|
||||
|
||||
Sinon, si vous utilisez l'approche `vue-cli-plugin-tauri` :
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install vue-cli-plugin-tauri@latest"
|
||||
yarn="yarn up vue-cli-plugin-tauri"
|
||||
pnpm="pnpm update vue-cli-plugin-tauri --latest"
|
||||
npm="npm install vue-cli-plugin-tauri@latest"
|
||||
yarn="yarn up vue-cli-plugin-tauri"
|
||||
pnpm="pnpm update vue-cli-plugin-tauri --latest"
|
||||
/>
|
||||
|
||||
## Mettre à jour les packages Cargo
|
||||
|
||||
@@ -30,35 +30,35 @@ hero:
|
||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<div class="hero-bg">
|
||||
<div class="bg-logo"></div>
|
||||
<div class="bg-grad"></div>
|
||||
<div class="bg-grad-red"></div>
|
||||
<div class="bg-logo"></div>
|
||||
<div class="bg-grad"></div>
|
||||
<div class="bg-grad-red"></div>
|
||||
</div>
|
||||
|
||||
<CardGrid stagger>
|
||||
<Card title="Frontend Indépendant" icon="rocket">
|
||||
Importez votre configuration web existant dans Tauri ou démarrez votre
|
||||
nouveau projet de rêve. Tauri supporte n'importe quel framework frontend,
|
||||
vous n'avez donc pas besoin de changer votre configuration.
|
||||
</Card>
|
||||
<Card title="Multiplatforme" icon="rocket">
|
||||
Développez vos applications pour Linux, macOS, Windows, Android et iOS -
|
||||
tout cela à partir du même code.
|
||||
</Card>
|
||||
<Card title="Communication Inter-Processus" icon="rocket">
|
||||
Écrivez votre frontend en Javascript, la logique de l'application en Rust,
|
||||
puis intégrez le tout profondément dans le système avec Swift et Kotlin.
|
||||
</Card>
|
||||
<Card title="Sécurité Maximale" icon="rocket">
|
||||
C'est la première préoccupation de l'équipe Tauri, qui dirige nos priorités
|
||||
et nos plus grandes innovations.
|
||||
</Card>
|
||||
<Card title="Poids Minimal" icon="rocket">
|
||||
En utilisant le moteur de rendu web natif du système d'exploitation, le
|
||||
poids d'une application Tauri peut atteindre 600 Ko.
|
||||
</Card>
|
||||
<Card title="Fonctionne avec Rust" icon="rocket">
|
||||
Avec la performance et la sécurité au cœur de ses priorités, Rust est le
|
||||
langage de la nouvelle génération d'applications.
|
||||
</Card>
|
||||
<Card title="Frontend Indépendant" icon="rocket">
|
||||
Importez votre configuration web existant dans Tauri ou démarrez votre
|
||||
nouveau projet de rêve. Tauri supporte n'importe quel framework frontend,
|
||||
vous n'avez donc pas besoin de changer votre configuration.
|
||||
</Card>
|
||||
<Card title="Multiplatforme" icon="rocket">
|
||||
Développez vos applications pour Linux, macOS, Windows, Android et iOS -
|
||||
tout cela à partir du même code.
|
||||
</Card>
|
||||
<Card title="Communication Inter-Processus" icon="rocket">
|
||||
Écrivez votre frontend en Javascript, la logique de l'application en Rust,
|
||||
puis intégrez le tout profondément dans le système avec Swift et Kotlin.
|
||||
</Card>
|
||||
<Card title="Sécurité Maximale" icon="rocket">
|
||||
C'est la première préoccupation de l'équipe Tauri, qui dirige nos priorités
|
||||
et nos plus grandes innovations.
|
||||
</Card>
|
||||
<Card title="Poids Minimal" icon="rocket">
|
||||
En utilisant le moteur de rendu web natif du système d'exploitation, le
|
||||
poids d'une application Tauri peut atteindre 600 Ko.
|
||||
</Card>
|
||||
<Card title="Fonctionne avec Rust" icon="rocket">
|
||||
Avec la performance et la sécurité au cœur de ses priorités, Rust est le
|
||||
langage de la nouvelle génération d'applications.
|
||||
</Card>
|
||||
</CardGrid>
|
||||
|
||||
@@ -88,9 +88,9 @@ Suivez ces étapes pour envoyer une notification:
|
||||
|
||||
```js
|
||||
import {
|
||||
isPermissionGranted,
|
||||
requestPermission,
|
||||
sendNotification,
|
||||
isPermissionGranted,
|
||||
requestPermission,
|
||||
sendNotification,
|
||||
} from '@tauri-apps/plugin-notification';
|
||||
|
||||
// Avez-vous la permission d'envoyer une notification ?
|
||||
@@ -98,13 +98,13 @@ let permissionGranted = await isPermissionGranted();
|
||||
|
||||
// Le cas échéant on la demande
|
||||
if (!permissionGranted) {
|
||||
const permission = await requestPermission();
|
||||
permissionGranted = permission === 'granted';
|
||||
const permission = await requestPermission();
|
||||
permissionGranted = permission === 'granted';
|
||||
}
|
||||
|
||||
// Une fois la permission obtenue, on envoie la notification
|
||||
if (permissionGranted) {
|
||||
sendNotification({ title: 'Tauri', body: 'Tauri est incroyable!' });
|
||||
sendNotification({ title: 'Tauri', body: 'Tauri est incroyable!' });
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -19,21 +19,21 @@ Un framework manque à la liste ? Il peut fonctionner avec Tauri sans configurat
|
||||
## JavaScript
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Next.js" href="/fr/start/frontend/nextjs" />
|
||||
<LinkCard title="Nuxt" href="/fr/start/frontend/nuxt" />
|
||||
<LinkCard title="Qwik" href="/fr/start/frontend/qwik" />
|
||||
<LinkCard title="Svelte" href="/fr/start/frontend/svelte" />
|
||||
<LinkCard title="Vite" href="/fr/start/frontend/vite" />
|
||||
<LinkCard title="Webpack" href="/fr/start/frontend/webpack" />
|
||||
<LinkCard title="Next.js" href="/fr/start/frontend/nextjs" />
|
||||
<LinkCard title="Nuxt" href="/fr/start/frontend/nuxt" />
|
||||
<LinkCard title="Qwik" href="/fr/start/frontend/qwik" />
|
||||
<LinkCard title="Svelte" href="/fr/start/frontend/svelte" />
|
||||
<LinkCard title="Vite" href="/fr/start/frontend/vite" />
|
||||
<LinkCard title="Webpack" href="/fr/start/frontend/webpack" />
|
||||
</CardGrid>
|
||||
|
||||
## Rust
|
||||
|
||||
<CardGrid>
|
||||
<LinkCard title="Leptos" href="/fr/start/frontend/leptos" />
|
||||
<LinkCard title="Sycamore" href="/fr/start/frontend/sycamore" />
|
||||
<LinkCard title="Trunk" href="/fr/start/frontend/trunk" />
|
||||
<LinkCard title="Yew" href="/fr/start/frontend/yew" />
|
||||
<LinkCard title="Leptos" href="/fr/start/frontend/leptos" />
|
||||
<LinkCard title="Sycamore" href="/fr/start/frontend/sycamore" />
|
||||
<LinkCard title="Trunk" href="/fr/start/frontend/trunk" />
|
||||
<LinkCard title="Yew" href="/fr/start/frontend/yew" />
|
||||
</CardGrid>
|
||||
|
||||
## Instructions de Configuration
|
||||
|
||||
@@ -20,9 +20,9 @@ Next.js est un framework React. Apprenez-en plus au sujet de Next.js sur https:/
|
||||
1. Installez `internal-ip` pour le développement mobile :
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install --save-dev internal-ip"
|
||||
yarn="yarn add -D internal-ip"
|
||||
pnpm="pnpm add -D internal-ip"
|
||||
npm="npm install --save-dev internal-ip"
|
||||
yarn="yarn add -D internal-ip"
|
||||
pnpm="pnpm add -D internal-ip"
|
||||
/>
|
||||
|
||||
2. Mettez à jour la configuration de Tauri :
|
||||
@@ -33,12 +33,12 @@ Next.js est un framework React. Apprenez-en plus au sujet de Next.js sur https:/
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -48,12 +48,12 @@ Next.js est un framework React. Apprenez-en plus au sujet de Next.js sur https:/
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -63,12 +63,12 @@ Next.js est un framework React. Apprenez-en plus au sujet de Next.js sur https:/
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -81,25 +81,25 @@ Next.js est un framework React. Apprenez-en plus au sujet de Next.js sur https:/
|
||||
// next.conf.ts
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
module.exports = async (phase, { defaultConfig }) => {
|
||||
let internalHost = null;
|
||||
// En mode développement, on utilise "internal-ip" pour se servir des assets.
|
||||
let internalHost = null;
|
||||
// En mode développement, on utilise "internal-ip" pour se servir des assets.
|
||||
|
||||
if (!isProd) {
|
||||
const { internalIpV4 } = await import('internal-ip');
|
||||
internalHost = await internalIpV4();
|
||||
}
|
||||
const nextConfig = {
|
||||
// Assurez-vous que Next.js utilise SSG au lieu de SSR
|
||||
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
|
||||
output: 'export',
|
||||
// Note: Cette fonctionnalité expérimentale est requise pour utiliser NextJS Image en mode SSG.
|
||||
// Voir https://nextjs.org/docs/messages/export-image-api pour des solutions différentes.
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
// Configurez assetPrefix sinon le server ne résoudra pas correctement vos assets.
|
||||
assetPrefix: isProd ? null : `http://${internalHost}:3000`,
|
||||
};
|
||||
return nextConfig;
|
||||
if (!isProd) {
|
||||
const { internalIpV4 } = await import('internal-ip');
|
||||
internalHost = await internalIpV4();
|
||||
}
|
||||
const nextConfig = {
|
||||
// Assurez-vous que Next.js utilise SSG au lieu de SSR
|
||||
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
|
||||
output: 'export',
|
||||
// Note: Cette fonctionnalité expérimentale est requise pour utiliser NextJS Image en mode SSG.
|
||||
// Voir https://nextjs.org/docs/messages/export-image-api pour des solutions différentes.
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
// Configurez assetPrefix sinon le server ne résoudra pas correctement vos assets.
|
||||
assetPrefix: isProd ? null : `http://${internalHost}:3000`,
|
||||
};
|
||||
return nextConfig;
|
||||
};
|
||||
```
|
||||
|
||||
@@ -25,12 +25,12 @@ Apprenez-en plus au sujet de Nuxt sur https://nuxt.com. Ce guide est valable à
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -40,12 +40,12 @@ Apprenez-en plus au sujet de Nuxt sur https://nuxt.com. Ce guide est valable à
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn dev",
|
||||
"beforeBuildCommand": "yarn generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -55,12 +55,12 @@ Apprenez-en plus au sujet de Nuxt sur https://nuxt.com. Ce guide est valable à
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"beforeBuildCommand": "pnpm generate",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../dist"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -72,32 +72,32 @@ Apprenez-en plus au sujet de Nuxt sur https://nuxt.com. Ce guide est valable à
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
// (optionnel) Activez les outils de développement Nuxt
|
||||
devtools: { enabled: true },
|
||||
// Activez SSG
|
||||
ssr: false,
|
||||
vite: {
|
||||
// Meilleur compatibilité pour la sortie "Tauri CLI"
|
||||
clearScreen: false,
|
||||
// Activez les variables d'environnement
|
||||
// Vous pouvez trouver les variables d'environnements additionnelles sur
|
||||
// https://tauri.app/2/reference/environment-variables/
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
server: {
|
||||
// Tauri requiert un port constant
|
||||
strictPort: true,
|
||||
// Active le serveur de développement pour être visible par les autres appareils pour le développement mobile
|
||||
host: '0.0.0.0',
|
||||
hmr: {
|
||||
// Utilisez le websocket pour le rechargement à chaud
|
||||
// (optionnel) Activez les outils de développement Nuxt
|
||||
devtools: { enabled: true },
|
||||
// Activez SSG
|
||||
ssr: false,
|
||||
vite: {
|
||||
// Meilleur compatibilité pour la sortie "Tauri CLI"
|
||||
clearScreen: false,
|
||||
// Activez les variables d'environnement
|
||||
// Vous pouvez trouver les variables d'environnements additionnelles sur
|
||||
// https://tauri.app/2/reference/environment-variables/
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
server: {
|
||||
// Tauri requiert un port constant
|
||||
strictPort: true,
|
||||
// Active le serveur de développement pour être visible par les autres appareils pour le développement mobile
|
||||
host: '0.0.0.0',
|
||||
hmr: {
|
||||
// Utilisez le websocket pour le rechargement à chaud
|
||||
|
||||
protocol: 'ws',
|
||||
// Assurez-vous que ce soit disponible sur le réseau
|
||||
host: '0.0.0.0',
|
||||
// Utilisez un port spécifique pour hmr
|
||||
port: 5183,
|
||||
},
|
||||
},
|
||||
},
|
||||
protocol: 'ws',
|
||||
// Assurez-vous que ce soit disponible sur le réseau
|
||||
host: '0.0.0.0',
|
||||
// Utilisez un port spécifique pour hmr
|
||||
port: 5183,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -27,15 +27,15 @@ Vous devrez utiliser `cargo install --git https://github.com/amrbashir/trunk` po
|
||||
```json
|
||||
// tauri.conf.json
|
||||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "trunk serve",
|
||||
"beforeBuildCommand": "trunk build",
|
||||
"devPath": "http://localhost:8080",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true
|
||||
}
|
||||
"build": {
|
||||
"beforeDevCommand": "trunk serve",
|
||||
"beforeBuildCommand": "trunk build",
|
||||
"devPath": "http://localhost:8080",
|
||||
"distDir": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ Ce guide vous explique comment mettre à niveau votre application basée sur Tau
|
||||
Tauri v2 contient la commande `migrate` qui simplifie votre migration:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install @tauri-apps/cli@latest
|
||||
npm="npm install @tauri-apps/cli@latest
|
||||
npm run tauri migrate"
|
||||
yarn="yarn upgrade @tauri-apps/cli --latest
|
||||
yarn="yarn upgrade @tauri-apps/cli --latest
|
||||
yarn tauri migrate"
|
||||
pnpm="pnpm update @tauri-apps/cli --latest
|
||||
pnpm="pnpm update @tauri-apps/cli --latest
|
||||
pnpm tauri migrate"
|
||||
cargo='cargo install tauri-cli --version "^2.0.0-beta"
|
||||
cargo='cargo install tauri-cli --version "^2.0.0-beta"
|
||||
cargo tauri migrate'
|
||||
/>
|
||||
|
||||
@@ -130,9 +130,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-app": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-app": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -190,9 +190,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-cli": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-cli": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -241,9 +241,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -299,21 +299,21 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-dialog": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-dialog": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
const filePath = await save({
|
||||
filters: [
|
||||
{
|
||||
name: 'Image',
|
||||
extensions: ['png', 'jpeg'],
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
name: 'Image',
|
||||
extensions: ['png', 'jpeg'],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
@@ -365,9 +365,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-fs": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-fs": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -411,16 +411,16 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-global-shortcut": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-global-shortcut": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
import { register } from '@tauri-apps/plugin-global-shortcut';
|
||||
await register('CommandOrControl+Shift+C', () => {
|
||||
console.log('Shortcut triggered');
|
||||
console.log('Shortcut triggered');
|
||||
});
|
||||
```
|
||||
|
||||
@@ -468,16 +468,16 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-http": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-http": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
import { fetch } from '@tauri-apps/plugin-http';
|
||||
const response = await fetch(
|
||||
'https://raw.githubusercontent.com/tauri-apps/tauri/dev/package.json'
|
||||
'https://raw.githubusercontent.com/tauri-apps/tauri/dev/package.json'
|
||||
);
|
||||
```
|
||||
|
||||
@@ -534,9 +534,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-notification": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-notification": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -714,9 +714,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-os": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-os": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -769,9 +769,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-process": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-process": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -828,9 +828,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-shell": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-shell": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1009,9 +1009,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-updater": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-updater": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1021,13 +1021,13 @@ import { relaunch } from '@tauri-apps/plugin-process';
|
||||
|
||||
const update = await check();
|
||||
if (update.response.available) {
|
||||
console.log(
|
||||
`Update to ${update.response.latestVersion} available! Date: ${update.response.date}`
|
||||
);
|
||||
console.log(`Release notes: ${update.response.body}`);
|
||||
await update.downloadAndInstall();
|
||||
// nécéssite le plugin `process`
|
||||
await relaunch();
|
||||
console.log(
|
||||
`Update to ${update.response.latestVersion} available! Date: ${update.response.date}`
|
||||
);
|
||||
console.log(`Release notes: ${update.response.body}`);
|
||||
await update.downloadAndInstall();
|
||||
// nécéssite le plugin `process`
|
||||
await relaunch();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1096,9 +1096,9 @@ fn main() {
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-window": "^2.0.0"
|
||||
}
|
||||
"dependencies": {
|
||||
"@tauri-apps/plugin-window": "^2.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,41 +31,41 @@ import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
|
||||
import Cta from '@fragments/cta.mdx';
|
||||
|
||||
<div class="hero-bg">
|
||||
<div class="bg-logo"></div>
|
||||
<div class="bg-grad"></div>
|
||||
<div class="bg-grad-red"></div>
|
||||
<div class="bg-logo"></div>
|
||||
<div class="bg-grad"></div>
|
||||
<div class="bg-grad-red"></div>
|
||||
</div>
|
||||
|
||||
<div class="lp-cta-card">
|
||||
<Card title="Create a Project" icon="rocket">
|
||||
<Cta />
|
||||
</Card>
|
||||
<Card title="Create a Project" icon="rocket">
|
||||
<Cta />
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<CardGrid>
|
||||
<Card title="Frontend Independent" icon="rocket">
|
||||
Bring your existing web stack to Tauri or start that new dream project.
|
||||
Tauri supports any frontend framework so you don't need to change your
|
||||
stack.
|
||||
</Card>
|
||||
<Card title="Cross Platform" icon="rocket">
|
||||
Build your app for Linux, macOS, Windows, Android and iOS - all from a
|
||||
single codebase.
|
||||
</Card>
|
||||
<Card title="Inter-Process Communication" icon="rocket">
|
||||
Write your frontend in JavaScript, application logic in Rust, and integrate
|
||||
deep into the system with Swift and Kotlin.
|
||||
</Card>
|
||||
<Card title="Maximum Security" icon="rocket">
|
||||
Front-of-mind for the Tauri Team that drives our highest priorities and
|
||||
biggest innovations.
|
||||
</Card>
|
||||
<Card title="Minimal Size" icon="rocket">
|
||||
By using the OS's native web renderer, the size of a Tauri app can be little
|
||||
as 600KB.
|
||||
</Card>
|
||||
<Card title="Powered by Rust" icon="rocket">
|
||||
With performance and security at the center, Rust is the language for the
|
||||
next generation of apps.
|
||||
</Card>
|
||||
<Card title="Frontend Independent" icon="rocket">
|
||||
Bring your existing web stack to Tauri or start that new dream project.
|
||||
Tauri supports any frontend framework so you don't need to change your
|
||||
stack.
|
||||
</Card>
|
||||
<Card title="Cross Platform" icon="rocket">
|
||||
Build your app for Linux, macOS, Windows, Android and iOS - all from a
|
||||
single codebase.
|
||||
</Card>
|
||||
<Card title="Inter-Process Communication" icon="rocket">
|
||||
Write your frontend in JavaScript, application logic in Rust, and integrate
|
||||
deep into the system with Swift and Kotlin.
|
||||
</Card>
|
||||
<Card title="Maximum Security" icon="rocket">
|
||||
Front-of-mind for the Tauri Team that drives our highest priorities and
|
||||
biggest innovations.
|
||||
</Card>
|
||||
<Card title="Minimal Size" icon="rocket">
|
||||
By using the OS's native web renderer, the size of a Tauri app can be little
|
||||
as 600KB.
|
||||
</Card>
|
||||
<Card title="Powered by Rust" icon="rocket">
|
||||
With performance and security at the center, Rust is the language for the
|
||||
next generation of apps.
|
||||
</Card>
|
||||
</CardGrid>
|
||||
|
||||
@@ -13,36 +13,36 @@ Crea un file `.vscode/launch.json` e incolla il contenuto JSON sottostante in es
|
||||
|
||||
```json title=".vscode/launch.json"
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Development Debug",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path=./src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
]
|
||||
},
|
||||
// task for the `beforeDevCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:dev"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Production Debug",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
|
||||
},
|
||||
// task for the `beforeBuildCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:build"
|
||||
}
|
||||
]
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Development Debug",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--manifest-path=./src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
]
|
||||
},
|
||||
// task for the `beforeDevCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:dev"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Tauri Production Debug",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./src-tauri/Cargo.toml"]
|
||||
},
|
||||
// task for the `beforeBuildCommand` if used, must be configured in `.vscode/tasks.json`
|
||||
"preLaunchTask": "ui:build"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -52,29 +52,29 @@ Nota che non utilizza il Tauri CLI, quindi le esclusive funzioni CLI non vengono
|
||||
|
||||
```json title=".vscode/tasks.json"
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "ui:dev",
|
||||
"type": "shell",
|
||||
// `dev` keeps running in the background
|
||||
// ideally you should also configure a `problemMatcher`
|
||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
||||
"isBackground": true,
|
||||
// change this to your `beforeDevCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["dev"]
|
||||
},
|
||||
{
|
||||
"label": "ui:build",
|
||||
"type": "shell",
|
||||
// change this to your `beforeBuildCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["build"]
|
||||
}
|
||||
]
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "ui:dev",
|
||||
"type": "shell",
|
||||
// `dev` keeps running in the background
|
||||
// ideally you should also configure a `problemMatcher`
|
||||
// see https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
|
||||
"isBackground": true,
|
||||
// change this to your `beforeDevCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["dev"]
|
||||
},
|
||||
{
|
||||
"label": "ui:build",
|
||||
"type": "shell",
|
||||
// change this to your `beforeBuildCommand`:
|
||||
"command": "yarn",
|
||||
"args": ["build"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -93,11 +93,11 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/mobile.json"
|
||||
{
|
||||
"$schema": "../gen/schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": ["barcode-scanner:allow-scan", "barcode-scanner:allow-cancel"]
|
||||
"$schema": "../gen/schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": ["barcode-scanner:allow-scan", "barcode-scanner:allow-cancel"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -86,33 +86,33 @@ Under `tauri.conf.json`, you have the following structure to configure the inter
|
||||
|
||||
```json title="src-tauri/tauri.conf.json"
|
||||
{
|
||||
"plugins": {
|
||||
"cli": {
|
||||
"description": "Tauri CLI Plugin Example",
|
||||
"args": [
|
||||
{
|
||||
"short": "v",
|
||||
"name": "verbose",
|
||||
"description": "Verbosity level"
|
||||
}
|
||||
],
|
||||
"subcommands": {
|
||||
"run": {
|
||||
"description": "Run the application",
|
||||
"args": [
|
||||
{
|
||||
"name": "debug",
|
||||
"description": "Run application in debug mode"
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"description": "Run application in release mode"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"plugins": {
|
||||
"cli": {
|
||||
"description": "Tauri CLI Plugin Example",
|
||||
"args": [
|
||||
{
|
||||
"short": "v",
|
||||
"name": "verbose",
|
||||
"description": "Verbosity level"
|
||||
}
|
||||
],
|
||||
"subcommands": {
|
||||
"run": {
|
||||
"description": "Run the application",
|
||||
"args": [
|
||||
{
|
||||
"name": "debug",
|
||||
"description": "Run application in debug mode"
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"description": "Run application in release mode"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -134,18 +134,18 @@ A positional argument is identified by its position in the list of arguments. Wi
|
||||
|
||||
```json title="src-tauri/tauri.conf.json"
|
||||
{
|
||||
"args": [
|
||||
{
|
||||
"name": "source",
|
||||
"index": 1,
|
||||
"takesValue": true
|
||||
},
|
||||
{
|
||||
"name": "destination",
|
||||
"index": 2,
|
||||
"takesValue": true
|
||||
}
|
||||
]
|
||||
"args": [
|
||||
{
|
||||
"name": "source",
|
||||
"index": 1,
|
||||
"takesValue": true
|
||||
},
|
||||
{
|
||||
"name": "destination",
|
||||
"index": 2,
|
||||
"takesValue": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -157,15 +157,15 @@ A named argument is a (key, value) pair where the key identifies the value. With
|
||||
|
||||
```json title="tauri-src/tauri.conf.json"
|
||||
{
|
||||
"args": [
|
||||
{
|
||||
"name": "type",
|
||||
"short": "t",
|
||||
"takesValue": true,
|
||||
"multiple": true,
|
||||
"possibleValues": ["foo", "bar"]
|
||||
}
|
||||
]
|
||||
"args": [
|
||||
{
|
||||
"name": "type",
|
||||
"short": "t",
|
||||
"takesValue": true,
|
||||
"multiple": true,
|
||||
"possibleValues": ["foo", "bar"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -177,12 +177,12 @@ A flag argument is a standalone key whose presence or absence provides informati
|
||||
|
||||
```json title="tauri-src/tauri.conf.json"
|
||||
{
|
||||
"args": [
|
||||
{
|
||||
"name": "verbose",
|
||||
"short": "v"
|
||||
}
|
||||
]
|
||||
"args": [
|
||||
{
|
||||
"name": "verbose",
|
||||
"short": "v"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -222,14 +222,14 @@ import { getMatches } from '@tauri-apps/plugin-cli';
|
||||
|
||||
const matches = await getMatches();
|
||||
if (matches.subcommand?.name === 'run') {
|
||||
// `./your-app run $ARGS` was executed
|
||||
const args = matches.subcommand.matches.args;
|
||||
if (args.debug?.value === true) {
|
||||
// `./your-app run --debug` was executed
|
||||
}
|
||||
if (args.release?.value === true) {
|
||||
// `./your-app run --release` was executed
|
||||
}
|
||||
// `./your-app run $ARGS` was executed
|
||||
const args = matches.subcommand.matches.args;
|
||||
if (args.debug?.value === true) {
|
||||
// `./your-app run --debug` was executed
|
||||
}
|
||||
if (args.release?.value === true) {
|
||||
// `./your-app run --release` was executed
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -272,11 +272,11 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={6}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["cli:default"]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["cli:default"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -102,19 +102,19 @@ For [universal links](https://developer.apple.com/documentation/xcode/allowing-a
|
||||
|
||||
```json title=".well-known/apple-app-site-association"
|
||||
{
|
||||
"applinks": {
|
||||
"details": [
|
||||
{
|
||||
"appIDs": ["$DEVELOPMENT_TEAM_ID.$APP_BUNDLE_ID"],
|
||||
"components": [
|
||||
{
|
||||
"/": "/open/*",
|
||||
"comment": "Matches any URL whose path starts with /open/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"applinks": {
|
||||
"details": [
|
||||
{
|
||||
"appIDs": ["$DEVELOPMENT_TEAM_ID.$APP_BUNDLE_ID"],
|
||||
"components": [
|
||||
{
|
||||
"/": "/open/*",
|
||||
"comment": "Matches any URL whose path starts with /open/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -146,14 +146,14 @@ Under `tauri.conf.json > plugins > deep-link`, configure the domains you want to
|
||||
|
||||
```json title="tauri.conf.json"
|
||||
{
|
||||
"plugins": {
|
||||
"deep-link": {
|
||||
"domains": [
|
||||
{ "host": "your.website.com", "pathPrefix": ["/open"] },
|
||||
{ "host": "another.site.br" }
|
||||
]
|
||||
}
|
||||
}
|
||||
"plugins": {
|
||||
"deep-link": {
|
||||
"domains": [
|
||||
{ "host": "your.website.com", "pathPrefix": ["/open"] },
|
||||
{ "host": "another.site.br" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -168,7 +168,7 @@ The deep-link plugin is available in both JavaScript and Rust.
|
||||
import { onOpenUrl } from '@tauri-apps/plugin-deep-link';
|
||||
|
||||
await onOpenUrl((urls) => {
|
||||
console.log('deep link:', urls);
|
||||
console.log('deep link:', urls);
|
||||
});
|
||||
```
|
||||
|
||||
@@ -205,15 +205,15 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={9}
|
||||
{
|
||||
"$schema": "../gen/schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": [
|
||||
// Usually you will need event:default to listen to the deep-link event
|
||||
"event:default",
|
||||
"deep-link:default"
|
||||
]
|
||||
"$schema": "../gen/schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": [
|
||||
// Usually you will need event:default to listen to the deep-link event
|
||||
"event:default",
|
||||
"deep-link:default"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@ import { ask } from '@tauri-apps/plugin-dialog';
|
||||
|
||||
// Create a Yes/No dialog
|
||||
const answer = await ask('This action cannot be reverted. Are you sure?', {
|
||||
title: 'Tauri',
|
||||
kind: 'warning',
|
||||
title: 'Tauri',
|
||||
kind: 'warning',
|
||||
});
|
||||
|
||||
console.log(answer);
|
||||
@@ -115,8 +115,8 @@ import { confirm } from '@tauri-apps/plugin-dialog';
|
||||
|
||||
// Creates a confirmation Ok/Cancel dialog
|
||||
const confirmation = await confirm(
|
||||
'This action cannot be reverted. Are you sure?',
|
||||
{ title: 'Tauri', kind: 'warning' }
|
||||
'This action cannot be reverted. Are you sure?',
|
||||
{ title: 'Tauri', kind: 'warning' }
|
||||
);
|
||||
|
||||
console.log(confirmation);
|
||||
@@ -149,8 +149,8 @@ import { open } from '@tauri-apps/plugin-dialog';
|
||||
|
||||
// Open a dialog
|
||||
const file = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
multiple: false,
|
||||
directory: false,
|
||||
});
|
||||
console.log(file);
|
||||
// Prints file path and name to the console
|
||||
@@ -166,12 +166,12 @@ Open a file/directory save dialog.
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
// Prompt to save a 'My Filter' with extension .png or .jpeg
|
||||
const path = await save({
|
||||
filters: [
|
||||
{
|
||||
name: 'My Filter',
|
||||
extensions: ['png', 'jpeg'],
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
name: 'My Filter',
|
||||
extensions: ['png', 'jpeg'],
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log(path);
|
||||
// Prints the chosen path
|
||||
|
||||
@@ -133,17 +133,17 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={7-11}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"fs:default",
|
||||
{
|
||||
"identifier": "fs:allow-exists",
|
||||
"allow": [{ "path": "$APPDATA/*" }]
|
||||
}
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"fs:default",
|
||||
{
|
||||
"identifier": "fs:allow-exists",
|
||||
"allow": [{ "path": "$APPDATA/*" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -464,16 +464,16 @@ To allow any `fs` command to access specific scopes:
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" {7-10}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
|
||||
}
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -481,19 +481,19 @@ To allow specific `fs` command to access specific scopes:
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" {7-14}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:allow-rename",
|
||||
"allow": [{ "path": "$HOME/**" }]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:allow-exists",
|
||||
"allow": [{ "path": "$APPDATA/*" }]
|
||||
}
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:allow-rename",
|
||||
"allow": [{ "path": "$HOME/**" }]
|
||||
},
|
||||
{
|
||||
"identifier": "fs:allow-exists",
|
||||
"allow": [{ "path": "$APPDATA/*" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -90,7 +90,7 @@ The global-shortcut plugin is available in both JavaScript and Rust.
|
||||
import { register } from '@tauri-apps/plugin-global-shortcut';
|
||||
|
||||
await register('CommandOrControl+Shift+C', () => {
|
||||
console.log('Shortcut triggered');
|
||||
console.log('Shortcut triggered');
|
||||
});
|
||||
```
|
||||
|
||||
@@ -136,15 +136,15 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={7-9}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"global-shortcut:allow-is-registered",
|
||||
"global-shortcut:allow-register",
|
||||
"global-shortcut:allow-unregister"
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"global-shortcut:allow-is-registered",
|
||||
"global-shortcut:allow-register",
|
||||
"global-shortcut:allow-unregister"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -75,13 +75,13 @@ The http plugin is available in both as an JavaScript API and in Rust as a [reqw
|
||||
```json
|
||||
//src-tauri/capabilities/base.json
|
||||
{
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "http:default",
|
||||
"allow": [{ "url": "https://*.tauri.app" }],
|
||||
"deny": [{ "url": "https://private.tauri.app" }]
|
||||
}
|
||||
]
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "http:default",
|
||||
"allow": [{ "url": "https://*.tauri.app" }],
|
||||
"deny": [{ "url": "https://private.tauri.app" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -94,7 +94,7 @@ The http plugin is available in both as an JavaScript API and in Rust as a [reqw
|
||||
|
||||
// Send a GET request
|
||||
const response = await fetch('http://test.tauri.app/data.json', {
|
||||
method: 'GET',
|
||||
method: 'GET',
|
||||
});
|
||||
console.log(response.status); // e.g. 200
|
||||
console.log(response.statusText); // e.g. "OK"
|
||||
|
||||
@@ -17,16 +17,16 @@ Tauri comes with extensibility in mind. On this page you'll find:
|
||||
- **[Community Resources](#community-resources)**: More plugins and recipes built by the Tauri community
|
||||
|
||||
<Search>
|
||||
## Features
|
||||
<FeaturesList />
|
||||
## Community Resources
|
||||
<LinkCard
|
||||
title="Have something to share?"
|
||||
description="Open a pull request to show us your amazing resource."
|
||||
href="https://github.com/tauri-apps/awesome-tauri/pulls"
|
||||
/>
|
||||
### Plugins
|
||||
<AwesomeTauri section="plugins-no-official" />
|
||||
### Integrations
|
||||
<AwesomeTauri section="integrations" />
|
||||
## Features
|
||||
<FeaturesList />
|
||||
## Community Resources
|
||||
<LinkCard
|
||||
title="Have something to share?"
|
||||
description="Open a pull request to show us your amazing resource."
|
||||
href="https://github.com/tauri-apps/awesome-tauri/pulls"
|
||||
/>
|
||||
### Plugins
|
||||
<AwesomeTauri section="plugins-no-official" />
|
||||
### Integrations
|
||||
<AwesomeTauri section="integrations" />
|
||||
</Search>
|
||||
|
||||
@@ -132,11 +132,11 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={6}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["log:default"]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["log:default"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ Follow these steps to send a notification:
|
||||
|
||||
```js
|
||||
import {
|
||||
isPermissionGranted,
|
||||
requestPermission,
|
||||
sendNotification,
|
||||
isPermissionGranted,
|
||||
requestPermission,
|
||||
sendNotification,
|
||||
} from '@tauri-apps/plugin-notification';
|
||||
|
||||
// Do you have permission to send a notification?
|
||||
@@ -102,13 +102,13 @@ let permissionGranted = await isPermissionGranted();
|
||||
|
||||
// If not we need to request it
|
||||
if (!permissionGranted) {
|
||||
const permission = await requestPermission();
|
||||
permissionGranted = permission === 'granted';
|
||||
const permission = await requestPermission();
|
||||
permissionGranted = permission === 'granted';
|
||||
}
|
||||
|
||||
// Once permission has been granted we can send the notification
|
||||
if (permissionGranted) {
|
||||
sendNotification({ title: 'Tauri', body: 'Tauri is awesome!' });
|
||||
sendNotification({ title: 'Tauri', body: 'Tauri is awesome!' });
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -85,8 +85,8 @@ The shell plugin is available in both JavaScript and Rust.
|
||||
import { Command } from '@tauri-apps/plugin-shell';
|
||||
|
||||
let result = await Command.create('exec-sh', [
|
||||
'-c',
|
||||
"echo 'Hello World!'",
|
||||
'-c',
|
||||
"echo 'Hello World!'",
|
||||
]).execute();
|
||||
console.log(result);
|
||||
```
|
||||
@@ -125,28 +125,28 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={6-23}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "shell:allow-execute",
|
||||
"allow": [
|
||||
{
|
||||
"name": "exec-sh",
|
||||
"cmd": "sh",
|
||||
"args": [
|
||||
"-c",
|
||||
{
|
||||
"validator": "\\S+"
|
||||
}
|
||||
],
|
||||
"sidecar": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "shell:allow-execute",
|
||||
"allow": [
|
||||
{
|
||||
"name": "exec-sh",
|
||||
"cmd": "sh",
|
||||
"args": [
|
||||
"-c",
|
||||
{
|
||||
"validator": "\\S+"
|
||||
}
|
||||
],
|
||||
"sidecar": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -44,20 +44,20 @@ branch = "v2"
|
||||
Then, you have to add JavaScript Guest bindings using your preferred JavaScript package manager.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="npm.io">
|
||||
<CommandTabs
|
||||
npm="npm add @tauri-apps/plugin-sql"
|
||||
yarn="yarn add @tauri-apps/plugin-sql"
|
||||
pnpm="pnpm add @tauri-apps/plugin-sql"
|
||||
/>
|
||||
</TabItem>
|
||||
<TabItem label="Git">
|
||||
<CommandTabs
|
||||
npm="npm add https://github.com/tauri-apps/tauri-plugin-sql#v2"
|
||||
yarn="yarn add https://github.com/tauri-apps/tauri-plugin-sql#v2"
|
||||
pnpm="pnpm add https://github.com/tauri-apps/tauri-plugin-sql#v2"
|
||||
/>
|
||||
</TabItem>
|
||||
<TabItem label="npm.io">
|
||||
<CommandTabs
|
||||
npm="npm add @tauri-apps/plugin-sql"
|
||||
yarn="yarn add @tauri-apps/plugin-sql"
|
||||
pnpm="pnpm add @tauri-apps/plugin-sql"
|
||||
/>
|
||||
</TabItem>
|
||||
<TabItem label="Git">
|
||||
<CommandTabs
|
||||
npm="npm add https://github.com/tauri-apps/tauri-plugin-sql#v2"
|
||||
yarn="yarn add https://github.com/tauri-apps/tauri-plugin-sql#v2"
|
||||
pnpm="pnpm add https://github.com/tauri-apps/tauri-plugin-sql#v2"
|
||||
/>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Usage
|
||||
@@ -230,11 +230,11 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={7-8}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["sql:allow-load", "sql:allow-execute"]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["sql:allow-load", "sql:allow-execute"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -146,16 +146,16 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={6-11}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"store:allow-get",
|
||||
"store:allow-set",
|
||||
"store:allow-save",
|
||||
"store:allow-load"
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"store:allow-get",
|
||||
"store:allow-set",
|
||||
"store:allow-save",
|
||||
"store:allow-load"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -13,5 +13,5 @@ import PluginLinks from '@components/PluginLinks.astro';
|
||||
<PluginLinks plugin="updater" />
|
||||
|
||||
<Stub>
|
||||
Based on https://github.com/tauri-apps/plugins-workspace/tree/plugins/updater
|
||||
Based on https://github.com/tauri-apps/plugins-workspace/tree/plugins/updater
|
||||
</Stub>
|
||||
|
||||
@@ -74,10 +74,10 @@ Here's an example of how you can use the plugin to upload and download files:
|
||||
import { upload } from '@tauri-apps/plugin-upload';
|
||||
|
||||
upload(
|
||||
'https://example.com/file-upload',
|
||||
'./path/to/my/file.txt',
|
||||
(progress, total) => console.log(`Uploaded ${progress} of ${total} bytes`), // a callback that will be called with the upload progress
|
||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
||||
'https://example.com/file-upload',
|
||||
'./path/to/my/file.txt',
|
||||
(progress, total) => console.log(`Uploaded ${progress} of ${total} bytes`), // a callback that will be called with the upload progress
|
||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
||||
);
|
||||
```
|
||||
|
||||
@@ -85,9 +85,9 @@ upload(
|
||||
import { download } from '@tauri-apps/plugin-upload';
|
||||
|
||||
download(
|
||||
'https://example.com/file-download-link',
|
||||
'./path/to/save/my/file.txt',
|
||||
(progress, total) => console.log(`Downloaded ${progress} of ${total} bytes`), // a callback that will be called with the download progress
|
||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
||||
'https://example.com/file-download-link',
|
||||
'./path/to/save/my/file.txt',
|
||||
(progress, total) => console.log(`Downloaded ${progress} of ${total} bytes`), // a callback that will be called with the download progress
|
||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
||||
);
|
||||
```
|
||||
|
||||
@@ -87,7 +87,7 @@ import WebSocket from '@tauri-apps/plugin-websocket';
|
||||
const ws = await WebSocket.connect('ws://127.0.0.1:8080');
|
||||
|
||||
ws.addListener((msg) => {
|
||||
console.log('Received Message:', msg);
|
||||
console.log('Received Message:', msg);
|
||||
});
|
||||
|
||||
await ws.send('Hello World!');
|
||||
@@ -103,11 +103,11 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={6}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["websocket:default"]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["websocket:default"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -57,11 +57,11 @@ See [Access Control List](/reference/acl/) for more information.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json" ins={7-8}
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["window:default", "window:allow-start-dragging"]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["window:default", "window:allow-start-dragging"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -80,27 +80,27 @@ Add this CSS sample to keep it at the top of the screen and style the buttons:
|
||||
|
||||
```css
|
||||
.titlebar {
|
||||
height: 30px;
|
||||
background: #329ea3;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
background: #329ea3;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.titlebar-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.titlebar-button:hover {
|
||||
background: #5bbec3;
|
||||
background: #5bbec3;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -110,21 +110,21 @@ Put this at the top of your `<body>` tag:
|
||||
|
||||
```html
|
||||
<div data-tauri-drag-region class="titlebar">
|
||||
<div class="titlebar-button" id="titlebar-minimize">
|
||||
<img
|
||||
src="https://api.iconify.design/mdi:window-minimize.svg"
|
||||
alt="minimize"
|
||||
/>
|
||||
</div>
|
||||
<div class="titlebar-button" id="titlebar-maximize">
|
||||
<img
|
||||
src="https://api.iconify.design/mdi:window-maximize.svg"
|
||||
alt="maximize"
|
||||
/>
|
||||
</div>
|
||||
<div class="titlebar-button" id="titlebar-close">
|
||||
<img src="https://api.iconify.design/mdi:close.svg" alt="close" />
|
||||
</div>
|
||||
<div class="titlebar-button" id="titlebar-minimize">
|
||||
<img
|
||||
src="https://api.iconify.design/mdi:window-minimize.svg"
|
||||
alt="minimize"
|
||||
/>
|
||||
</div>
|
||||
<div class="titlebar-button" id="titlebar-maximize">
|
||||
<img
|
||||
src="https://api.iconify.design/mdi:window-maximize.svg"
|
||||
alt="maximize"
|
||||
/>
|
||||
</div>
|
||||
<div class="titlebar-button" id="titlebar-close">
|
||||
<img src="https://api.iconify.design/mdi:close.svg" alt="close" />
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -140,14 +140,14 @@ import { Window } from '@tauri-apps/api/window';
|
||||
const appWindow = new Window('main');
|
||||
|
||||
document
|
||||
.getElementById('titlebar-minimize')
|
||||
?.addEventListener('click', () => appWindow.minimize());
|
||||
.getElementById('titlebar-minimize')
|
||||
?.addEventListener('click', () => appWindow.minimize());
|
||||
document
|
||||
.getElementById('titlebar-maximize')
|
||||
?.addEventListener('click', () => appWindow.toggleMaximize());
|
||||
.getElementById('titlebar-maximize')
|
||||
?.addEventListener('click', () => appWindow.toggleMaximize());
|
||||
document
|
||||
.getElementById('titlebar-close')
|
||||
?.addEventListener('click', () => appWindow.close());
|
||||
.getElementById('titlebar-close')
|
||||
?.addEventListener('click', () => appWindow.close());
|
||||
```
|
||||
|
||||
### (macOS) Transparent Titlebar with Custom Window Background Color
|
||||
|
||||
@@ -35,10 +35,10 @@ Use your project's package manager to add the dependency:
|
||||
{' '}
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri add window-state"
|
||||
yarn="yarn run tauri add window-state"
|
||||
pnpm="pnpm tauri add window-state"
|
||||
cargo="cargo tauri add window-state"
|
||||
npm="npm run tauri add window-state"
|
||||
yarn="yarn run tauri add window-state"
|
||||
pnpm="pnpm tauri add window-state"
|
||||
cargo="cargo tauri add window-state"
|
||||
/>
|
||||
|
||||
</TabItem>
|
||||
@@ -98,8 +98,8 @@ Similarly you can manually restore a window's state from disk:
|
||||
|
||||
```javascript
|
||||
import {
|
||||
restoreStateCurrent,
|
||||
StateFlags,
|
||||
restoreStateCurrent,
|
||||
StateFlags,
|
||||
} from '@tauri-apps/plugin-window-state';
|
||||
|
||||
restoreStateCurrent(StateFlags.ALL);
|
||||
|
||||
@@ -20,20 +20,20 @@ The following JSON defines a capability that enables default functionality for c
|
||||
|
||||
```json title="src-tauri/capabilities/main.json
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
"window:allow-set-title"
|
||||
]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
"window:allow-set-title"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -47,11 +47,11 @@ For example, let's define a capability for desktop. Note it enables permissions
|
||||
|
||||
```json title="src-tauri/capabilities/desktop.json
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "desktop-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["linux", "macOS", "windows"],
|
||||
"permissions": ["global-shortcut:allow-register"]
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "desktop-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["linux", "macOS", "windows"],
|
||||
"permissions": ["global-shortcut:allow-register"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -59,15 +59,15 @@ And define a capability for mobile. Note it enables permissions on plugins that
|
||||
|
||||
```json title="src-tauri/capabilities/mobile.json
|
||||
{
|
||||
"$schema": "../gen/schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": [
|
||||
"nfc:allow-scan",
|
||||
"biometric:allow-authenticate",
|
||||
"barcode-scanner:allow-scan"
|
||||
]
|
||||
"$schema": "../gen/schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": [
|
||||
"nfc:allow-scan",
|
||||
"biometric:allow-authenticate",
|
||||
"barcode-scanner:allow-scan"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -81,11 +81,11 @@ In the example above we defined specific capabilities for desktop and mobile, an
|
||||
|
||||
```json title="src-tauri/capabilities/linux.json
|
||||
{
|
||||
"$schema": "../gen/schemas/linux-schema.json",
|
||||
"identifier": "linux-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": ["dbus::call"]
|
||||
"$schema": "../gen/schemas/linux-schema.json",
|
||||
"identifier": "linux-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": ["dbus::call"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -115,12 +115,12 @@ Let's study some examples for official plugins:
|
||||
|
||||
```json title="src-tauri/capabilities/base.json
|
||||
{
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
|
||||
}
|
||||
]
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -132,12 +132,12 @@ Let's study some examples for official plugins:
|
||||
|
||||
```json title="src-tauri/capabilities/base.json
|
||||
{
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:allow-rename",
|
||||
"allow": [{ "path": "$HOME/**" }]
|
||||
}
|
||||
]
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "fs:allow-rename",
|
||||
"allow": [{ "path": "$HOME/**" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -145,13 +145,13 @@ Let's study some examples for official plugins:
|
||||
|
||||
```json title="src-tauri/capabilities/base.json
|
||||
{
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "http:default",
|
||||
"allow": [{ "url": "https://*.tauri.app" }],
|
||||
"deny": [{ "url": "https://private.tauri.app" }]
|
||||
}
|
||||
]
|
||||
"permissions": [
|
||||
{
|
||||
"identifier": "http:default",
|
||||
"allow": [{ "url": "https://*.tauri.app" }],
|
||||
"deny": [{ "url": "https://private.tauri.app" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ The Tauri command line interface (CLI) is the way to interact with Tauri through
|
||||
You can add the Tauri CLI to your current project using your package manager of choice:
|
||||
|
||||
<CommandTabs
|
||||
npm="npm install --save-dev @tauri-apps/cli@next"
|
||||
yarn="yarn add -D @tauri-apps/cli@next"
|
||||
pnpm="pnpm add -D @tauri-apps/cli@next"
|
||||
cargo='cargo install tauri-cli --version "^2.0.0-beta"'
|
||||
npm="npm install --save-dev @tauri-apps/cli@next"
|
||||
yarn="yarn add -D @tauri-apps/cli@next"
|
||||
pnpm="pnpm add -D @tauri-apps/cli@next"
|
||||
cargo='cargo install tauri-cli --version "^2.0.0-beta"'
|
||||
/>
|
||||
{/* TODO: 2.0 */}
|
||||
|
||||
@@ -47,10 +47,10 @@ For CLI commands related to developing plugins visit the [Develop a Tauri Plugin
|
||||
## `build`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri build"
|
||||
yarn="yarn tauri build"
|
||||
pnpm="pnpm tauri build"
|
||||
cargo="cargo tauri build"
|
||||
npm="npm run tauri build"
|
||||
yarn="yarn tauri build"
|
||||
pnpm="pnpm tauri build"
|
||||
cargo="cargo tauri build"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -94,10 +94,10 @@ Options:
|
||||
## `dev`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri dev"
|
||||
yarn="yarn tauri dev"
|
||||
pnpm="pnpm tauri dev"
|
||||
cargo="cargo tauri dev"
|
||||
npm="npm run tauri dev"
|
||||
yarn="yarn tauri dev"
|
||||
pnpm="pnpm tauri dev"
|
||||
cargo="cargo tauri dev"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -131,10 +131,10 @@ If you have entered a command to the `build.beforeDevCommand` property, this one
|
||||
## `icon`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri icon"
|
||||
yarn="yarn tauri icon"
|
||||
pnpm="pnpm tauri icon"
|
||||
cargo="cargo tauri icon"
|
||||
npm="npm run tauri icon"
|
||||
yarn="yarn tauri icon"
|
||||
pnpm="pnpm tauri icon"
|
||||
cargo="cargo tauri icon"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -157,10 +157,10 @@ Options:
|
||||
## `info`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri info"
|
||||
yarn="yarn tauri info"
|
||||
pnpm="pnpm tauri info"
|
||||
cargo="cargo tauri info"
|
||||
npm="npm run tauri info"
|
||||
yarn="yarn tauri info"
|
||||
pnpm="pnpm tauri info"
|
||||
cargo="cargo tauri info"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -180,10 +180,10 @@ Options:
|
||||
## `init`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri init"
|
||||
yarn="yarn tauri init"
|
||||
pnpm="pnpm tauri init"
|
||||
cargo="cargo tauri init"
|
||||
npm="npm run tauri init"
|
||||
yarn="yarn tauri init"
|
||||
pnpm="pnpm tauri init"
|
||||
cargo="cargo tauri init"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -225,10 +225,10 @@ Options:
|
||||
## `add`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri add"
|
||||
yarn="yarn tauri add"
|
||||
pnpm="pnpm tauri add"
|
||||
cargo="cargo tauri add"
|
||||
npm="npm run tauri add"
|
||||
yarn="yarn tauri add"
|
||||
pnpm="pnpm tauri add"
|
||||
cargo="cargo tauri add"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -251,10 +251,10 @@ Options:
|
||||
## `signer`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri signer"
|
||||
yarn="yarn tauri signer"
|
||||
pnpm="pnpm tauri signer"
|
||||
cargo="cargo tauri signer"
|
||||
npm="npm run tauri signer"
|
||||
yarn="yarn tauri signer"
|
||||
pnpm="pnpm tauri signer"
|
||||
cargo="cargo tauri signer"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -276,10 +276,10 @@ Options:
|
||||
## `completions`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri completions"
|
||||
yarn="yarn tauri completions"
|
||||
pnpm="pnpm tauri completions"
|
||||
cargo="cargo tauri completions"
|
||||
npm="npm run tauri completions"
|
||||
yarn="yarn tauri completions"
|
||||
pnpm="pnpm tauri completions"
|
||||
cargo="cargo tauri completions"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -432,10 +432,10 @@ Add-Content -Path $profile -Value '& "$PSScriptRoot\_tauri.ps1"'
|
||||
## `android`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri android"
|
||||
yarn="yarn tauri android"
|
||||
pnpm="pnpm tauri android"
|
||||
cargo="cargo tauri android"
|
||||
npm="npm run tauri android"
|
||||
yarn="yarn tauri android"
|
||||
pnpm="pnpm tauri android"
|
||||
cargo="cargo tauri android"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -459,10 +459,10 @@ Options:
|
||||
## `ios`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri ios"
|
||||
yarn="yarn tauri ios"
|
||||
pnpm="pnpm tauri ios"
|
||||
cargo="cargo tauri ios"
|
||||
npm="npm run tauri ios"
|
||||
yarn="yarn tauri ios"
|
||||
pnpm="pnpm tauri ios"
|
||||
cargo="cargo tauri ios"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -486,10 +486,10 @@ Options:
|
||||
## `migrate`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri migrate"
|
||||
yarn="yarn tauri migrate"
|
||||
pnpm="pnpm tauri migrate"
|
||||
cargo="cargo tauri migrate"
|
||||
npm="npm run tauri migrate"
|
||||
yarn="yarn tauri migrate"
|
||||
pnpm="pnpm tauri migrate"
|
||||
cargo="cargo tauri migrate"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -506,10 +506,10 @@ Options:
|
||||
## `permission`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm tauri permission"
|
||||
yarn="yarn tauri permission"
|
||||
pnpm="pnpm tauri permission"
|
||||
cargo="cargo tauri permission"
|
||||
npm="npm tauri permission"
|
||||
yarn="yarn tauri permission"
|
||||
pnpm="pnpm tauri permission"
|
||||
cargo="cargo tauri permission"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -591,10 +591,10 @@ Options:
|
||||
## `capability`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm tauri capability"
|
||||
yarn="yarn tauri capability"
|
||||
pnpm="pnpm tauri capability"
|
||||
cargo="cargo tauri capability"
|
||||
npm="npm tauri capability"
|
||||
yarn="yarn tauri capability"
|
||||
pnpm="pnpm tauri capability"
|
||||
cargo="cargo tauri capability"
|
||||
/>
|
||||
|
||||
```
|
||||
@@ -634,10 +634,10 @@ Options:
|
||||
## `help`
|
||||
|
||||
<CommandTabs
|
||||
npm="npm run tauri help"
|
||||
yarn="yarn tauri help"
|
||||
pnpm="pnpm tauri help"
|
||||
cargo="cargo tauri help"
|
||||
npm="npm run tauri help"
|
||||
yarn="yarn tauri help"
|
||||
pnpm="pnpm tauri help"
|
||||
cargo="cargo tauri help"
|
||||
/>
|
||||
|
||||
```
|
||||
|
||||
@@ -43,20 +43,20 @@ for core plugins and the `window.setTitle` API.
|
||||
|
||||
```json title="src-tauri/capabilities/main.json
|
||||
{
|
||||
"$schema": "./schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
"window:allow-set-title"
|
||||
]
|
||||
"$schema": "./schemas/desktop-schema.json",
|
||||
"identifier": "main-capability",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
"app:default",
|
||||
"resources:default",
|
||||
"menu:default",
|
||||
"tray:default",
|
||||
"window:allow-set-title"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -72,11 +72,11 @@ capability files in the `capabilities` directory.
|
||||
|
||||
```json title=src-tauri/tauri.conf.json
|
||||
{
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": ["my-capability", "main-capability"]
|
||||
}
|
||||
}
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": ["my-capability", "main-capability"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -84,19 +84,19 @@ Inline capabilities can be mixed with pre-defined capabilities.
|
||||
|
||||
```json title=src-tauri/tauri.conf.json
|
||||
{
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": [
|
||||
{
|
||||
"identifier": "my-capability",
|
||||
"description": "My application capability used for all windows",
|
||||
"windows": ["*"],
|
||||
"permissions": ["fs:default", "allow-home-read-extended"]
|
||||
},
|
||||
"my-second-capability"
|
||||
]
|
||||
}
|
||||
}
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": [
|
||||
{
|
||||
"identifier": "my-capability",
|
||||
"description": "My application capability used for all windows",
|
||||
"windows": ["*"],
|
||||
"permissions": ["fs:default", "allow-home-read-extended"]
|
||||
},
|
||||
"my-second-capability"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -111,11 +111,11 @@ Note it enables permissions on plugins that are only available on desktop:
|
||||
|
||||
```json title="src-tauri/capabilities/desktop.json
|
||||
{
|
||||
"$schema": "./schemas/desktop-schema.json",
|
||||
"identifier": "desktop-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["linux", "macOS", "windows"],
|
||||
"permissions": ["global-shortcut:allow-register"]
|
||||
"$schema": "./schemas/desktop-schema.json",
|
||||
"identifier": "desktop-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["linux", "macOS", "windows"],
|
||||
"permissions": ["global-shortcut:allow-register"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -124,15 +124,15 @@ Note it enables permissions on plugins that are only available on mobile:
|
||||
|
||||
```json title="src-tauri/capabilities/mobile.json
|
||||
{
|
||||
"$schema": "./schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": [
|
||||
"nfc:allow-scan",
|
||||
"biometric:allow-authenticate",
|
||||
"barcode-scanner:allow-scan"
|
||||
]
|
||||
"$schema": "./schemas/mobile-schema.json",
|
||||
"identifier": "mobile-capability",
|
||||
"windows": ["main"],
|
||||
"platforms": ["iOS", "android"],
|
||||
"permissions": [
|
||||
"nfc:allow-scan",
|
||||
"biometric:allow-authenticate",
|
||||
"barcode-scanner:allow-scan"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user