mirror of
https://github.com/Raghu-Ch/angular-challenges.git
synced 2026-02-10 04:43:03 -05:00
feat: create leaderboard
This commit is contained in:
@@ -1,102 +1,113 @@
|
|||||||
import starlight from '@astrojs/starlight';
|
import starlight from '@astrojs/starlight';
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
|
import svelte from '@astrojs/svelte';
|
||||||
|
|
||||||
export const locales = {
|
export const locales = {
|
||||||
root: {
|
root: {
|
||||||
label: 'English',
|
label: 'English',
|
||||||
lang: 'en',
|
lang: 'en'
|
||||||
},
|
},
|
||||||
es: {
|
es: {
|
||||||
label: 'Español',
|
label: 'Español',
|
||||||
lang: 'es',
|
lang: 'es'
|
||||||
},
|
},
|
||||||
fr: {
|
fr: {
|
||||||
label: 'Français',
|
label: 'Français',
|
||||||
lang: 'fr',
|
lang: 'fr'
|
||||||
},
|
},
|
||||||
pt: {
|
pt: {
|
||||||
label: 'Português',
|
label: 'Português',
|
||||||
lang: 'pt',
|
lang: 'pt'
|
||||||
},
|
},
|
||||||
ru: {
|
ru: {
|
||||||
label: 'Русский',
|
label: 'Русский',
|
||||||
lang: 'ru',
|
lang: 'ru'
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [
|
integrations: [starlight({
|
||||||
starlight({
|
title: 'Angular Challenges',
|
||||||
title: 'Angular Challenges',
|
logo: {
|
||||||
logo: {
|
src: './public/angular-challenge.webp',
|
||||||
src: './public/angular-challenge.webp',
|
alt: 'angular challenges logo'
|
||||||
alt: 'angular challenges logo',
|
},
|
||||||
|
favicon: './angular-challenge.ico',
|
||||||
|
social: {
|
||||||
|
github: 'https://github.com/tomalaforge/angular-challenges',
|
||||||
|
linkedin: 'https://www.linkedin.com/in/thomas-laforge-2b05a945/',
|
||||||
|
twitter: 'https://twitter.com/laforge_toma'
|
||||||
|
},
|
||||||
|
customCss: ['./src/styles/custom-css.css'],
|
||||||
|
sidebar: [{
|
||||||
|
label: 'Guides',
|
||||||
|
autogenerate: {
|
||||||
|
directory: 'guides'
|
||||||
},
|
},
|
||||||
favicon: './angular-challenge.ico',
|
translations: {
|
||||||
social: {
|
es: 'Guías',
|
||||||
github: 'https://github.com/tomalaforge/angular-challenges',
|
fr: 'Guides',
|
||||||
linkedin: 'https://www.linkedin.com/in/thomas-laforge-2b05a945/',
|
pt: 'Guias',
|
||||||
twitter: 'https://twitter.com/laforge_toma',
|
ru: 'Руководство'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// label: 'Leaderboard',
|
||||||
|
// autogenerate: {
|
||||||
|
// directory: 'leaderboard',
|
||||||
|
// collapsed: true
|
||||||
|
// },
|
||||||
|
// translations: {
|
||||||
|
// es: 'Leaderboard',
|
||||||
|
// fr: 'Leaderboard',
|
||||||
|
// pt: 'Leaderboard',
|
||||||
|
// ru: 'Leaderboard'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
label: 'Challenges',
|
||||||
|
autogenerate: {
|
||||||
|
directory: 'challenges'
|
||||||
},
|
},
|
||||||
customCss: ['./src/styles/custom-css.css'],
|
translations: {
|
||||||
sidebar: [
|
es: 'Desafíos',
|
||||||
{
|
fr: 'Challenges',
|
||||||
label: 'Guides',
|
pt: 'Desafios',
|
||||||
autogenerate: { directory: 'guides' },
|
ru: 'Задачи'
|
||||||
translations: {
|
}
|
||||||
es: 'Guías',
|
}],
|
||||||
fr: 'Guides',
|
head: [{
|
||||||
pt: 'Guias',
|
tag: 'script',
|
||||||
ru: 'Руководство',
|
attrs: {
|
||||||
},
|
src: 'https://www.googletagmanager.com/gtag/js?id=G-6BXJ62W6G5',
|
||||||
},
|
async: true
|
||||||
{
|
}
|
||||||
label: 'Challenges',
|
}, {
|
||||||
autogenerate: { directory: 'challenges' },
|
tag: 'script',
|
||||||
translations: {
|
content: `
|
||||||
es: 'Desafíos',
|
|
||||||
fr: 'Challenges',
|
|
||||||
pt: 'Desafios',
|
|
||||||
ru: 'Задачи',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
head: [
|
|
||||||
{
|
|
||||||
tag: 'script',
|
|
||||||
attrs: {
|
|
||||||
src: 'https://www.googletagmanager.com/gtag/js?id=G-6BXJ62W6G5',
|
|
||||||
async: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
tag: 'script',
|
|
||||||
content: `
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
gtag('config', 'G-6BXJ62W6G5');
|
gtag('config', 'G-6BXJ62W6G5');
|
||||||
`,
|
`
|
||||||
},
|
}, {
|
||||||
{
|
tag: 'script',
|
||||||
tag: 'script',
|
attrs: {
|
||||||
attrs: {
|
src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2438923752868254',
|
||||||
src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2438923752868254',
|
async: true
|
||||||
async: true,
|
}
|
||||||
}
|
}],
|
||||||
}
|
components: {
|
||||||
],
|
MarkdownContent: './src/components/Content.astro',
|
||||||
components: {
|
TableOfContents: './src/components/TableOfContents.astro',
|
||||||
MarkdownContent: './src/components/Content.astro',
|
PageTitle: './src/components/PageTitle.astro',
|
||||||
TableOfContents: './src/components/TableOfContents.astro',
|
MobileMenuFooter: './src/components/MobileMenuFooter.astro',
|
||||||
PageTitle: './src/components/PageTitle.astro',
|
SiteTitle: './src/components/SiteTitle.astro'
|
||||||
MobileMenuFooter: './src/components/MobileMenuFooter.astro',
|
},
|
||||||
SiteTitle: './src/components/SiteTitle.astro',
|
defaultLocale: 'root',
|
||||||
},
|
locales
|
||||||
defaultLocale: 'root',
|
}), svelte()]
|
||||||
locales,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|||||||
925
docs/package-lock.json
generated
925
docs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/starlight": "^0.15.1",
|
"@astrojs/starlight": "^0.15.1",
|
||||||
|
"@astrojs/svelte": "^5.2.0",
|
||||||
"@fontsource/ibm-plex-serif": "^5.0.8",
|
"@fontsource/ibm-plex-serif": "^5.0.8",
|
||||||
"astro": "^4.0.0",
|
"astro": "^4.0.0",
|
||||||
"sharp": "^0.32.5"
|
"sharp": "^0.32.5",
|
||||||
|
"svelte": "^4.2.12",
|
||||||
|
"typescript": "^5.4.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
93
docs/src/components/leaderboard/LeaderboardAnswer.svelte
Normal file
93
docs/src/components/leaderboard/LeaderboardAnswer.svelte
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import UserBox from './UserBox.svelte';
|
||||||
|
|
||||||
|
let users = [];
|
||||||
|
let loading = true;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
async function fetchGitHubUsers() {
|
||||||
|
try {
|
||||||
|
const prCounts = {};
|
||||||
|
let page = 1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const response = await fetch(`https://api.github.com/search/issues?q=repo:tomalaforge/angular-challenges+is:pr+label:%22answer%22&per_page=200&page=${page}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('API rate limit exceeded. Please try again in a few minutes.');
|
||||||
|
}
|
||||||
|
const { total_count, items } = await response.json();
|
||||||
|
|
||||||
|
if (!items || items.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.forEach(pr => {
|
||||||
|
const userLogin = pr.user.login;
|
||||||
|
if (prCounts[userLogin]) {
|
||||||
|
prCounts[userLogin].count++;
|
||||||
|
prCounts[userLogin].challengeNumber.push(pr.labels.filter(l => !isNaN(Number(l.name))).map(l => Number(l.name))?.[0]);
|
||||||
|
} else {
|
||||||
|
prCounts[userLogin] = {
|
||||||
|
avatar: pr.user.avatar_url,
|
||||||
|
count: 1,
|
||||||
|
challengeNumber: [pr.labels.filter(l => !isNaN(Number(l.name))).map(l => Number(l.name))?.[0]]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(total_count < page * 100) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
|
||||||
|
users = Object.entries(prCounts).map(([login, pr]) => ({
|
||||||
|
login,
|
||||||
|
avatar: pr.avatar,
|
||||||
|
count: pr.count,
|
||||||
|
challengeNumber: pr.challengeNumber.sort((a, b) => a - b)
|
||||||
|
})).filter((r) => r.login !== 'allcontributors[bot]').sort((a, b) => b.count - a.count);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
error = e.message;
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
fetchGitHubUsers();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<p>Loading...</p>
|
||||||
|
{:else if error}
|
||||||
|
<p>Error: {error}</p>
|
||||||
|
{:else}
|
||||||
|
<div class="box not-content">
|
||||||
|
{#each users as { avatar, count, login,challengeNumber }, index}
|
||||||
|
<UserBox {avatar} {login} {index}>
|
||||||
|
{count} Answers
|
||||||
|
<div slot="addon" class="challenge-number">{challengeNumber.join(', ')}</div>
|
||||||
|
</UserBox>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.box {
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.challenge-number {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--sl-color-gray-3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
72
docs/src/components/leaderboard/LeaderboardChallenge.svelte
Normal file
72
docs/src/components/leaderboard/LeaderboardChallenge.svelte
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import UserBox from './UserBox.svelte';
|
||||||
|
|
||||||
|
|
||||||
|
let users = [];
|
||||||
|
let loading = true;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const createUser = (items) => {
|
||||||
|
const prCounts = {};
|
||||||
|
items.forEach((pr) => {
|
||||||
|
const userLogin = pr.user.login;
|
||||||
|
if (prCounts[userLogin]) {
|
||||||
|
prCounts[userLogin].count++;
|
||||||
|
} else {
|
||||||
|
prCounts[userLogin] = {
|
||||||
|
avatar: pr.user.avatar_url,
|
||||||
|
count: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.entries(prCounts).map(([login, pr]) => ({
|
||||||
|
login,
|
||||||
|
avatar: pr.avatar,
|
||||||
|
count: pr.count
|
||||||
|
})).filter((r) => r.login !== 'allcontributors[bot]').sort((a, b) => b.count - a.count);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function fetchGitHubUsers() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`https://api.github.com/search/issues?q=repo:tomalaforge/angular-challenges+is:pr+label:%22challenge-creation%22`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('API rate limit exceeded. Please try again in a few minutes.');
|
||||||
|
}
|
||||||
|
const { items } = await response.json();
|
||||||
|
users = createUser(items);
|
||||||
|
} catch (e) {
|
||||||
|
error = e.message;
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
fetchGitHubUsers();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<p>Loading...</p>
|
||||||
|
{:else if error}
|
||||||
|
<p>Error: {error}</p>
|
||||||
|
{:else}
|
||||||
|
<div class="box not-content">
|
||||||
|
{#each users as { avatar, count, login, challengeNumber }, index}
|
||||||
|
<UserBox {avatar} {login} {index}>
|
||||||
|
{count} Challenges Created
|
||||||
|
</UserBox>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.box {
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
88
docs/src/components/leaderboard/LeaderboardCommit.svelte
Normal file
88
docs/src/components/leaderboard/LeaderboardCommit.svelte
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import UserBox from './UserBox.svelte';
|
||||||
|
|
||||||
|
let users = [];
|
||||||
|
let loading = true;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
async function fetchGitHubUsers() {
|
||||||
|
try {
|
||||||
|
const prCounts = {};
|
||||||
|
let page = 1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const response = await fetch(`https://api.github.com/search/issues?q=repo:tomalaforge/angular-challenges+is:pr+no:label&per_page=100&page=${page}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('API rate limit exceeded. Please try again in a few minutes.');
|
||||||
|
}
|
||||||
|
const { total_count, items } = await response.json();
|
||||||
|
|
||||||
|
if (!items || items.length === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.forEach(pr => {
|
||||||
|
const userLogin = pr.user.login;
|
||||||
|
if (prCounts[userLogin]) {
|
||||||
|
prCounts[userLogin].count++;
|
||||||
|
prCounts[userLogin].challengeNumber.push(pr.labels.filter(l => !isNaN(Number(l.name))).map(l => l.name).join(', '));
|
||||||
|
} else {
|
||||||
|
prCounts[userLogin] = {
|
||||||
|
avatar: pr.user.avatar_url,
|
||||||
|
count: 1,
|
||||||
|
challengeNumber: [pr.labels.filter(l => !isNaN(Number(l.name))).map(l => l.name).join(', ')]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(total_count < page * 100) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
page++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
users = Object.entries(prCounts).map(([login, pr]) => ({
|
||||||
|
login,
|
||||||
|
avatar: pr.avatar,
|
||||||
|
count: pr.count,
|
||||||
|
challengeNumber: pr.challengeNumber
|
||||||
|
})).filter((r) => r.login !== 'allcontributors[bot]').sort((a, b) => b.count - a.count);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
error = e.message;
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
fetchGitHubUsers();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<p>Loading...</p>
|
||||||
|
{:else if error}
|
||||||
|
<p>Error: {error}</p>
|
||||||
|
{:else}
|
||||||
|
<div class="box not-content">
|
||||||
|
{#each users as { avatar, count, login }, index}
|
||||||
|
<UserBox {avatar} {login} {index}>
|
||||||
|
{count} PRs merged
|
||||||
|
</UserBox>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.box {
|
||||||
|
display: grid;
|
||||||
|
justify-items: center;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
77
docs/src/components/leaderboard/UserBox.svelte
Normal file
77
docs/src/components/leaderboard/UserBox.svelte
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<script>
|
||||||
|
export let avatar;
|
||||||
|
export let login;
|
||||||
|
export let index;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="user-box">
|
||||||
|
<div class="user-info">
|
||||||
|
<img src={avatar} alt="" width="40" height="40" class="avatar" />
|
||||||
|
<div class="name-box">
|
||||||
|
<div class="user-name">{login}</div>
|
||||||
|
<div class="count"><slot /></div>
|
||||||
|
<slot name="addon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="position">
|
||||||
|
#{index + 1}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.position {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
color: var(--sl-color-gray-6);
|
||||||
|
background-color: var(--sl-color-gray-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
border: 1px solid var(--sl-color-gray-3);
|
||||||
|
border-radius: 5px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
padding: 1rem 0 1rem 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
justify-content: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 24px;
|
||||||
|
color: red;
|
||||||
|
line-height: 24px;
|
||||||
|
max-width: 150px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
font-size: var(--sl-text-xs);
|
||||||
|
color: var(--sl-color-gray-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
11
docs/src/content/docs/leaderboard/answers.mdx
Normal file
11
docs/src/content/docs/leaderboard/answers.mdx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
title: Challenges answered
|
||||||
|
description: leaderboard showing the number of challenges answered.
|
||||||
|
noCommentSection: true
|
||||||
|
prev: false
|
||||||
|
next: false
|
||||||
|
---
|
||||||
|
|
||||||
|
import LeaderboardAnswer from '../../../components/leaderboard/LeaderboardAnswer.svelte';
|
||||||
|
|
||||||
|
<LeaderboardAnswer client:load />
|
||||||
11
docs/src/content/docs/leaderboard/challenges.mdx
Normal file
11
docs/src/content/docs/leaderboard/challenges.mdx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
title: Number of Challenges Created
|
||||||
|
description: leaderboard showing the number of challenges created.
|
||||||
|
noCommentSection: true
|
||||||
|
prev: false
|
||||||
|
next: false
|
||||||
|
---
|
||||||
|
|
||||||
|
import LeaderboardChallenge from '../../../components/leaderboard/LeaderboardChallenge.svelte';
|
||||||
|
|
||||||
|
<LeaderboardChallenge client:load />
|
||||||
11
docs/src/content/docs/leaderboard/commit.mdx
Normal file
11
docs/src/content/docs/leaderboard/commit.mdx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
title: Number of contributions
|
||||||
|
description: leaderboard showing the number of contributions.
|
||||||
|
noCommentSection: true
|
||||||
|
prev: false
|
||||||
|
next: false
|
||||||
|
---
|
||||||
|
|
||||||
|
import LeaderboardCommit from '../../../components/leaderboard/LeaderboardCommit.svelte';
|
||||||
|
|
||||||
|
<LeaderboardCommit client:load />
|
||||||
5
docs/svelte.config.js
Normal file
5
docs/svelte.config.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { vitePreprocess } from '@astrojs/svelte';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
};
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "astro/tsconfigs/strict"
|
"extends": "astro/tsconfigs/strict",
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "react"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user