Merge pull request #296 from mearashadowfax/astro-update

Astro update
This commit is contained in:
Emil Gulamov 2025-01-02 19:34:43 +04:00 committed by GitHub
commit 46772f89cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 1419 additions and 1174 deletions

View file

@ -4,6 +4,8 @@ import sitemap from "@astrojs/sitemap";
import compressor from "astro-compressor"; import compressor from "astro-compressor";
import starlight from "@astrojs/starlight"; import starlight from "@astrojs/starlight";
import mdx from "@astrojs/mdx";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
// https://docs.astro.build/en/guides/images/#authorizing-remote-images // https://docs.astro.build/en/guides/images/#authorizing-remote-images
@ -22,9 +24,7 @@ export default defineConfig({
// }, // },
// }, // },
prefetch: true, prefetch: true,
integrations: [ integrations: [tailwind(), sitemap({
tailwind(),
sitemap({
i18n: { i18n: {
defaultLocale: "en", // All urls that don't contain `fr` after `https://screwfast.uk/` will be treated as default locale, i.e. `en` defaultLocale: "en", // All urls that don't contain `fr` after `https://screwfast.uk/` will be treated as default locale, i.e. `en`
locales: { locales: {
@ -32,8 +32,7 @@ export default defineConfig({
fr: "fr", fr: "fr",
}, },
}, },
}), }), starlight({
starlight({
title: "ScrewFast Docs", title: "ScrewFast Docs",
defaultLocale: "root", defaultLocale: "root",
// https://github.com/withastro/starlight/blob/main/packages/starlight/CHANGELOG.md // https://github.com/withastro/starlight/blob/main/packages/starlight/CHANGELOG.md
@ -111,12 +110,10 @@ export default defineConfig({
}, },
}, },
], ],
}), }), compressor({
compressor({
gzip: false, gzip: false,
brotli: true, brotli: true,
}), }), mdx()],
],
experimental: { experimental: {
clientPrerender: true, clientPrerender: true,
}, },

2060
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,16 +11,17 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/check": "^0.9.4", "@astrojs/check": "^0.9.4",
"@astrojs/mdx": "^4.0.3",
"@astrojs/sitemap": "^3.2.1", "@astrojs/sitemap": "^3.2.1",
"@astrojs/starlight": "^0.29.3", "@astrojs/starlight": "^0.30.3",
"@astrojs/starlight-tailwind": "^2.0.3", "@astrojs/starlight-tailwind": "^3.0.0",
"@astrojs/tailwind": "^5.1.4", "@astrojs/tailwind": "^5.1.4",
"@preline/accordion": "^2.6.0", "@preline/accordion": "^2.5.0",
"@preline/collapse": "^2.6.0", "@preline/collapse": "^2.6.0",
"@preline/dropdown": "^2.6.0", "@preline/dropdown": "^2.6.0",
"@preline/overlay": "^2.6.0", "@preline/overlay": "^2.6.0",
"@preline/tabs": "^2.6.0", "@preline/tabs": "^2.6.0",
"astro": "^4.16.18", "astro": "^5.1.2",
"astro-compressor": "^1.0.0", "astro-compressor": "^1.0.0",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"globby": "^14.0.2", "globby": "^14.0.2",

View file

