diff --git a/astro.config.mjs b/astro.config.mjs index d2c210c..458ba56 100755 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -7,12 +7,26 @@ import { defineConfig, squooshImageService } from "astro/config"; import remarkCollapse from "remark-collapse"; import remarkToc from "remark-toc"; import config from "./src/config/config.json"; +import languagesJSON from "./src/config/language.json"; +const { default_language } = config.settings; + +const supportedLang = [...languagesJSON.map((lang) => lang.languageCode)]; +const disabledLanguages = config.settings.disable_languages; + +// Filter out disabled languages from supportedLang +const filteredSupportedLang = supportedLang.filter( + (lang) => !disabledLanguages.includes(lang), +); // https://astro.build/config export default defineConfig({ site: config.site.base_url ? config.site.base_url : "http://examplesite.com", base: config.site.base_path ? config.site.base_path : "/", - trailingSlash: config.site.trailing_slash ? "always" : "never", + trailingSlash: config.site.trailing_slash ? "always" : "ignore", + i18n: { + locales: filteredSupportedLang, + defaultLocale: default_language, + }, image: { service: squooshImageService(), }, diff --git a/package.json b/package.json index 5f30638..2581fc6 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "astroplate", - "version": "3.4.5", + "version": "4.0.0", "description": "Astro and Tailwindcss boilerplate", "author": "zeon.studio", "license": "MIT", @@ -11,50 +11,51 @@ "preview": "astro preview", "format": "prettier -w ./src", "generate-json": "node scripts/jsonGenerator.js", - "remove-darkmode": "node scripts/removeDarkmode.js && yarn format" + "remove-darkmode": "node scripts/removeDarkmode.js && yarn format", + "remove-multilang": "node scripts/removeMultilang.js && yarn format" }, "dependencies": { - "@astrojs/mdx": "^2.3.0", - "@astrojs/react": "^3.3.0", - "@astrojs/rss": "^4.0.5", - "@astrojs/sitemap": "^3.1.2", + "@astrojs/mdx": "^3.1.3", + "@astrojs/react": "^3.6.1", + "@astrojs/rss": "^4.0.7", + "@astrojs/sitemap": "^3.1.6", "@astrojs/tailwind": "^5.1.0", - "astro": "^4.6.1", + "astro": "^4.12.3", "astro-auto-import": "^0.4.2", - "astro-font": "^0.0.80", + "astro-font": "^0.0.81", "date-fns": "^3.6.0", "disqus-react": "^1.1.5", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", - "marked": "^12.0.1", - "prettier-plugin-astro": "^0.13.0", - "prettier-plugin-tailwindcss": "^0.5.13", + "marked": "^13.0.3", + "prettier-plugin-astro": "^0.14.1", + "prettier-plugin-tailwindcss": "^0.6.5", "prop-types": "^15.8.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-icons": "^5.0.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-icons": "^5.2.1", "react-lite-youtube-embed": "^2.4.0", "remark-collapse": "^0.1.2", "remark-toc": "^9.0.0", - "swiper": "^11.1.1" + "swiper": "^11.1.8" }, "devDependencies": { "@tailwindcss/forms": "^0.5.7", - "@tailwindcss/typography": "^0.5.12", + "@tailwindcss/typography": "^0.5.13", "@types/marked": "^5.0.2", - "@types/node": "20.12.7", - "@types/react": "18.2.78", - "@types/react-dom": "18.2.25", + "@types/node": "22.0.0", + "@types/react": "18.3.3", + "@types/react-dom": "18.3.0", "autoprefixer": "^10.4.19", - "eslint": "^9.0.0", - "postcss": "^8.4.38", - "prettier": "^3.2.5", - "prettier-plugin-astro": "^0.13.0", - "prettier-plugin-tailwindcss": "^0.5.13", - "sass": "^1.75.0", - "sharp": "0.33.1", + "eslint": "^9.8.0", + "postcss": "^8.4.40", + "prettier": "^3.3.3", + "prettier-plugin-astro": "^0.14.1", + "prettier-plugin-tailwindcss": "^0.6.5", + "sass": "^1.77.8", + "sharp": "0.33.4", "tailwind-bootstrap-grid": "^5.1.0", - "tailwindcss": "^3.4.3", - "typescript": "5.4.5" + "tailwindcss": "^3.4.7", + "typescript": "5.5.4" } } diff --git a/readme.md b/readme.md index a9badb4..ab5c00c 100755 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@

If you find this project useful, please give it a ⭐ to show your support.

-

👀 Demo | Page Speed (100%)🚀 +

👀 Demo | Page Speed (100%)🚀

