This commit is contained in:
Ayres Vitor
2025-07-29 23:36:47 -03:00
parent 39e3c75e3e
commit 495ec4bc76
8 changed files with 431 additions and 435 deletions

View File

@@ -7,6 +7,7 @@
# Generated reference docs
src/content/docs/reference
src/content/docs/release
# Git Modules
packages/tauri

View File

@@ -1,79 +1,79 @@
---
const GITHUB_TOKEN = import.meta.env.GITHUB_TOKEN;
let gitHubSponsors = [];
export type Sponsor = {
id: string;
name: string;
avatarUrl: string;
profileUrl?: string;
tier?: Tier;
};
export const IMAGE_DIMENSION = 64;
const IS_PRODUCTION = import.meta.env.NETLIFY != undefined;
export type Tier = 'platinum' | 'gold' | 'silver' | 'bronze';
if (GITHUB_TOKEN || IS_PRODUCTION) {
gitHubSponsors = await getGitHubSponsors();
}
const gitHubSponsorsLoaded = gitHubSponsors.length > 0;
async function getGitHubSponsors(): Promise<any[]> {
if (!GITHUB_TOKEN)
throw Error('Error generator sponsor list: GITHUB_TOKEN is invalid or not set');
// https://docs.github.com/graphql
const gitHubQuery = `query {
organization(login:"tauri-apps") {
sponsors(first: 100) {
nodes {
... on Actor {
login,
avatarUrl(size: ${IMAGE_DIMENSION})
}
}
}
}
}`;
const gitHubSponsorResponse = await fetch('https://api.github.com/graphql', {
method: 'POST',
body: JSON.stringify({ query: gitHubQuery }),
headers: {
Authorization: `bearer ${GITHUB_TOKEN}`,
},
});
if (!gitHubSponsorResponse.ok)
throw Error(
`There was an issue with the GitHub sponsors query: ${gitHubSponsorResponse.status}: ${gitHubSponsorResponse.statusText}`
);
const gitHubSponsorData = (await gitHubSponsorResponse.json()).data;
return gitHubSponsorData.organization.sponsors.nodes
.map(
(node: any): Sponsor => ({
id: node.login,
name: node.login,
avatarUrl: node.avatarUrl,
})
)
.sort((a: Sponsor, b: Sponsor) => a.name.localeCompare(b.name));
}
---
{!gitHubSponsorsLoaded && <p>_error_loading_</p>}
{
gitHubSponsorsLoaded && (
<div class="sponsor-grid github">
{gitHubSponsors.map((sponsor) => (
<div class="sponsor" />
))}
</div>
)
}
---
const GITHUB_TOKEN = import.meta.env.GITHUB_TOKEN;
let gitHubSponsors = [];
export type Sponsor = {
id: string;
name: string;
avatarUrl: string;
profileUrl?: string;
tier?: Tier;
};
export const IMAGE_DIMENSION = 64;
const IS_PRODUCTION = import.meta.env.NETLIFY != undefined;
export type Tier = 'platinum' | 'gold' | 'silver' | 'bronze';
if (GITHUB_TOKEN || IS_PRODUCTION) {
gitHubSponsors = await getGitHubSponsors();
}
const gitHubSponsorsLoaded = gitHubSponsors.length > 0;
async function getGitHubSponsors(): Promise<any[]> {
if (!GITHUB_TOKEN)
throw Error('Error generator sponsor list: GITHUB_TOKEN is invalid or not set');
// https://docs.github.com/graphql
const gitHubQuery = `query {
organization(login:"tauri-apps") {
sponsors(first: 100) {
nodes {
... on Actor {
login,
avatarUrl(size: ${IMAGE_DIMENSION})
}
}
}
}
}`;
const gitHubSponsorResponse = await fetch('https://api.github.com/graphql', {
method: 'POST',
body: JSON.stringify({ query: gitHubQuery }),
headers: {
Authorization: `bearer ${GITHUB_TOKEN}`,
},
});
if (!gitHubSponsorResponse.ok)
throw Error(
`There was an issue with the GitHub sponsors query: ${gitHubSponsorResponse.status}: ${gitHubSponsorResponse.statusText}`
);
const gitHubSponsorData = (await gitHubSponsorResponse.json()).data;
return gitHubSponsorData.organization.sponsors.nodes
.map(
(node: any): Sponsor => ({
id: node.login,
name: node.login,
avatarUrl: node.avatarUrl,
})
)
.sort((a: Sponsor, b: Sponsor) => a.name.localeCompare(b.name));
}
---
{!gitHubSponsorsLoaded && <p>_error_loading_</p>}
{
gitHubSponsorsLoaded && (
<div class="sponsor-grid github">
{gitHubSponsors.map((sponsor) => (
<div class="sponsor" />
))}
</div>
)
}

View File