@ -20,8 +20,8 @@ interface Props {
<a <a
class="group relative block rounded-xl outline-none ring-zinc-500 transition duration-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none" class="group relative block rounded-xl outline-none ring-zinc-500 transition duration-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
href={blogLocale && blogLocale !== "en" href={blogLocale && blogLocale !== "en"
? `/${blogLocale}/blog/${blogEntry.slug.replace(/^fr\//, "")}/` ? `/${blogLocale}/blog/${blogEntry.id.replace(/^fr\//, "")}/`
: `/blog/${blogEntry.slug.replace(/^en\//, "")}/`} : `/blog/${blogEntry.id.replace(/^en\//, "")}/`}
data-astro-prefetch data-astro-prefetch
> >
<!-- The container for the blog post's cover image. Uses astro:assets' Image for image source --> <!-- The container for the blog post's cover image. Uses astro:assets' Image for image source -->

View file

@ -36,7 +36,7 @@ interface Props {
> >
<a <a
class="outline-none ring-zinc-500 transition duration-300 hover:text-orange-400 focus-visible:ring dark:text-neutral-300 dark:ring-zinc-200 dark:hover:text-neutral-50 dark:focus:outline-none" class="outline-none ring-zinc-500 transition duration-300 hover:text-orange-400 focus-visible:ring dark:text-neutral-300 dark:ring-zinc-200 dark:hover:text-neutral-50 dark:focus:outline-none"
href={recentBlogLocale && recentBlogLocale !== "en" ? `/${recentBlogLocale}/blog/${blogEntry.slug.replace(/^fr\//, '')}/` : `/blog/${blogEntry.slug.replace(/^en\//, '')}/`} href={recentBlogLocale && recentBlogLocale !== "en" ? `/${recentBlogLocale}/blog/${blogEntry.id.replace(/^fr\//, '')}/` : `/blog/${blogEntry.id.replace(/^en\//, '')}/`}
> >
{blogEntry.data.description} {blogEntry.data.description}
</a> </a>
@ -57,7 +57,7 @@ interface Props {
<!-- Read More button which is a link to the blog post detailed page --> <!-- Read More button which is a link to the blog post detailed page -->
<div class="mt-5"> <div class="mt-5">
<PrimaryCTA <PrimaryCTA
url={recentBlogLocale && recentBlogLocale !== "en" ? `/${recentBlogLocale}/blog/${blogEntry.slug.replace(/^fr\//, '')}/` : `/blog/${blogEntry.slug.replace(/^en\//, '')}/`} url={recentBlogLocale && recentBlogLocale !== "en" ? `/${recentBlogLocale}/blog/${blogEntry.id.replace(/^fr\//, '')}/` : `/blog/${blogEntry.id.replace(/^en\//, '')}/`}
title="Read More" title="Read More"
data-astro-prefetch data-astro-prefetch
/> />

View file

@ -21,8 +21,8 @@ interface Props {
<a <a
class="group rounded-xl outline-none ring-zinc-500 transition duration-300 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none" class="group rounded-xl outline-none ring-zinc-500 transition duration-300 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
href={insightLocale && insightLocale !== "en" href={insightLocale && insightLocale !== "en"
? `/${insightLocale}/insights/${insightEntry.slug.replace(/^fr\//, "")}/` ? `/${insightLocale}/insights/${insightEntry.id.replace(/^fr\//, "")}/`
: `/insights/${insightEntry.slug.replace(/^en\//, "")}/`} : `/insights/${insightEntry.id.replace(/^en\//, "")}/`}
> >
<!-- This is the container for the insight's cover image. --> <!-- This is the container for the insight's cover image. -->
<div class="relative overflow-hidden rounded-xl pt-[50%] sm:pt-[70%]"> <div class="relative overflow-hidden rounded-xl pt-[50%] sm:pt-[70%]">

View file

@ -15,8 +15,8 @@ interface Props {
<a <a
class="group block rounded-xl outline-none ring-zinc-500 transition duration-300 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none" class="group block rounded-xl outline-none ring-zinc-500 transition duration-300 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none"
href={recentBlogLocale && recentBlogLocale !== "en" href={recentBlogLocale && recentBlogLocale !== "en"
? `/${recentBlogLocale}/blog/${blogEntry.slug.replace(/^fr\//, "")}/` ? `/${recentBlogLocale}/blog/${blogEntry.id.replace(/^fr\//, "")}/`
: `/blog/${blogEntry.slug.replace(/^en\//, "")}/`} : `/blog/${blogEntry.id.replace(/^en\//, "")}/`}
data-astro-prefetch data-astro-prefetch
> >
<div> <div>

View file

@ -19,8 +19,8 @@ const imageClass =
<!-- A clickable card that leads to the details of the product--> <!-- A clickable card that leads to the details of the product-->
<a <a
href={productLocale && productLocale !== "en" href={productLocale && productLocale !== "en"
? `/${productLocale}/products/${product.slug.replace(/^fr\//, "")}/` ? `/${productLocale}/products/${product.id.replace(/^fr\//, "")}/`
: `/products/${product.slug.replace(/^en\//, "")}/`} : `/products/${product.id.replace(/^en\//, "")}/`}
data-astro-prefetch data-astro-prefetch
class="group relative flex h-48 items-end overflow-hidden rounded-xl shadow-lg outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:h-80" class="group relative flex h-48 items-end overflow-hidden rounded-xl shadow-lg outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:h-80"
> >

View file

@ -19,8 +19,8 @@ const imageClass =
<!-- The anchor tag is the main container for the product card. When clicked, this leads to the details of the product. --> <!-- The anchor tag is the main container for the product card. When clicked, this leads to the details of the product. -->
<a <a
href={productLocale && productLocale !== "en" href={productLocale && productLocale !== "en"
? `/${productLocale}/products/${product.slug.replace(/^fr\//, "")}/` ? `/${productLocale}/products/${product.id.replace(/^fr\//, "")}/`
: `/products/${product.slug.replace(/^en\//, "")}/`} : `/products/${product.id.replace(/^en\//, "")}/`}
data-astro-prefetch data-astro-prefetch
class="group relative flex h-48 items-end overflow-hidden rounded-lg shadow-xl outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:col-span-2 md:h-80" class="group relative flex h-48 items-end overflow-hidden rounded-lg shadow-xl outline-none ring-zinc-500 focus-visible:ring dark:ring-zinc-200 dark:focus:outline-none md:col-span-2 md:h-80"
> >

97
src/content.config.ts Normal file
View file

@ -0,0 +1,97 @@
// https://docs.astro.build/en/guides/content-collections/#defining-collections
import { z, defineCollection } from 'astro:content';
import { docsSchema } from '@astrojs/starlight/schema';
import { glob } from 'astro/loaders';
const productsCollection = defineCollection({
loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: "./src/content/products" }),
schema: ({ image }) => z.object({
title: z.string(),
description: z.string(),
main: z.object({
id: z.number(),
content: z.string(),
imgCard: image(),
imgMain: image(),
imgAlt: z.string(),
}),
tabs: z.array(
z.object({
id: z.string(),
dataTab: z.string(),
title: z.string(),
})
),
longDescription: z.object({
title: z.string(),
subTitle: z.string(),
btnTitle: z.string(),
btnURL: z.string(),
}),
descriptionList: z.array(
z.object({
title: z.string(),
subTitle: z.string(),
})
),
specificationsLeft: z.array(
z.object({
title: z.string(),
subTitle: z.string(),
})
),
specificationsRight: z.array(
z.object({
title: z.string(),
subTitle: z.string(),
})
).optional(),
tableData: z.array(
z.object({
feature: z.array(z.string()),
description: z.array(z.array(z.string())),
})
).optional(),
blueprints: z.object({
first: image().optional(),
second: image().optional(),
}),
}),
});
const blogCollection = defineCollection({
loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: "./src/content/blog" }),
schema: ({ image }) => z.object ({
title: z.string(),
description: z.string(),
contents: z.array(z.string()),
author: z.string(),
role: z.string().optional(),
authorImage: image(),
authorImageAlt: z.string(),
pubDate: z.date(),
cardImage: image(),
cardImageAlt: z.string(),
readTime: z.number(),
tags: z.array(z.string()).optional(),
}),
});
const insightsCollection = defineCollection({
loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: "./src/content/insights" }),
schema: ({ image }) => z.object ({
title: z.string(),
description: z.string(),
// contents: z.array(z.string()),
cardImage: image(),
cardImageAlt: z.string(),
}),
});
export const collections = {
docs: defineCollection({ schema: docsSchema() }),
'products': productsCollection,
'blog': blogCollection,
'insights': insightsCollection,
};