@@ -26,6 +26,7 @@ ## 📌 Key Features - đŸ‘„ Multi-Authors +- 🌐 Multilingual - 🎯 Similar Posts Suggestion - 🔍 Search Functionality - 🌑 Dark Mode @@ -65,10 +66,10 @@ ### 📩 Dependencies -- astro 4.0+ +- astro v4.12+ - node v20.10+ - npm v10.2+ -- tailwind v3.3+ +- tailwind v3.4+ ### 👉 Install Dependencies @@ -109,12 +110,14 @@ docker run -it --rm astroplate ash ``` + ## 🐞 Reporting Issues We use GitHub Issues as the official bug tracker for this Template. Please Search [existing issues](https://github.com/zeon-studio/astroplate/issues). It’s possible someone has already reported the same problem. If your problem or idea has not been addressed yet, feel free to [open a new issue](https://github.com/zeon-studio/astroplate/issues). + ## 📝 License Copyright (c) 2023 - Present, Designed & Developed by [Zeon Studio](https://zeon.studio/) diff --git a/scripts/jsonGenerator.js b/scripts/jsonGenerator.js index 8aee1ac..5881da2 100644 --- a/scripts/jsonGenerator.js +++ b/scripts/jsonGenerator.js @@ -1,49 +1,66 @@ const fs = require("fs"); const path = require("path"); const matter = require("gray-matter"); +const languages = require("../src/config/language.json"); -const CONTENT_DEPTH = 2; const JSON_FOLDER = "./.json"; -const BLOG_FOLDER = "src/content/blog"; +const CONTENT_ROOT = "src/content"; +const CONTENT_DEPTH = 3; +const BLOG_FOLDER = "blog"; // get data from markdown -const getData = (folder, groupDepth) => { - const getPath = fs.readdirSync(folder); - const removeIndex = getPath.filter((item) => !item.startsWith("-")); +const getData = (folder, groupDepth, langIndex = 0) => { + const getPaths = languages + .map((lang, index) => { + const langFolder = lang.contentDir ? lang.contentDir : lang.languageCode; + const dir = path.join(CONTENT_ROOT, folder, langFolder); + return fs + .readdirSync(dir) + .filter( + (filename) => + !filename.startsWith("-") && + (filename.endsWith(".md") || filename.endsWith(".mdx")), + ) + .flatMap((filename) => { + const filepath = path.join(dir, filename); + const stats = fs.statSync(filepath); + const isFolder = stats.isDirectory(); - const getPaths = removeIndex.flatMap((filename) => { - const filepath = path.join(folder, filename); - const stats = fs.statSync(filepath); - const isFolder = stats.isDirectory(); + if (isFolder) { + return getData(filepath, groupDepth, index); + } else { + const file = fs.readFileSync(filepath, "utf-8"); + const { data, content } = matter(file); + const pathParts = filepath.split(path.sep); - if (isFolder) { - return getData(filepath, groupDepth); - } else if (filename.endsWith(".md") || filename.endsWith(".mdx")) { - const file = fs.readFileSync(filepath, "utf-8"); - const { data, content } = matter(file); - const pathParts = filepath.split(path.sep); - const slug = - data.slug || - pathParts - .slice(CONTENT_DEPTH) - .join("/") - .replace(/\.[^/.]+$/, ""); - const group = pathParts[groupDepth]; + let slug; + if (data.slug) { + const slugParts = data.slug.split("/"); + slugParts[0] = BLOG_FOLDER; + slug = slugParts.join("/"); + } else { + slug = pathParts + .slice(CONTENT_DEPTH) + .join("/") + .replace(/\.[^/.]+$/, ""); + slug = `${BLOG_FOLDER}/${slug.split("/").slice(1).join("/")}`; + } + data.slug = slug; + const group = "blog"; - return { - group: group, - slug: slug, - frontmatter: data, - content: content, - }; - } else { - return []; - } - }); + return { + lang: languages[index].languageCode, // Set the correct language code dynamically + group: group, + slug: data.slug, + frontmatter: data, + content: content, + }; + } + }); + }) + .flat(); - const publishedPages = getPaths.filter( - (page) => !page.frontmatter?.draft && page, - ); + const publishedPages = getPaths.filter((page) => !page.frontmatter?.draft); return publishedPages; }; @@ -56,10 +73,10 @@ try { // create json files fs.writeFileSync( `${JSON_FOLDER}/posts.json`, - JSON.stringify(getData(BLOG_FOLDER, 2)), + JSON.stringify(getData(BLOG_FOLDER, 3)), ); - // merger json files for search + // merge json files for search const posts = require(`../${JSON_FOLDER}/posts.json`); const search = [...posts]; fs.writeFileSync(`${JSON_FOLDER}/search.json`, JSON.stringify(search)); diff --git a/scripts/removeMultilang.js b/scripts/removeMultilang.js new file mode 100644 index 0000000..d885069 --- /dev/null +++ b/scripts/removeMultilang.js @@ -0,0 +1,72 @@ +const fs = require("fs"); +const path = require("path"); +const languages = require("../src/config/language.json"); + +// Filter out the English language +const englishLang = languages.filter((item) => item.languageCode === "en"); +const filterLangs = languages.filter((item) => item.languageCode !== "en"); +const contentDir = "src/content"; +const configDir = "src/config"; +const i18nDir = "src/i18n"; + +// Update language.json to only include the English language +fs.writeFileSync( + path.join(configDir, "language.json"), + JSON.stringify(englishLang, null, 2), +); + +// Remove content directories for languages other than English +filterLangs.forEach((lang) => { + const langContentDir = path.join(contentDir, lang.contentDir); + fs.rm(langContentDir, { recursive: true, force: true }, (err) => { + if (err) { + console.error(`Error deleting folder ${langContentDir}:`, err); + return; + } + console.log(`Folder ${langContentDir} deleted successfully`); + }); +}); + +// Remove other menu.{lang}.json files except menu.en.json +fs.readdir(configDir, (err, files) => { + if (err) { + console.error("Error reading config directory:", err); + return; + } + + files.forEach((file) => { + if (file.startsWith("menu.") && file !== "menu.en.json") { + const filePath = path.join(configDir, file); + fs.unlink(filePath, (err) => { + if (err) { + console.error(`Error deleting file ${filePath}:`, err); + return; + } + console.log(`File ${filePath} deleted successfully`); + }); + } + }); +}); + +// Remove other language files from i18n folder except en.json +fs.readdir(i18nDir, (err, files) => { + if (err) { + console.error("Error reading i18n directory:", err); + return; + } + + files.forEach((file) => { + if (file !== "en.json") { + const filePath = path.join(i18nDir, file); + fs.unlink(filePath, (err) => { + if (err) { + console.error(`Error deleting file ${filePath}:`, err); + return; + } + console.log(`File ${filePath} deleted successfully`); + }); + } + }); +}); + +console.log("Cleanup completed."); diff --git a/src/config/config.json b/src/config/config.json index 683fe50..3b3d910 100755 --- a/src/config/config.json +++ b/src/config/config.json @@ -19,7 +19,10 @@ "default_theme": "system", "pagination": 2, "summary_length": 200, - "blog_folder": "blog" + "blog_folder": "blog", + "default_language": "en", + "disable_languages": [], + "default_language_in_subdir": false }, "params": { diff --git a/src/config/language.json b/src/config/language.json new file mode 100644 index 0000000..706b137 --- /dev/null +++ b/src/config/language.json @@ -0,0 +1,14 @@ +[ + { + "languageName": "En", + "languageCode": "en", + "contentDir": "english", + "weight": 1 + }, + { + "languageName": "Fr", + "languageCode": "fr", + "contentDir": "french", + "weight": 2 + } +] diff --git a/src/config/menu.en.json b/src/config/menu.en.json new file mode 100644 index 0000000..9f52c3a --- /dev/null +++ b/src/config/menu.en.json @@ -0,0 +1,24 @@ +{ + "main": [ + { "name": "Home", "url": "/" }, + { "name": "About", "url": "/about" }, + { "name": "Elements", "url": "/elements" }, + { + "name": "Pages", + "url": "", + "hasChildren": true, + "children": [ + { "name": "Contact", "url": "/contact" }, + { "name": "Blog", "url": "/blog" }, + { "name": "Authors", "url": "/authors" }, + { "name": "Categories", "url": "/categories" }, + { "name": "Tags", "url": "/tags" }, + { "name": "404 Page", "url": "/404" } + ] + } + ], + "footer": [ + { "name": "Elements", "url": "/elements" }, + { "name": "Privacy Policy", "url": "/privacy-policy" } + ] +} diff --git a/src/config/menu.fr.json b/src/config/menu.fr.json new file mode 100644 index 0000000..495c883 --- /dev/null +++ b/src/config/menu.fr.json @@ -0,0 +1,24 @@ +{ + "main": [ + { "name": "Accueil", "url": "/" }, + { "name": "À propos", "url": "/about" }, + { "name": "ÉlĂ©ments", "url": "/elements" }, + { + "name": "Pages", + "url": "", + "hasChildren": true, + "children": [ + { "name": "Contact", "url": "/contact" }, + { "name": "Blog", "url": "/blog" }, + { "name": "Auteurs", "url": "/authors" }, + { "name": "CatĂ©gories", "url": "/categories" }, + { "name": "Étiquettes", "url": "/tags" }, + { "name": "Page 404", "url": "/404" } + ] + } + ], + "footer": [ + { "name": "ÉlĂ©ments", "url": "/elements" }, + { "name": "Politique de confidentialitĂ©", "url": "/privacy-policy" } + ] +} diff --git a/src/config/menu.json b/src/config/menu.json deleted file mode 100755 index 3502218..0000000 --- a/src/config/menu.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "main": [ - { - "name": "Home", - "url": "/" - }, - { - "name": "About", - "url": "/about" - }, - { - "name": "Elements", - "url": "/elements" - }, - { - "name": "Pages", - "url": "", - "hasChildren": true, - "children": [ - { - "name": "Contact", - "url": "/contact" - }, - { - "name": "Blog", - "url": "/blog" - }, - { - "name": "Authors", - "url": "/authors" - }, - { - "name": "Categories", - "url": "/categories" - }, - { - "name": "Tags", - "url": "/tags" - }, - { - "name": "404 Page", - "url": "/404" - } - ] - } - ], - "footer": [ - { - "name": "Elements", - "url": "/elements" - }, - { - "name": "Privacy Policy", - "url": "/privacy-policy" - } - ] -} diff --git a/src/content/about/-index.md b/src/content/about/english/-index.md similarity index 100% rename from src/content/about/-index.md rename to src/content/about/english/-index.md diff --git a/src/content/about/french/-index.md b/src/content/about/french/-index.md new file mode 100644 index 0000000..041c6ad --- /dev/null +++ b/src/content/about/french/-index.md @@ -0,0 +1,9 @@ +--- +title: "HĂ©, je suis John Doe !" +meta_title: "About" +description: "this is meta description" +image: "/images/avatar.png" +draft: false +--- + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Ils ne connaissent pas les bienfaits du corps, ou sauf qu'ils le recevront Ă  d'autres moments, le tout, les temps de travail, qu'il dĂ©teste Ă  partir de ce moment mais. Il fuit les plaisirs perçus pour ĂȘtre supposĂ©s n'ĂȘtre rien, tout ou, et la douleur est ce qui est la plus grande option, car cela lui est facile, et avec ce que cela s'ensuit, ils lui procurent de la douleur et ainsi de suite ! Car ledit expĂ©dient de la vĂ©ritĂ© repousse le plaisir et empĂȘche la douleur, ils fournissent comme si diff --git a/src/content/authors/-index.md b/src/content/authors/english/-index.md similarity index 100% rename from src/content/authors/-index.md rename to src/content/authors/english/-index.md diff --git a/src/content/authors/john-doe.md b/src/content/authors/english/john-doe.md similarity index 100% rename from src/content/authors/john-doe.md rename to src/content/authors/english/john-doe.md diff --git a/src/content/authors/sam-wilson.md b/src/content/authors/english/sam-wilson.md similarity index 100% rename from src/content/authors/sam-wilson.md rename to src/content/authors/english/sam-wilson.md diff --git a/src/content/authors/william-jacob.md b/src/content/authors/english/william-jacob.md similarity index 100% rename from src/content/authors/william-jacob.md rename to src/content/authors/english/william-jacob.md diff --git a/src/content/authors/french/-index.md b/src/content/authors/french/-index.md new file mode 100644 index 0000000..517a9bf --- /dev/null +++ b/src/content/authors/french/-index.md @@ -0,0 +1,5 @@ +--- +title: "Auteurs" +meta_title: "" +description: "this is meta description" +--- diff --git a/src/content/authors/french/john-doe.md b/src/content/authors/french/john-doe.md new file mode 100644 index 0000000..857f439 --- /dev/null +++ b/src/content/authors/french/john-doe.md @@ -0,0 +1,20 @@ +--- +title: John Doe +email: johndoe@email.com +image: "/images/avatar.png" +description: this is meta description +social: + - name: github + icon: FaGithub + link: https://github.com + + - name: twitter + icon: FaTwitter + link: https://twitter.com + + - name: linkedin + icon: FaLinkedin + link: https://linkedin.com +--- + +lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr navigation et dolore magna aliqua. diff --git a/src/content/authors/french/sam-wilson.md b/src/content/authors/french/sam-wilson.md new file mode 100644 index 0000000..d3ab0e5 --- /dev/null +++ b/src/content/authors/french/sam-wilson.md @@ -0,0 +1,20 @@ +--- +title: Sam Wilson +email: samwilson@email.com +image: "/images/avatar.png" +description: this is meta description +social: + - name: github + icon: FaGithub + link: https://github.com + + - name: twitter + icon: FaTwitter + link: https://twitter.com + + - name: linkedin + icon: FaLinkedin + link: https://linkedin.com +--- + +lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr navigation et dolore magna aliqua. diff --git a/src/content/authors/french/william-jacob.md b/src/content/authors/french/william-jacob.md new file mode 100644 index 0000000..193589a --- /dev/null +++ b/src/content/authors/french/william-jacob.md @@ -0,0 +1,20 @@ +--- +title: Guillaume Jacob +email: williamjacob@email.com +image: "/images/avatar.png" +description: this is meta description +social: + - name: github + icon: FaGithub + link: https://github.com + + - name: twitter + icon: FaTwitter + link: https://twitter.com + + - name: linkedin + icon: FaLinkedin + link: https://linkedin.com +--- + +lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr navigation et dolore magna aliqua. diff --git a/src/content/blog/-index.md b/src/content/blog/english/-index.md similarity index 100% rename from src/content/blog/-index.md rename to src/content/blog/english/-index.md diff --git a/src/content/blog/post-1.md b/src/content/blog/english/post-1.md similarity index 100% rename from src/content/blog/post-1.md rename to src/content/blog/english/post-1.md diff --git a/src/content/blog/post-2.md b/src/content/blog/english/post-2.md similarity index 100% rename from src/content/blog/post-2.md rename to src/content/blog/english/post-2.md diff --git a/src/content/blog/post-3.md b/src/content/blog/english/post-3.md similarity index 100% rename from src/content/blog/post-3.md rename to src/content/blog/english/post-3.md diff --git a/src/content/blog/post-4.md b/src/content/blog/english/post-4.md similarity index 100% rename from src/content/blog/post-4.md rename to src/content/blog/english/post-4.md diff --git a/src/content/blog/french/-index.md b/src/content/blog/french/-index.md new file mode 100755 index 0000000..eac3331 --- /dev/null +++ b/src/content/blog/french/-index.md @@ -0,0 +1,5 @@ +--- +title: "Articles de blog" +meta_title: "" +description: "Ceci est une mĂ©ta-description" +--- diff --git a/src/content/blog/french/post-1.md b/src/content/blog/french/post-1.md new file mode 100755 index 0000000..8d1a370 --- /dev/null +++ b/src/content/blog/french/post-1.md @@ -0,0 +1,23 @@ +--- +title: "Comment crĂ©er une application avec des technologies modernes" +meta_title: "" +description: "Ceci est une mĂ©ta-description" +date: 2022-04-04T05:00:00Z +image: "/images/image-placeholder.png" +categories: ["french","Application", "Data"] +author: "John Doe" +tags: ["nextjs", "tailwind", "react"] +draft: false +--- + +Personne ne veut mĂȘme sortir un maquillage de l'urne des soins empoisonnĂ©s. C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +## Design CrĂ©atif + +Car en guise de maquillage, l'urne du poison C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +> Le client lui-mĂȘme doit pouvoir poursuivre l'adipisicing. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! diff --git a/src/content/blog/french/post-2.md b/src/content/blog/french/post-2.md new file mode 100755 index 0000000..38a17df --- /dev/null +++ b/src/content/blog/french/post-2.md @@ -0,0 +1,23 @@ +--- +title: "Comment crĂ©er une application avec des technologies modernes" +meta_title: "" +description: "Ceci est une mĂ©ta-description" +date: 2022-04-04T05:00:00Z +image: "/images/image-placeholder.png" +categories: ["Technology", "Data"] +author: "Sam Wilson" +tags: ["technology", "tailwind"] +draft: false +--- + +Personne ne veut mĂȘme sortir un maquillage de l'urne des soins empoisonnĂ©s. C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +## Design CrĂ©atif + +Car en guise de maquillage, l'urne du poison C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +> Le client lui-mĂȘme doit pouvoir poursuivre l'adipisicing. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! diff --git a/src/content/blog/french/post-3.md b/src/content/blog/french/post-3.md new file mode 100755 index 0000000..7c1fb81 --- /dev/null +++ b/src/content/blog/french/post-3.md @@ -0,0 +1,23 @@ +--- +title: "Comment crĂ©er une application avec des technologies modernes" +meta_title: "" +description: "Ceci est une mĂ©ta-description" +date: 2022-04-04T05:00:00Z +image: "/images/image-placeholder.png" +categories: ["Software"] +author: "John Doe" +tags: ["software", "tailwind"] +draft: false +--- + +Personne ne veut mĂȘme sortir un maquillage de l'urne des soins empoisonnĂ©s. C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +## Design CrĂ©atif + +Car en guise de maquillage, l'urne du poison C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +> Le client lui-mĂȘme doit pouvoir poursuivre l'adipisicing. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! diff --git a/src/content/blog/french/post-4.md b/src/content/blog/french/post-4.md new file mode 100755 index 0000000..d489e36 --- /dev/null +++ b/src/content/blog/french/post-4.md @@ -0,0 +1,23 @@ +--- +title: "Comment crĂ©er une application avec des technologies modernes" +meta_title: "" +description: "Ceci est une mĂ©ta-description" +date: 2022-04-04T05:00:00Z +image: "/images/image-placeholder.png" +categories: ["Architecture"] +author: "John Doe" +tags: ["silicon", "technology"] +draft: false +--- + +Personne ne veut mĂȘme sortir un maquillage de l'urne des soins empoisonnĂ©s. C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +## Design CrĂ©atif + +Car en guise de maquillage, l'urne du poison C'Ă©tait un week-end. Je suis un footballeur complet. Pour boire, le lac occupe le plus grand porche. Chacune des cibles de la vie ne flatte pas Euismod. + +> Le client lui-mĂȘme doit pouvoir poursuivre l'adipisicing. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! + +L'entreprise elle-mĂȘme est une entreprise trĂšs prospĂšre. Personne ne prend mĂȘme la peine de l'ouvrir. Alors je vais ouvrir la naissance pour choisir ? Être rejetĂ© par certaines personnes est un choix commode du prĂ©sent pour ressentir une douleur comme la sienne ! diff --git a/src/content/config.ts b/src/content/config.ts index 6b926a5..c690a41 100755 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -1,6 +1,6 @@ import { defineCollection, z } from "astro:content"; -// Post collection schema +// Blog collection schema const blogCollection = defineCollection({ schema: z.object({ title: z.string(), @@ -49,9 +49,96 @@ const pagesCollection = defineCollection({ }), }); +// Contact collection schema +const contactCollection = defineCollection({ + schema: z.object({ + title: z.string(), + meta_title: z.string().optional(), + description: z.string(), + image: z.string().optional(), + draft: z.boolean().optional(), + }), +}); + +// About collection schema +const aboutCollection = defineCollection({ + schema: z.object({ + title: z.string(), + meta_title: z.string().optional(), + description: z.string().optional(), + image: z.string(), + draft: z.boolean().optional(), + }), +}); + +// Banner schema +const bannerSchema = z.object({ + title: z.string(), + content: z.string(), + image: z.string(), + button: z.object({ + enable: z.boolean(), + label: z.string(), + link: z.string(), + }), +}); + +// Features schema +const featureSchema = z.object({ + title: z.string(), + image: z.string(), + content: z.string(), + bulletpoints: z.array(z.string()), + button: z.object({ + enable: z.boolean(), + label: z.string().optional(), + link: z.string().optional(), + }), +}); + +// Content schema (for the main content structure with banner and features) +const contentSchema = z.object({ + banner: bannerSchema, + features: z.array(featureSchema), +}); + +// Content collection schema +const contentCollection = defineCollection({ + schema: contentSchema, +}); + +// Testimonial schema +const testimonialSchema = z.object({ + name: z.string(), + designation: z.string(), + avatar: z.string(), + content: z.string(), +}); + +// Testimonials schema +const testimonialsSchema = z.array(testimonialSchema); + +// Call to Action schema +const callToActionSchema = z.object({ + enable: z.boolean(), + title: z.string(), + image: z.string(), + description: z.string(), + button: z.object({ + enable: z.boolean(), + label: z.string(), + link: z.string().url(), + }), +}); + // Export collections export const collections = { blog: blogCollection, authors: authorsCollection, pages: pagesCollection, + contact: contactCollection, + about: aboutCollection, + content: contentCollection, + testimonials: testimonialsSchema, + callToAction: callToActionSchema, }; diff --git a/src/content/contact/-index.md b/src/content/contact/english/-index.md similarity index 100% rename from src/content/contact/-index.md rename to src/content/contact/english/-index.md diff --git a/src/content/contact/french/-index.md b/src/content/contact/french/-index.md new file mode 100644 index 0000000..bd6b9f6 --- /dev/null +++ b/src/content/contact/french/-index.md @@ -0,0 +1,6 @@ +--- +title: "Contact" +meta_title: "" +description: "this is meta description" +draft: false +--- diff --git a/src/content/homepage/-index.md b/src/content/homepage/english/-index.md similarity index 100% rename from src/content/homepage/-index.md rename to src/content/homepage/english/-index.md diff --git a/src/content/homepage/french/-index.md b/src/content/homepage/french/-index.md new file mode 100755 index 0000000..be96b3f --- /dev/null +++ b/src/content/homepage/french/-index.md @@ -0,0 +1,53 @@ +--- +# Banner +banner: + title: "Le modĂšle de dĂ©marrage ultime dont vous avez besoin pour dĂ©marrer votre projet Astro" + content: "Astroplate est un modĂšle de dĂ©marrage gratuit construit avec Astro et TailwindCSS, fournissant tout ce dont vous avez besoin pour dĂ©marrer votre projet Astro et gagner un temps prĂ©cieux." + image: "/images/banner.png" + button: + enable: true + label: "Commencer gratuitement" + link: "https://github.com/zeon-studio/astroplate" + +# Features +features: + - title: "Ce qui est inclus dans Astroplate" + image: "/images/service-1.png" + content: "Astroplate est un modĂšle de dĂ©marrage complet qui inclut tout ce dont vous avez besoin pour dĂ©marrer votre projet Astro. Ce qui est inclus dans Astroplate" + bulletpoints: + - "10+ pages prĂ©-construites" + - "Score Google Pagespeed de 95+" + - "Construit avec Astro et TailwindCSS pour un style facile et personnalisable" + - "EntiĂšrement responsive sur tous les appareils" + - "OptimisĂ© pour le rĂ©fĂ©rencement pour de meilleurs classements dans les moteurs de recherche" + - "**Open-source et gratuit** pour une utilisation personnelle et commerciale" + button: + enable: false + label: "Commencer maintenant" + link: "#" + + - title: "DĂ©couvrez les fonctionnalitĂ©s clĂ©s d'Astro" + image: "/images/service-2.png" + content: "Astro est un framework web tout-en-un pour construire des sites web rapides et centrĂ©s sur le contenu. Il offre une gamme de fonctionnalitĂ©s excitantes pour les dĂ©veloppeurs et les crĂ©ateurs de sites web. Certaines des fonctionnalitĂ©s clĂ©s sont :" + bulletpoints: + - "ZĂ©ro JS, par dĂ©faut : Aucun surcoĂ»t d'exĂ©cution JavaScript pour vous ralentir." + - "Personnalisable : Tailwind, MDX et plus de 100 autres intĂ©grations au choix." + - "Agnostique Ă  l'UI : Supporte React, Preact, Svelte, Vue, Solid, Lit et plus encore." + button: + enable: true + label: "Commencer maintenant" + link: "https://github.com/zeon-studio/astroplate" + + - title: "Les principales raisons de choisir Astro pour votre prochain projet" + image: "/images/service-3.png" + content: "Avec Astro, vous pouvez construire des sites web modernes et centrĂ©s sur le contenu sans sacrifier la performance ou la facilitĂ© d'utilisation." + bulletpoints: + - "Charge instantanĂ©e des sites statiques pour une meilleure expĂ©rience utilisateur et SEO." + - "Syntaxe intuitive et support pour les frameworks populaires rendent l'apprentissage et l'utilisation d'Astro un jeu d'enfant." + - "Utilisez n'importe quelle bibliothĂšque ou framework front-end, ou construisez des composants personnalisĂ©s, pour tout type de projet." + - "Construit sur une technologie de pointe pour garder vos projets Ă  jour avec les derniĂšres normes web." + button: + enable: false + label: "" + link: "" +--- diff --git a/src/content/pages/elements.mdx b/src/content/pages/english/elements.mdx similarity index 100% rename from src/content/pages/elements.mdx rename to src/content/pages/english/elements.mdx diff --git a/src/content/pages/privacy-policy.md b/src/content/pages/english/privacy-policy.md similarity index 100% rename from src/content/pages/privacy-policy.md rename to src/content/pages/english/privacy-policy.md diff --git a/src/content/pages/french/elements.mdx b/src/content/pages/french/elements.mdx new file mode 100755 index 0000000..c0301a3 --- /dev/null +++ b/src/content/pages/french/elements.mdx @@ -0,0 +1,255 @@ +--- +title: "ÉlĂ©ments" +meta_title: "" +description: "Ceci est une mĂ©ta-description" +draft: false +--- + +# Titre 1 + +## Titre 2 + +### Titre 3 + +#### Titre 4 + +##### Titre 5 + +###### Titre 6 + +--- + +### Paragraphe + +Êtes-vous venu ici pour quelque chose en particulier ou juste pour critiquer Riker? Et en entrant Ă  vitesse maximale, vous ĂȘtes apparu pour un instant ĂȘtre Ă  deux endroits Ă  la fois. Nous avons un saboteur Ă  bord. Nous savons que vous vous occupez de minerai volĂ©. Mais je veux parler de la tentative d'assassinat sur le Lieutenant Worf. Quelqu'un pourrait-il survivre dans un tampon de tĂ©lĂ©porteur pendant 75 ans? Le destin. Il protĂšge les fous, les petits enfants et les navires. + +Êtes-vous venu ici pour quelque chose en particulier ou juste pour critiquer Riker? Et en entrant Ă  vitesse maximale, vous ĂȘtes apparu pour un instant ĂȘtre Ă  deux endroits Ă  la fois. Nous avons un saboteur Ă  bord. Nous savons que vous vous occupez de minerai volĂ©. Mais je veux parler de la tentative d'assassinat sur le Lieutenant Worf. Quelqu'un pourrait-il survivre dans un tampon de tĂ©lĂ©porteur pendant 75 ans? Le destin. Il protĂšge les fous, les petits enfants et les navires. + +--- + +### Emphase + +1. Êtes-vous venu ici pour quelque chose en **particulier** ou juste en gĂ©nĂ©ral + +2. Êtes-vous venu ici pour quelque chose en particulier + +3. _Êtes-vous venu ici_ + +4. Êtes-vous venu ici pour **quelque chose** en particulier + +5. Êtes-vous venu ici pour quelque chose en particulier + +6. Êtes-vous venu ici pour quelque chose en particulier + +7. Les URLs et les URLs entre crochets seront automatiquement transformĂ©es en liens. [http://www.example.com](http://www.example.com) ou + +8. [http://www.example.com](http://www.example.com) et parfois example.com (mais pas sur Github, par exemple). + +--- + +### Lien + +[Je suis un lien en ligne](https://www.google.com) + +[Je suis un lien en ligne avec titre](https://www.google.com "Page d'accueil de Google") + +[Je suis un lien de rĂ©fĂ©rence][texte de rĂ©fĂ©rence insensible Ă  la casse] + +[Je suis une rĂ©fĂ©rence relative Ă  un fichier de dĂ©pĂŽt](../blob/master/LICENSE) + +[Vous pouvez utiliser des chiffres pour les dĂ©finitions de liens de rĂ©fĂ©rence][1] + +Ou laissez-le vide et utilisez [le texte du lien lui-mĂȘme]. + +example.com (mais pas sur Github, par exemple). + +Du texte pour montrer que les liens de rĂ©fĂ©rence peuvent suivre plus tard. + +[texte de rĂ©fĂ©rence insensible Ă  la casse]: https://www.themefisher.com +[1]: https://gethugothemes.com +[le texte du lien lui-mĂȘme]: https://www.getjekyllthemes.com + +--- + +### Liste OrdonnĂ©e + +1. ÉlĂ©ment de liste +2. ÉlĂ©ment de liste +3. ÉlĂ©ment de liste +4. ÉlĂ©ment de liste +5. ÉlĂ©ment de liste + +--- + +### Liste Non OrdonnĂ©e + +- ÉlĂ©ment de liste +- ÉlĂ©ment de liste +- ÉlĂ©ment de liste +- ÉlĂ©ment de liste +- ÉlĂ©ment de liste + +--- + +### Code and Syntax Highlighting + +#### HTML + +```html +