@@ -1,122 +1,122 @@
---
import { Image } from 'astro:assets';
import { IMAGE_DIMENSION, type Sponsor } from './_types';
interface Props {
sponsor: Sponsor;
needComma?: boolean;
}
const { sponsor, needComma } = Astro.props;
const roundingStyle: Record<Sponsor['type'], string> = {
ORGANIZATION: 'rounded-lg',
INDIVIDUAL: 'rounded-full',
};
---
{
(sponsor.tier === 'platinum' || sponsor.tier === 'gold' || sponsor.tier === 'silver') && (
<div class="image-container">
<a href={sponsor.profileUrl} target="_blank" rel="noopener noreferrer">
<Image
src={sponsor.avatarUrl}
alt={sponsor.name}
width={IMAGE_DIMENSION}
height={IMAGE_DIMENSION}
class={`image ${sponsor.tier} ${roundingStyle[sponsor.type]}`}
/>
</a>
</div>
)
}
{
!sponsor.tier && sponsor.avatarUrl && (
<div class="image-container">
fallback
<a
href={sponsor.profileUrl || `https://github.com/${sponsor.name}`}
target="_blank"
rel="noopener noreferrer"
>
<Image
src={sponsor.avatarUrl}
alt={sponsor.name}
width={IMAGE_DIMENSION}
height={IMAGE_DIMENSION}
class={`image ${roundingStyle[sponsor.type]}`}
/>
</a>
</div>
)
}
{
sponsor.tier === 'bronze' && (
<>
<a href={sponsor.profileUrl} target="_blank" rel="noopener noreferrer" class="bronze-sponsor">
{sponsor.name}
</a>
{needComma && <span class="bronze-separator">, </span>}
</>
)
}
<style define:vars={{ dimension: `${IMAGE_DIMENSION}px` }}>
.rounded-full {
border-radius: 50%;
}
.rounded-lg {
border-radius: 8px;
}
.image {
object-fit: cover;
background-color: white;
border: 2px solid var(--sl-color-gray-1);
}
.image-container {
aspect-ratio: 1;
width: fit-content;
display: inline-flex;
align-items: center;
justify-content: center;
transition: transform 1s ease;
}
.image-container:hover {
transform: scale(1.1);
}
.platinum {
width: 8rem;
height: 8rem;
}
.gold {
width: 6rem;
height: 6rem;
}
.silver {
width: 4rem;
height: 4rem;
}
.bronze-sponsor {
filter: brightness(0.8);
text-decoration: none;
}
.bronze-sponsor:hover {
filter: brightness(1.2);
text-decoration: underline;
}
.bronze-separator {
color: var(--sl-color-text-muted);
padding-inline-end: 2px;
}
</style>
---
import { Image } from 'astro:assets';
import { IMAGE_DIMENSION, type Sponsor } from './_types';
interface Props {
sponsor: Sponsor;
needComma?: boolean;
}
const { sponsor, needComma } = Astro.props;
const roundingStyle: Record<Sponsor['type'], string> = {
ORGANIZATION: 'rounded-lg',
INDIVIDUAL: 'rounded-full',
};
---
{
(sponsor.tier === 'platinum' || sponsor.tier === 'gold' || sponsor.tier === 'silver') && (
<div class="image-container">
<a href={sponsor.profileUrl} target="_blank" rel="noopener noreferrer">
<Image
src={sponsor.avatarUrl}
alt={sponsor.name}
width={IMAGE_DIMENSION}
height={IMAGE_DIMENSION}
class={`image ${sponsor.tier} ${roundingStyle[sponsor.type]}`}
/>
</a>
</div>
)
}
{
!sponsor.tier && sponsor.avatarUrl && (
<div class="image-container">
fallback
<a
href={sponsor.profileUrl || `https://github.com/${sponsor.name}`}
target="_blank"
rel="noopener noreferrer"
>
<Image
src={sponsor.avatarUrl}
alt={sponsor.name}
width={IMAGE_DIMENSION}
height={IMAGE_DIMENSION}
class={`image ${roundingStyle[sponsor.type]}`}
/>
</a>
</div>
)
}
{
sponsor.tier === 'bronze' && (
<>
<a href={sponsor.profileUrl} target="_blank" rel="noopener noreferrer" class="bronze-sponsor">
{sponsor.name}
</a>
{needComma && <span class="bronze-separator">, </span>}
</>
)
}
<style define:vars={{ dimension: `${IMAGE_DIMENSION}px` }}>
.rounded-full {
border-radius: 50%;
}
.rounded-lg {
border-radius: 8px;
}
.image {
object-fit: cover;
background-color: white;
border: 2px solid var(--sl-color-gray-1);
}
.image-container {
aspect-ratio: 1;
width: fit-content;
display: inline-flex;
align-items: center;
justify-content: center;
transition: transform 1s ease;
}
.image-container:hover {
transform: scale(1.1);
}
.platinum {
width: 8rem;
height: 8rem;
}
.gold {
width: 6rem;
height: 6rem;
}
.silver {
width: 4rem;
height: 4rem;
}
.bronze-sponsor {
filter: brightness(0.8);
text-decoration: none;
}
.bronze-sponsor:hover {
filter: brightness(1.2);
text-decoration: underline;
}
.bronze-separator {
color: var(--sl-color-text-muted);
padding-inline-end: 2px;
}
</style>