View file

@ -1,96 +1,96 @@
// https://docs.astro.build/en/guides/content-collections/#defining-collections // // https://docs.astro.build/en/guides/content-collections/#defining-collections
import { z, defineCollection } from 'astro:content'; // import { z, defineCollection } from 'astro:content';
import { docsSchema } from '@astrojs/starlight/schema'; // import { docsSchema } from '@astrojs/starlight/schema';
const productsCollection = defineCollection({ // const productsCollection = defineCollection({
type: 'content', // type: 'content',
schema: ({ image }) => z.object({ // schema: ({ image }) => z.object({
title: z.string(), // title: z.string(),
description: z.string(), // description: z.string(),
main: z.object({ // main: z.object({
id: z.number(), // id: z.number(),
content: z.string(), // content: z.string(),
imgCard: image(), // imgCard: image(),
imgMain: image(), // imgMain: image(),
imgAlt: z.string(), // imgAlt: z.string(),
}), // }),
tabs: z.array( // tabs: z.array(
z.object({ // z.object({
id: z.string(), // id: z.string(),
dataTab: z.string(), // dataTab: z.string(),
title: z.string(), // title: z.string(),
}) // })
), // ),
longDescription: z.object({ // longDescription: z.object({
title: z.string(), // title: z.string(),
subTitle: z.string(), // subTitle: z.string(),
btnTitle: z.string(), // btnTitle: z.string(),
btnURL: z.string(), // btnURL: z.string(),
}), // }),
descriptionList: z.array( // descriptionList: z.array(
z.object({ // z.object({
title: z.string(), // title: z.string(),
subTitle: z.string(), // subTitle: z.string(),
}) // })
), // ),
specificationsLeft: z.array( // specificationsLeft: z.array(
z.object({ // z.object({
title: z.string(), // title: z.string(),
subTitle: z.string(), // subTitle: z.string(),
}) // })
), // ),
specificationsRight: z.array( // specificationsRight: z.array(
z.object({ // z.object({
title: z.string(), // title: z.string(),
subTitle: z.string(), // subTitle: z.string(),
}) // })
).optional(), // ).optional(),
tableData: z.array( // tableData: z.array(
z.object({ // z.object({
feature: z.array(z.string()), // feature: z.array(z.string()),
description: z.array(z.array(z.string())), // description: z.array(z.array(z.string())),
}) // })
).optional(), // ).optional(),
blueprints: z.object({ // blueprints: z.object({
first: image().optional(), // first: image().optional(),
second: image().optional(), // second: image().optional(),
}), // }),
}), // }),
}); // });
const blogCollection = defineCollection({ // const blogCollection = defineCollection({
type: "content", // type: "content",
schema: ({ image }) => z.object ({ // schema: ({ image }) => z.object ({
title: z.string(), // title: z.string(),
description: z.string(), // description: z.string(),
contents: z.array(z.string()), // contents: z.array(z.string()),
author: z.string(), // author: z.string(),
role: z.string().optional(), // role: z.string().optional(),
authorImage: image(), // authorImage: image(),
authorImageAlt: z.string(), // authorImageAlt: z.string(),
pubDate: z.date(), // pubDate: z.date(),
cardImage: image(), // cardImage: image(),
cardImageAlt: z.string(), // cardImageAlt: z.string(),
readTime: z.number(), // readTime: z.number(),
tags: z.array(z.string()).optional(), // tags: z.array(z.string()).optional(),
}), // }),
}); // });
const insightsCollection = defineCollection({ // const insightsCollection = defineCollection({
type: "content", // type: "content",
schema: ({ image }) => z.object ({ // schema: ({ image }) => z.object ({
title: z.string(), // title: z.string(),
description: z.string(), // description: z.string(),
// contents: z.array(z.string()), // // contents: z.array(z.string()),
cardImage: image(), // cardImage: image(),
cardImageAlt: z.string(), // cardImageAlt: z.string(),
}), // }),
}); // });
export const collections = { // export const collections = {
docs: defineCollection({ schema: docsSchema() }), // docs: defineCollection({ schema: docsSchema() }),
'products': productsCollection, // 'products': productsCollection,
'blog': blogCollection, // 'blog': blogCollection,
'insights': insightsCollection, // 'insights': insightsCollection,
}; // };