+``` + +--- + +#### CSS + +```css +img { + vertical-align: middle; + border: 0; + max-width: 100%; + height: auto; +} +``` + +--- + +#### JavaScript + +```javascript +window.addEventListener("load", (e) => { + document.querySelector(".preloader").style.display = "none"; +}); +``` + +--- + +### Button + + + diff --git a/src/pages/index.astro b/src/pages/[...lang]/index.astro similarity index 75% rename from src/pages/index.astro rename to src/pages/[...lang]/index.astro index 19d3f99..a4aae5f 100755 --- a/src/pages/index.astro +++ b/src/pages/[...lang]/index.astro @@ -1,27 +1,37 @@ --- import ImageMod from "@/components/ImageMod.astro"; import Base from "@/layouts/Base.astro"; +import { getListPage, getSinglePage } from "@/lib/contentParser.astro"; +import { supportedLang } from "@/lib/utils/languageParser"; import { markdownify } from "@/lib/utils/textConverter"; import CallToAction from "@/partials/CallToAction.astro"; import Testimonial from "@/partials/Testimonial.astro"; -import type { Button, Feature } from "@/types"; -import { getEntry } from "astro:content"; +import type { Feature } from "@/types"; +import type { ContentEntryMap } from "astro:content"; import { FaCheck } from "react-icons/fa"; -interface Homepage { - banner: { - title: string; - content: string; - image: string; - button: Button; - }; - features: Feature[]; +export function getStaticPaths() { + const paths = supportedLang.map((lang) => ({ + params: { lang: lang || undefined }, + })); + return paths; } -const homepage = await getEntry("homepage", "-index"); -const testimonial = await getEntry("sections", "testimonial"); -const call_to_action = await getEntry("sections", "call-to-action"); -const { banner, features }: Homepage = homepage.data; +const { lang } = Astro.params; +const homepage = await getListPage("homepage", lang as keyof ContentEntryMap); +const { banner, features } = homepage[0].data; + +const testimonial = await getSinglePage( + "sections", + lang as keyof ContentEntryMap, + "testimonial" +); + +const call_to_action = await getSinglePage( + "sections", + lang as keyof ContentEntryMap, + "call-to-action" +); --- @@ -70,7 +80,7 @@ const { banner, features }: Homepage = homepage.data; { - features.map((feature, index: number) => ( + features.map((feature: Feature, index: number) => (
@@ -109,6 +119,6 @@ const { banner, features }: Homepage = homepage.data; } - - + + diff --git a/src/pages/[...lang]/tags/[tag].astro b/src/pages/[...lang]/tags/[tag].astro new file mode 100644 index 0000000..ab84299 --- /dev/null +++ b/src/pages/[...lang]/tags/[tag].astro @@ -0,0 +1,75 @@ +--- +import BlogCard from "@/components/BlogCard.astro"; +import config from "@/config/config.json"; +import Base from "@/layouts/Base.astro"; +import { getSinglePage } from "@/lib/contentParser.astro"; +import { getTaxonomy } from "@/lib/taxonomyParser.astro"; +import { supportedLang } from "@/lib/utils/languageParser"; +import { sortByDate } from "@/lib/utils/sortFunctions"; +import taxonomyFilter from "@/lib/utils/taxonomyFilter"; +import PageHeader from "@/partials/PageHeader.astro"; +import type { ContentEntryMap } from "astro:content"; + +// get all static paths for tags +export async function getStaticPaths() { + const { default_language } = config.settings; + + const paths = await Promise.all( + supportedLang.map(async (lang) => { + const tags = await getTaxonomy(lang as keyof ContentEntryMap, "tags"); + + return tags.map((tag) => ({ + params: { + lang: lang || undefined, + tag: tag, + }, + props: { + tag, + }, + })); + }) + ); + + // Handle default path (no lang) + const defaultCategories = await getTaxonomy( + default_language as keyof ContentEntryMap, + "tags" + ); + const defaultPaths = defaultCategories.map((tag) => ({ + params: { + lang: undefined, + tag: tag, + }, + props: { + tag, + }, + })); + + return [...paths.flat(), ...defaultPaths]; +} + +const { tag, lang } = Astro.params; + +// get posts by tag +const BLOG_FOLDER = "blog"; +const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap); +const filterByTags = taxonomyFilter(posts, "tags", tag!); +const sortedPosts = sortByDate(filterByTags); +--- + + + +
+
+
+ { + sortedPosts.map((post) => ( +
+ +
+ )) + } +
+
+
+ diff --git a/src/pages/tags/index.astro b/src/pages/[...lang]/tags/index.astro old mode 100755 new mode 100644 similarity index 59% rename from src/pages/tags/index.astro rename to src/pages/[...lang]/tags/index.astro index 0989c16..68e8247 --- a/src/pages/tags/index.astro +++ b/src/pages/[...lang]/tags/index.astro @@ -1,13 +1,28 @@ --- +import config from "@/config/config.json"; import Base from "@/layouts/Base.astro"; import { getAllTaxonomy, getTaxonomy } from "@/lib/taxonomyParser.astro"; +import { slugSelector, supportedLang } from "@/lib/utils/languageParser"; import { humanize } from "@/lib/utils/textConverter"; import PageHeader from "@/partials/PageHeader.astro"; +import type { ContentEntryMap } from "astro:content"; +const { default_language } = config.settings; -const BLOG_FOLDER = "blog"; +export function getStaticPaths() { + const paths = supportedLang.map((lang) => ({ + params: { lang: lang || undefined }, + })); + return paths; +} -const tags = await getTaxonomy(BLOG_FOLDER, "tags"); -const allTags = await getAllTaxonomy(BLOG_FOLDER, "tags"); +let { lang } = Astro.params; + +if (!lang) { + lang = default_language; +} +const langCollection: keyof ContentEntryMap = lang as keyof ContentEntryMap; +const tags = await getTaxonomy(langCollection, "tags"); +const allTags = await getAllTaxonomy(langCollection, "tags"); --- @@ -21,7 +36,7 @@ const allTags = await getAllTaxonomy(BLOG_FOLDER, "tags"); return (
  • {humanize(tag)}{" "} diff --git a/src/pages/authors/index.astro b/src/pages/authors/index.astro deleted file mode 100755 index 8df557f..0000000 --- a/src/pages/authors/index.astro +++ /dev/null @@ -1,29 +0,0 @@ ---- -import AuthorCard from "@/components/AuthorCard.astro"; -import Base from "@/layouts/Base.astro"; -import { getSinglePage } from "@/lib/contentParser.astro"; -import PageHeader from "@/partials/PageHeader.astro"; -import { getEntry } from "astro:content"; - -const COLLECTION_FOLDER = "authors"; - -const authorIndex = await getEntry(COLLECTION_FOLDER, "-index"); -const authors = await getSinglePage(COLLECTION_FOLDER); ---- - - - -
    -
    -
    - { - authors.map((author) => ( -
    - -
    - )) - } -
    -
    -
    - diff --git a/src/pages/blog/[single].astro b/src/pages/blog/[single].astro deleted file mode 100755 index 984477b..0000000 --- a/src/pages/blog/[single].astro +++ /dev/null @@ -1,30 +0,0 @@ ---- -import Base from "@/layouts/Base.astro"; -import PostSingle from "@/layouts/PostSingle.astro"; -import { getSinglePage } from "@/lib/contentParser.astro"; - -export async function getStaticPaths() { - const BLOG_FOLDER = "blog"; - const posts = await getSinglePage(BLOG_FOLDER); - - const paths = posts.map((post) => ({ - params: { - single: post.slug, - }, - props: { post }, - })); - return paths; -} - -const { post } = Astro.props; -const { title, meta_title, description, image } = post.data; ---- - - - - diff --git a/src/pages/categories/[category].astro b/src/pages/categories/[category].astro deleted file mode 100755 index c5fbef9..0000000 --- a/src/pages/categories/[category].astro +++ /dev/null @@ -1,46 +0,0 @@ ---- -import BlogCard from "@/components/BlogCard.astro"; -import Base from "@/layouts/Base.astro"; -import { getSinglePage } from "@/lib/contentParser.astro"; -import { getTaxonomy } from "@/lib/taxonomyParser.astro"; -import { sortByDate } from "@/lib/utils/sortFunctions"; -import taxonomyFilter from "@/lib/utils/taxonomyFilter"; -import PageHeader from "@/partials/PageHeader.astro"; - -// get static paths for all categories -export async function getStaticPaths() { - const BLOG_FOLDER = "blog"; - const categories = await getTaxonomy(BLOG_FOLDER, "categories"); - - return categories.map((category) => { - return { - params: { category }, - }; - }); -} - -const { category } = Astro.params; - -// get posts by category -const BLOG_FOLDER = "blog"; -const posts = await getSinglePage(BLOG_FOLDER); -const filterByCategories = taxonomyFilter(posts, "categories", category!); -const sortedPosts = sortByDate(filterByCategories); ---- - - - -
    -
    -
    - { - sortedPosts.map((post) => ( -
    - -
    - )) - } -
    -
    -
    - diff --git a/src/pages/tags/[tag].astro b/src/pages/tags/[tag].astro deleted file mode 100755 index cd81405..0000000 --- a/src/pages/tags/[tag].astro +++ /dev/null @@ -1,45 +0,0 @@ ---- -import BlogCard from "@/components/BlogCard.astro"; -import Base from "@/layouts/Base.astro"; -import { getSinglePage } from "@/lib/contentParser.astro"; -import { getTaxonomy } from "@/lib/taxonomyParser.astro"; -import { sortByDate } from "@/lib/utils/sortFunctions"; -import taxonomyFilter from "@/lib/utils/taxonomyFilter"; -import PageHeader from "@/partials/PageHeader.astro"; - -export async function getStaticPaths() { - const BLOG_FOLDER = "blog"; - const tags = await getTaxonomy(BLOG_FOLDER, "tags"); - - return tags.map((tag) => { - return { - params: { tag }, - }; - }); -} - -const { tag } = Astro.params; - -// get posts by tag -const BLOG_FOLDER = "blog"; -const posts = await getSinglePage(BLOG_FOLDER); -const filterByTags = taxonomyFilter(posts, "tags", tag!); -const sortedPosts = sortByDate(filterByTags); ---- - - - -
    -
    -
    - { - sortedPosts.map((post) => ( -
    - -
    - )) - } -
    -
    -
    - diff --git a/src/styles/base.scss b/src/styles/base.scss index 2fac7c2..b568330 100755 --- a/src/styles/base.scss +++ b/src/styles/base.scss @@ -3,7 +3,7 @@ html { } body { - @apply bg-body text-base dark:bg-darkmode-body font-primary font-normal leading-relaxed text-text dark:text-darkmode-text; + @apply bg-body dark:bg-darkmode-body font-primary font-normal leading-relaxed text-text dark:text-darkmode-text; } h1, diff --git a/src/types/index.d.ts b/src/types/index.d.ts index acb3d63..fb8ccc0 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,3 +1,5 @@ +import type { ContentEntryMap } from "astro:content"; + export type Feature = { button: button; image: string;