View File

@@ -1,11 +1,11 @@
export type Sponsor = {
id: string;
name: string;
avatarUrl: string;
profileUrl?: string;
tier?: Tier;
type: 'ORGANIZATION' | 'INDIVIDUAL';
};
export type Tier = 'platinum' | 'gold' | 'silver' | 'bronze';
export const IMAGE_DIMENSION = 256;
export type Sponsor = {
id: string;
name: string;
avatarUrl: string;
profileUrl?: string;
tier?: Tier;
type: 'ORGANIZATION' | 'INDIVIDUAL';
};
export type Tier = 'platinum' | 'gold' | 'silver' | 'bronze';
export const IMAGE_DIMENSION = 256;

View File

@@ -1,62 +1,62 @@
---
import { Image } from 'astro:assets';
interface ServiceProvider {
name: string;
image?: string;
url: string;
}
const serviceProviders: ServiceProvider[] = [
{
name: 'Netlify',
url: 'https://www.netlify.com/',
},
{
name: 'Meilisearch',
url: 'https://www.meilisearch.com/',
},
];
---
{
serviceProviders.length > 0 && (
<div class="service-providers">
{serviceProviders.map((provider) => (
<div class="service-provider not-content">
<a href={provider.url} target="_blank" rel="noopener noreferrer">
{provider.name}
</a>
{provider.image && <Image src={provider.image} inferSize alt={provider.name} />}
</div>
))}
</div>
)
}
<style>
.service-providers {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
.service-provider {
padding: 1rem;
border: 4px solid var(--sl-color-gray-5);
border-radius: 8px;
background: var(--sl-color-bg-nav);
}
.service-provider a {
font-weight: 600;
color: var(--sl-color-text);
text-decoration: none;
display: block;
margin-bottom: 0.5rem;
}
.service-provider a:hover {
color: var(--sl-color-accent);
}
</style>
---
import { Image } from 'astro:assets';
interface ServiceProvider {
name: string;
image?: string;
url: string;
}
const serviceProviders: ServiceProvider[] = [
{
name: 'Netlify',
url: 'https://www.netlify.com/',
},
{
name: 'Meilisearch',
url: 'https://www.meilisearch.com/',
},
];
---
{
serviceProviders.length > 0 && (
<div class="service-providers">
{serviceProviders.map((provider) => (
<div class="service-provider not-content">
<a href={provider.url} target="_blank" rel="noopener noreferrer">
{provider.name}
</a>
{provider.image && <Image src={provider.image} inferSize alt={provider.name} />}
</div>
))}
</div>
)
}
<style>
.service-providers {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
.service-provider {
padding: 1rem;
border: 4px solid var(--sl-color-gray-5);
border-radius: 8px;
background: var(--sl-color-bg-nav);
}
.service-provider a {
font-weight: 600;
color: var(--sl-color-text);
text-decoration: none;
display: block;
margin-bottom: 0.5rem;
}
.service-provider a:hover {
color: var(--sl-color-accent);
}
</style>

View File

@@ -27,7 +27,6 @@ import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
import Cta from '@fragments/cta.mdx';
import SponsorList from '@components/sponsors/SponsorList.astro';
<div class="hero-bg">
<div class="bg-logo"></div>
<div class="bg-grad"></div>
@@ -40,36 +39,32 @@ import SponsorList from '@components/sponsors/SponsorList.astro';
</Card>
</div>
{/*
<CardGrid stagger>
<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> */}
<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>
<SponsorList />

View File

@@ -1,84 +1,84 @@
import {
IMAGE_DIMENSION,
type Sponsor,
type Tier,
} from '@components/sponsors/OpenCollective/_types';
export const PLATINUM_THRESHOLD = 5_000;
export const GOLD_THRESHOLD = 500;
export const SILVER_THRESHOLD = 100;
export async function fetchOpenCollectiveData() {
const filteredSlugs = ['github-sponsors'];
// Documentation at https://graphql-docs-v2.opencollective.com/welcome
const query = `query account {
collective(slug: "tauri") {
contributors(limit: 1000) {
nodes {
account {
name
type
imageUrl(height: ${IMAGE_DIMENSION})
slug
isIncognito
}
totalAmountContributed {
value
currency
}
}
}
}
}`;
const res = await fetch('https://api.opencollective.com/graphql/v2', {
method: 'POST',
body: JSON.stringify({ query }),
headers: {
'Content-Type': 'application/json',
},
});
if (!res.ok) {
throw Error(
`Open Collective query failed: ${res.status} ${res.statusText} \n ${JSON.stringify(await res.json(), null, 2)}, `
);
}
// TODO: handle currency
const openCollectiveData = (await res.json()).data;
return openCollectiveData.collective.contributors.nodes
.filter(
(node: any) =>
!node.account.isIncognito &&
node.totalAmountContributed.value > 0 &&
!filteredSlugs.includes(node.account.slug) &&
node.account.name != 'Guest'
)
.sort((a: any, b: any) => b.totalAmountContributed.value - a.totalAmountContributed.value)
.map((node: any): Sponsor => {
let tier: Tier;
let amount = node.totalAmountContributed.value;
if (amount >= PLATINUM_THRESHOLD) {
tier = 'platinum';
} else if (amount >= GOLD_THRESHOLD) {
tier = 'gold';
} else if (amount >= SILVER_THRESHOLD) {
tier = 'silver';
} else {
tier = 'bronze';
}
const { slug, name, type, isIncognito, imageUrl } = node.account;
return {
name,
id: name,
avatarUrl: imageUrl,
profileUrl: `https://opencollective.com/${slug}`,
tier,
type,
};
});
}
import {
IMAGE_DIMENSION,
type Sponsor,
type Tier,
} from '@components/sponsors/OpenCollective/_types';
export const PLATINUM_THRESHOLD = 5_000;
export const GOLD_THRESHOLD = 500;
export const SILVER_THRESHOLD = 100;
export async function fetchOpenCollectiveData() {
const filteredSlugs = ['github-sponsors'];
// Documentation at https://graphql-docs-v2.opencollective.com/welcome
const query = `query account {
collective(slug: "tauri") {
contributors(limit: 1000) {
nodes {
account {
name
type
imageUrl(height: ${IMAGE_DIMENSION})
slug
isIncognito
}
totalAmountContributed {
value
currency
}
}
}
}
}`;
const res = await fetch('https://api.opencollective.com/graphql/v2', {
method: 'POST',
body: JSON.stringify({ query }),
headers: {
'Content-Type': 'application/json',
},
});
if (!res.ok) {
throw Error(
`Open Collective query failed: ${res.status} ${res.statusText} \n ${JSON.stringify(await res.json(), null, 2)}, `
);
}
// TODO: handle currency
const openCollectiveData = (await res.json()).data;
return openCollectiveData.collective.contributors.nodes
.filter(
(node: any) =>
!node.account.isIncognito &&
node.totalAmountContributed.value > 0 &&
!filteredSlugs.includes(node.account.slug) &&
node.account.name != 'Guest'
)
.sort((a: any, b: any) => b.totalAmountContributed.value - a.totalAmountContributed.value)
.map((node: any): Sponsor => {
let tier: Tier;
let amount = node.totalAmountContributed.value;
if (amount >= PLATINUM_THRESHOLD) {
tier = 'platinum';
} else if (amount >= GOLD_THRESHOLD) {
tier = 'gold';
} else if (amount >= SILVER_THRESHOLD) {
tier = 'silver';
} else {
tier = 'bronze';
}
const { slug, name, type, isIncognito, imageUrl } = node.account;
return {
name,
id: name,
avatarUrl: imageUrl,
profileUrl: `https://opencollective.com/${slug}`,
tier,
type,
};
});
}

View File

@@ -1,46 +1,46 @@
{
"folders": [
{
"path": ".",
"name": "docs"
},
{
"path": "packages",
"name": "packages",
"folders": [
{
"path": "js-api-generator",
},
{
"path": "config-generator",
},
{
"path": "cli-generator",
},
{
"path": "releases-generator",
},
{
"path": "compatibility-table",
}
]
},
// todo: fix paths so that we can see docs, packages and submodules
{
"path": "packages",
"name": "submodules",
"folders": [
{
"path": "awesome-tauri",
},
{
"path": "tauri",
},
{
"path": "plugins-workspace",
}
]
}
],
"settings": {}
}
{
"folders": [
{
"path": ".",
"name": "docs",
},
{
"path": "packages",
"name": "packages",
"folders": [
{
"path": "js-api-generator",
},
{
"path": "config-generator",
},
{
"path": "cli-generator",
},
{
"path": "releases-generator",
},
{
"path": "compatibility-table",
},
],
},
// todo: fix paths so that we can see docs, packages and submodules
{
"path": "packages",
"name": "submodules",
"folders": [
{
"path": "awesome-tauri",
},
{
"path": "tauri",
},
{
"path": "plugins-workspace",
},
],
},
],
"settings": {},
}