View file

@ -18,9 +18,9 @@ export async function getStaticPaths() {
id.startsWith("en/") id.startsWith("en/")
); );
return blogPosts.map((post) => { return blogPosts.map((post) => {
const slugWithoutLang = post.slug.replace(/^en\//, ""); // Remove the "en/" prefix const idWithoutLang = post.id.replace(/^en\//, ""); // Remove the "en/" prefix
return { return {
params: { slug: slugWithoutLang }, params: { id: idWithoutLang },
props: { post }, props: { post },
}; };
}); });
@ -39,7 +39,7 @@ const blogPosts: CollectionEntry<"blog">[] = await getCollection(
// In a production site, you might want to implement a more robust algorithm, choosing related posts based on tags, categories, dates, authors, or keywords. // In a production site, you might want to implement a more robust algorithm, choosing related posts based on tags, categories, dates, authors, or keywords.
// See example: https://blog.codybrunner.com/2024/adding-related-articles-with-astro-content-collections/ // See example: https://blog.codybrunner.com/2024/adding-related-articles-with-astro-content-collections/
const relatedPosts: CollectionEntry<"blog">[] = blogPosts.filter( const relatedPosts: CollectionEntry<"blog">[] = blogPosts.filter(
(blogEntry) => blogEntry.slug !== post.slug (blogEntry) => blogEntry.id !== post.id
); );
const pageTitle: string = `${post.data.title} | ${SITE.title}`; const pageTitle: string = `${post.data.title} | ${SITE.title}`;

View file

@ -18,9 +18,9 @@ export async function getStaticPaths() {
id.startsWith("fr/") id.startsWith("fr/")
); );
return blogPosts.map((post) => { return blogPosts.map((post) => {
const slugWithoutLang = post.slug.replace(/^fr\//, ""); // Remove the "fr/" prefix const idWithoutLang = post.id.replace(/^fr\//, ""); // Remove the "fr/" prefix
return { return {
params: { lang: "fr", slug: slugWithoutLang }, params: { lang: "fr", id: idWithoutLang },
props: { post }, props: { post },
}; };
}); });
@ -34,7 +34,7 @@ const blogPosts: CollectionEntry<"blog">[] = await getCollection(
({ id }) => id.startsWith("fr/") ({ id }) => id.startsWith("fr/")
); );
const relatedPosts: CollectionEntry<"blog">[] = blogPosts.filter( const relatedPosts: CollectionEntry<"blog">[] = blogPosts.filter(
(blogEntry) => blogEntry.slug !== post.slug (blogEntry) => blogEntry.id !== post.id
); );
const pageTitle: string = `${post.data.title} | ${SITE.title}`; const pageTitle: string = `${post.data.title} | ${SITE.title}`;

View file

@ -3,15 +3,15 @@
import { SITE } from "@data/constants"; import { SITE } from "@data/constants";
import MainLayout from "@/layouts/MainLayout.astro"; import MainLayout from "@/layouts/MainLayout.astro";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import { getCollection } from "astro:content"; import { getCollection, render } from "astro:content";
// Use `getStaticPaths` to generate static routes for generated pages on build // Use `getStaticPaths` to generate static routes for generated pages on build
export async function getStaticPaths() { export async function getStaticPaths() {
const insightPosts = await getCollection("insights", ({ id }) => id.startsWith("fr/")); const insightPosts = await getCollection("insights", ({ id }) => id.startsWith("fr/"));
return insightPosts.map((post) => { return insightPosts.map((post) => {
const slugWithoutLang = post.slug.replace(/^fr\//, ''); // Remove the "fr/" prefix const idWithoutLang = post.id.replace(/^fr\//, ''); // Remove the "fr/" prefix
return { return {
params: { lang: 'fr', slug: slugWithoutLang }, params: { lang: 'fr', id: idWithoutLang },
props: { post }, props: { post },
}; };
}); });
@ -20,7 +20,7 @@ export async function getStaticPaths() {
// Get the props for this page that define a specific insight post // Get the props for this page that define a specific insight post
const { post } = Astro.props; const { post } = Astro.props;
const { Content } = await post.render(); const { Content } = await render(post);
const pageTitle: string = `${post.data.title} | ${SITE.title}`; const pageTitle: string = `${post.data.title} | ${SITE.title}`;
--- ---
@ -54,7 +54,7 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
> >
</div> </div>
</div> </div>
<p class="text-pretty text-sm font-light text-neutral-500"> <p class="text-pretty text-sm text-neutral-500">
Table of Contents: Table of Contents:
</p> </p>
<div id="toc" class=""> <div id="toc" class="">

View file

@ -20,9 +20,9 @@ export async function getStaticPaths() {
id.startsWith("fr/") id.startsWith("fr/")
); );
return productEntries.map((product) => { return productEntries.map((product) => {
const slugWithoutLang = product.slug.replace(/^fr\//, ""); // Remove the "fr/" prefix const idWithoutLang = product.id.replace(/^fr\//, ""); // Remove the "fr/" prefix
return { return {
params: { lang: "fr", slug: slugWithoutLang }, params: { lang: "fr", id: idWithoutLang },
props: { product }, props: { product },
}; };
}); });

View file

@ -3,7 +3,7 @@
import { SITE } from "@data/constants"; import { SITE } from "@data/constants";
import MainLayout from "@/layouts/MainLayout.astro"; import MainLayout from "@/layouts/MainLayout.astro";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import { getCollection } from "astro:content"; import { getCollection, render } from "astro:content";
// Use `getStaticPaths` to generate static routes for generated pages on build // Use `getStaticPaths` to generate static routes for generated pages on build
export async function getStaticPaths() { export async function getStaticPaths() {
@ -11,9 +11,9 @@ export async function getStaticPaths() {
id.startsWith("en/") id.startsWith("en/")
); );
return insightPosts.map((post) => { return insightPosts.map((post) => {
const slugWithoutLang = post.slug.replace(/^en\//, ""); // Remove the "fr/" prefix const idWithoutLang = post.id.replace(/^en\//, ""); // Remove the "fr/" prefix
return { return {
params: { slug: slugWithoutLang }, params: { id: idWithoutLang },
props: { post }, props: { post },
}; };
}); });
@ -22,7 +22,7 @@ export async function getStaticPaths() {
// Get the props for this page that define a specific insight post // Get the props for this page that define a specific insight post
const { post } = Astro.props; const { post } = Astro.props;
const { Content } = await post.render(); const { Content } = await render(post);
const pageTitle: string = `${post.data.title} | ${SITE.title}`; const pageTitle: string = `${post.data.title} | ${SITE.title}`;
--- ---
@ -56,7 +56,7 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
> >
</div> </div>
</div> </div>
<p class="text-pretty text-sm font-light text-neutral-500"> <p class="text-pretty text-sm text-neutral-500">
Table of Contents: Table of Contents:
</p> </p>
<div id="toc" class=""> <div id="toc" class="">

View file

@ -21,9 +21,9 @@ export async function getStaticPaths() {
id.startsWith("en/") id.startsWith("en/")
); );
return productEntries.map((product) => { return productEntries.map((product) => {
const slugWithoutLang = product.slug.replace(/^en\//, ""); // Remove the "en/" prefix const idWithoutLang = product.id.replace(/^en\//, ""); // Remove the "en/" prefix
return { return {
params: { slug: slugWithoutLang }, params: { id: idWithoutLang },
props: { product }, props: { product },
}; };
}); });

View file

@ -12,5 +12,7 @@
"@styles/*": ["src/assets/styles/*"], "@styles/*": ["src/assets/styles/*"],
"@utils/*": ["src/utils/*"] "@utils/*": ["src/utils/*"]
}, },
} },
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
} }