mirror of
https://github.com/10h30/astroplate.git
synced 2026-07-11 18:56:06 +09:00
+26
-26
@@ -15,47 +15,47 @@
|
|||||||
"remove-multilang": "node scripts/removeMultilang.js && yarn format"
|
"remove-multilang": "node scripts/removeMultilang.js && yarn format"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^2.3.0",
|
"@astrojs/mdx": "^3.1.3",
|
||||||
"@astrojs/react": "^3.3.0",
|
"@astrojs/react": "^3.6.1",
|
||||||
"@astrojs/rss": "^4.0.5",
|
"@astrojs/rss": "^4.0.7",
|
||||||
"@astrojs/sitemap": "^3.1.2",
|
"@astrojs/sitemap": "^3.1.6",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"astro": "^4.6.1",
|
"astro": "^4.12.3",
|
||||||
"astro-auto-import": "^0.4.2",
|
"astro-auto-import": "^0.4.2",
|
||||||
"astro-font": "^0.0.80",
|
"astro-font": "^0.0.81",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"disqus-react": "^1.1.5",
|
"disqus-react": "^1.1.5",
|
||||||
"github-slugger": "^2.0.0",
|
"github-slugger": "^2.0.0",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"marked": "^12.0.1",
|
"marked": "^13.0.3",
|
||||||
"prettier-plugin-astro": "^0.13.0",
|
"prettier-plugin-astro": "^0.14.1",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.13",
|
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.2.1",
|
||||||
"react-lite-youtube-embed": "^2.4.0",
|
"react-lite-youtube-embed": "^2.4.0",
|
||||||
"remark-collapse": "^0.1.2",
|
"remark-collapse": "^0.1.2",
|
||||||
"remark-toc": "^9.0.0",
|
"remark-toc": "^9.0.0",
|
||||||
"swiper": "^11.1.1"
|
"swiper": "^11.1.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@tailwindcss/typography": "^0.5.12",
|
"@tailwindcss/typography": "^0.5.13",
|
||||||
"@types/marked": "^5.0.2",
|
"@types/marked": "^5.0.2",
|
||||||
"@types/node": "20.12.7",
|
"@types/node": "22.0.0",
|
||||||
"@types/react": "18.2.78",
|
"@types/react": "18.3.3",
|
||||||
"@types/react-dom": "18.2.25",
|
"@types/react-dom": "18.3.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.8.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.40",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.3.3",
|
||||||
"prettier-plugin-astro": "^0.13.0",
|
"prettier-plugin-astro": "^0.14.1",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.13",
|
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||||
"sass": "^1.75.0",
|
"sass": "^1.77.8",
|
||||||
"sharp": "0.33.1",
|
"sharp": "0.33.4",
|
||||||
"tailwind-bootstrap-grid": "^5.1.0",
|
"tailwind-bootstrap-grid": "^5.1.0",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.7",
|
||||||
"typescript": "5.4.5"
|
"typescript": "5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
## 📌 Key Features
|
## 📌 Key Features
|
||||||
|
|
||||||
- 👥 Multi-Authors
|
- 👥 Multi-Authors
|
||||||
|
- 🌐 Multilingual
|
||||||
- 🎯 Similar Posts Suggestion
|
- 🎯 Similar Posts Suggestion
|
||||||
- 🔍 Search Functionality
|
- 🔍 Search Functionality
|
||||||
- 🌑 Dark Mode
|
- 🌑 Dark Mode
|
||||||
@@ -65,10 +66,10 @@
|
|||||||
|
|
||||||
### 📦 Dependencies
|
### 📦 Dependencies
|
||||||
|
|
||||||
- astro 4.0+
|
- astro v4.12+
|
||||||
- node v20.10+
|
- node v20.10+
|
||||||
- npm v10.2+
|
- npm v10.2+
|
||||||
- tailwind v3.3+
|
- tailwind v3.4+
|
||||||
|
|
||||||
### 👉 Install Dependencies
|
### 👉 Install Dependencies
|
||||||
|
|
||||||
@@ -109,12 +110,14 @@ docker run -it --rm astroplate ash
|
|||||||
```
|
```
|
||||||
|
|
||||||
<!-- reporting issue -->
|
<!-- reporting issue -->
|
||||||
|
|
||||||
## 🐞 Reporting Issues
|
## 🐞 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.
|
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).
|
If your problem or idea has not been addressed yet, feel free to [open a new issue](https://github.com/zeon-studio/astroplate/issues).
|
||||||
|
|
||||||
<!-- licence -->
|
<!-- licence -->
|
||||||
|
|
||||||
## 📝 License
|
## 📝 License
|
||||||
|
|
||||||
Copyright (c) 2023 - Present, Designed & Developed by [Zeon Studio](https://zeon.studio/)
|
Copyright (c) 2023 - Present, Designed & Developed by [Zeon Studio](https://zeon.studio/)
|
||||||
|
|||||||
+22
-16
@@ -9,11 +9,11 @@ const CONTENT_DEPTH = 3;
|
|||||||
const BLOG_FOLDER = "blog";
|
const BLOG_FOLDER = "blog";
|
||||||
|
|
||||||
// get data from markdown
|
// get data from markdown
|
||||||
const getData = (folder, groupDepth) => {
|
const getData = (folder, groupDepth, langIndex = 0) => {
|
||||||
// get paths
|
|
||||||
const getPaths = languages
|
const getPaths = languages
|
||||||
.map((lang) => {
|
.map((lang, index) => {
|
||||||
const dir = path.join(CONTENT_ROOT, lang.contentDir, folder);
|
const langFolder = lang.contentDir ? lang.contentDir : lang.languageCode;
|
||||||
|
const dir = path.join(CONTENT_ROOT, folder, langFolder);
|
||||||
return fs
|
return fs
|
||||||
.readdirSync(dir)
|
.readdirSync(dir)
|
||||||
.filter(
|
.filter(
|
||||||
@@ -21,29 +21,37 @@ const getData = (folder, groupDepth) => {
|
|||||||
!filename.startsWith("-") &&
|
!filename.startsWith("-") &&
|
||||||
(filename.endsWith(".md") || filename.endsWith(".mdx")),
|
(filename.endsWith(".md") || filename.endsWith(".mdx")),
|
||||||
)
|
)
|
||||||
.map((filename) => {
|
.flatMap((filename) => {
|
||||||
const filepath = path.join(dir, filename);
|
const filepath = path.join(dir, filename);
|
||||||
const stats = fs.statSync(filepath);
|
const stats = fs.statSync(filepath);
|
||||||
const isFolder = stats.isDirectory();
|
const isFolder = stats.isDirectory();
|
||||||
|
|
||||||
if (isFolder) {
|
if (isFolder) {
|
||||||
return getData(filepath, groupDepth);
|
return getData(filepath, groupDepth, index);
|
||||||
} else {
|
} else {
|
||||||
const file = fs.readFileSync(filepath, "utf-8");
|
const file = fs.readFileSync(filepath, "utf-8");
|
||||||
const { data, content } = matter(file);
|
const { data, content } = matter(file);
|
||||||
const pathParts = filepath.split(path.sep);
|
const pathParts = filepath.split(path.sep);
|
||||||
const slug =
|
|
||||||
data.slug ||
|
let slug;
|
||||||
pathParts
|
if (data.slug) {
|
||||||
|
const slugParts = data.slug.split("/");
|
||||||
|
slugParts[0] = BLOG_FOLDER;
|
||||||
|
slug = slugParts.join("/");
|
||||||
|
} else {
|
||||||
|
slug = pathParts
|
||||||
.slice(CONTENT_DEPTH)
|
.slice(CONTENT_DEPTH)
|
||||||
.join("/")
|
.join("/")
|
||||||
.replace(/\.[^/.]+$/, "");
|
.replace(/\.[^/.]+$/, "");
|
||||||
const group = pathParts[groupDepth];
|
slug = `${BLOG_FOLDER}/${slug.split("/").slice(1).join("/")}`;
|
||||||
|
}
|
||||||
|
data.slug = slug;
|
||||||
|
const group = "blog";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lang: lang.languageCode,
|
lang: languages[index].languageCode, // Set the correct language code dynamically
|
||||||
group: group,
|
group: group,
|
||||||
slug: slug,
|
slug: data.slug,
|
||||||
frontmatter: data,
|
frontmatter: data,
|
||||||
content: content,
|
content: content,
|
||||||
};
|
};
|
||||||
@@ -52,9 +60,7 @@ const getData = (folder, groupDepth) => {
|
|||||||
})
|
})
|
||||||
.flat();
|
.flat();
|
||||||
|
|
||||||
const publishedPages = getPaths.filter(
|
const publishedPages = getPaths.filter((page) => !page.frontmatter?.draft);
|
||||||
(page) => !page.frontmatter?.draft && page,
|
|
||||||
);
|
|
||||||
return publishedPages;
|
return publishedPages;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,7 +76,7 @@ try {
|
|||||||
JSON.stringify(getData(BLOG_FOLDER, 3)),
|
JSON.stringify(getData(BLOG_FOLDER, 3)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// merger json files for search
|
// merge json files for search
|
||||||
const posts = require(`../${JSON_FOLDER}/posts.json`);
|
const posts = require(`../${JSON_FOLDER}/posts.json`);
|
||||||
const search = [...posts];
|
const search = [...posts];
|
||||||
fs.writeFileSync(`${JSON_FOLDER}/search.json`, JSON.stringify(search));
|
fs.writeFileSync(`${JSON_FOLDER}/search.json`, JSON.stringify(search));
|
||||||
|
|||||||
+85
-55
@@ -1,66 +1,96 @@
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
const rootDirs = ["src/pages", "src/hooks", "src/layouts", "src/styles"];
|
(function () {
|
||||||
|
const rootDirs = ["src/pages", "src/hooks", "src/layouts", "src/styles"];
|
||||||
|
|
||||||
const configFiles = [
|
const deleteAssetList = [
|
||||||
{
|
"public/images/logo-darkmode.png",
|
||||||
filePath: "tailwind.config.js",
|
"src/layouts/components/ThemeSwitcher.astro",
|
||||||
patterns: ["darkmode:\\s*{[^}]*},", 'darkMode:\\s*"class",'],
|
];
|
||||||
},
|
|
||||||
{ filePath: "src/config/theme.json", patterns: ["colors.darkmode"] },
|
|
||||||
];
|
|
||||||
|
|
||||||
rootDirs.forEach(removeDarkModeFromPages);
|
const configFiles = [
|
||||||
configFiles.forEach(removeDarkMode);
|
{
|
||||||
|
filePath: "tailwind.config.js",
|
||||||
|
patterns: ["darkmode:\\s*{[^}]*},", 'darkMode:\\s*"class",'],
|
||||||
|
},
|
||||||
|
{ filePath: "src/config/theme.json", patterns: ["colors.darkmode"] },
|
||||||
|
];
|
||||||
|
|
||||||
function removeDarkModeFromFiles(filePath, regexPatterns) {
|
const filePaths = [
|
||||||
const fileContent = fs.readFileSync(filePath, "utf8");
|
{
|
||||||
let updatedContent = fileContent;
|
filePath: "src/layouts/partials/Header.astro",
|
||||||
regexPatterns.forEach((pattern) => {
|
patterns: [
|
||||||
const regex = new RegExp(pattern, "g");
|
"<ThemeSwitchers*(?:\\s+[^>]+)?\\s*(?:\\/\\>|>([\\s\\S]*?)<\\/ThemeSwitchers*>)",
|
||||||
updatedContent = updatedContent.replace(regex, "");
|
],
|
||||||
});
|
},
|
||||||
fs.writeFileSync(filePath, updatedContent, "utf8");
|
];
|
||||||
}
|
|
||||||
|
|
||||||
function removeDarkModeFromPages(directoryPath) {
|
filePaths.forEach(({ filePath, patterns }) => {
|
||||||
const files = fs.readdirSync(directoryPath);
|
|
||||||
|
|
||||||
files.forEach((file) => {
|
|
||||||
const filePath = path.join(directoryPath, file);
|
|
||||||
const stats = fs.statSync(filePath);
|
|
||||||
if (stats.isDirectory()) {
|
|
||||||
removeDarkModeFromPages(filePath);
|
|
||||||
} else if (stats.isFile()) {
|
|
||||||
removeDarkModeFromFiles(filePath, [
|
|
||||||
'(?:(?!["])\\S)*dark:(?:(?![,;"])\\S)*',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeDarkMode(configFile) {
|
|
||||||
const { filePath, patterns } = configFile;
|
|
||||||
if (filePath === "tailwind.config.js") {
|
|
||||||
removeDarkModeFromFiles(filePath, patterns);
|
removeDarkModeFromFiles(filePath, patterns);
|
||||||
} else {
|
});
|
||||||
const contentFile = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
||||||
patterns.forEach((pattern) => deleteNestedProperty(contentFile, pattern));
|
|
||||||
fs.writeFileSync(filePath, JSON.stringify(contentFile));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteNestedProperty(obj, propertyPath) {
|
deleteAssetList.forEach(deleteAsset);
|
||||||
const properties = propertyPath.split(".");
|
function deleteAsset(asset) {
|
||||||
let currentObj = obj;
|
try {
|
||||||
for (let i = 0; i < properties.length - 1; i++) {
|
fs.unlinkSync(asset);
|
||||||
const property = properties[i];
|
console.log(`${path.basename(asset)} deleted successfully!`);
|
||||||
if (currentObj.hasOwnProperty(property)) {
|
} catch (error) {
|
||||||
currentObj = currentObj[property];
|
console.error(`${asset} not found`);
|
||||||
} else {
|
|
||||||
return; // Property not found, no need to continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete currentObj[properties[properties.length - 1]];
|
|
||||||
}
|
rootDirs.forEach(removeDarkModeFromPages);
|
||||||
|
configFiles.forEach(removeDarkMode);
|
||||||
|
|
||||||
|
function removeDarkModeFromFiles(filePath, regexPatterns) {
|
||||||
|
const fileContent = fs.readFileSync(filePath, "utf8");
|
||||||
|
let updatedContent = fileContent;
|
||||||
|
regexPatterns.forEach((pattern) => {
|
||||||
|
const regex = new RegExp(pattern, "g");
|
||||||
|
updatedContent = updatedContent.replace(regex, "");
|
||||||
|
});
|
||||||
|
fs.writeFileSync(filePath, updatedContent, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDarkModeFromPages(directoryPath) {
|
||||||
|
const files = fs.readdirSync(directoryPath);
|
||||||
|
|
||||||
|
files.forEach((file) => {
|
||||||
|
const filePath = path.join(directoryPath, file);
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
removeDarkModeFromPages(filePath);
|
||||||
|
} else if (stats.isFile()) {
|
||||||
|
removeDarkModeFromFiles(filePath, [
|
||||||
|
'(?:(?!["])\\S)*dark:(?:(?![,;"])\\S)*',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDarkMode(configFile) {
|
||||||
|
const { filePath, patterns } = configFile;
|
||||||
|
if (filePath === "tailwind.config.js") {
|
||||||
|
removeDarkModeFromFiles(filePath, patterns);
|
||||||
|
} else {
|
||||||
|
const contentFile = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||||
|
patterns.forEach((pattern) => deleteNestedProperty(contentFile, pattern));
|
||||||
|
fs.writeFileSync(filePath, JSON.stringify(contentFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteNestedProperty(obj, propertyPath) {
|
||||||
|
const properties = propertyPath.split(".");
|
||||||
|
let currentObj = obj;
|
||||||
|
for (let i = 0; i < properties.length - 1; i++) {
|
||||||
|
const property = properties[i];
|
||||||
|
if (currentObj.hasOwnProperty(property)) {
|
||||||
|
currentObj = currentObj[property];
|
||||||
|
} else {
|
||||||
|
return; // Property not found, no need to continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete currentObj[properties[properties.length - 1]];
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"blog_folder": "blog",
|
"blog_folder": "blog",
|
||||||
"default_language": "en",
|
"default_language": "en",
|
||||||
"disable_languages": [],
|
"disable_languages": [],
|
||||||
"default_language_in_path": false
|
"default_language_in_subdir": false
|
||||||
},
|
},
|
||||||
|
|
||||||
"params": {
|
"params": {
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ image: "/images/avatar.png"
|
|||||||
draft: false
|
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
|
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
|
||||||
+88
-1
@@ -1,6 +1,6 @@
|
|||||||
import { defineCollection, z } from "astro:content";
|
import { defineCollection, z } from "astro:content";
|
||||||
|
|
||||||
// Post collection schema
|
// Blog collection schema
|
||||||
const blogCollection = defineCollection({
|
const blogCollection = defineCollection({
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
title: z.string(),
|
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 collections
|
||||||
export const collections = {
|
export const collections = {
|
||||||
blog: blogCollection,
|
blog: blogCollection,
|
||||||
authors: authorsCollection,
|
authors: authorsCollection,
|
||||||
pages: pagesCollection,
|
pages: pagesCollection,
|
||||||
|
contact: contactCollection,
|
||||||
|
about: aboutCollection,
|
||||||
|
content: contentCollection,
|
||||||
|
testimonials: testimonialsSchema,
|
||||||
|
callToAction: callToActionSchema,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,4 +50,4 @@ features:
|
|||||||
enable: false
|
enable: false
|
||||||
label: ""
|
label: ""
|
||||||
link: ""
|
link: ""
|
||||||
---
|
---
|
||||||
@@ -9,6 +9,7 @@ import "@/styles/main.scss";
|
|||||||
import { AstroFont } from "astro-font";
|
import { AstroFont } from "astro-font";
|
||||||
import { ViewTransitions } from "astro:transitions";
|
import { ViewTransitions } from "astro:transitions";
|
||||||
import SearchModal from "./helpers/SearchModal";
|
import SearchModal from "./helpers/SearchModal";
|
||||||
|
import { getLangFromUrl } from "@/lib/utils/languageParser";
|
||||||
|
|
||||||
// font families
|
// font families
|
||||||
const pf = theme.fonts.font_family.primary;
|
const pf = theme.fonts.font_family.primary;
|
||||||
@@ -40,6 +41,8 @@ export interface Props {
|
|||||||
// distructure frontmatters
|
// distructure frontmatters
|
||||||
const { title, meta_title, description, image, noindex, canonical, lang } =
|
const { title, meta_title, description, image, noindex, canonical, lang } =
|
||||||
Astro.props;
|
Astro.props;
|
||||||
|
|
||||||
|
const language = lang || getLangFromUrl(Astro.url);
|
||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
@@ -108,7 +111,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
|
|||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content={plainify(
|
content={plainify(
|
||||||
description ? description : config.metadata.meta_description,
|
description ? description : config.metadata.meta_description
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -121,7 +124,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
|
|||||||
<meta
|
<meta
|
||||||
property="og:title"
|
property="og:title"
|
||||||
content={plainify(
|
content={plainify(
|
||||||
meta_title ? meta_title : title ? title : config.site.title,
|
meta_title ? meta_title : title ? title : config.site.title
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -129,7 +132,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
|
|||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content={plainify(
|
content={plainify(
|
||||||
description ? description : config.metadata.meta_description,
|
description ? description : config.metadata.meta_description
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
@@ -142,7 +145,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
|
|||||||
<meta
|
<meta
|
||||||
name="twitter:title"
|
name="twitter:title"
|
||||||
content={plainify(
|
content={plainify(
|
||||||
meta_title ? meta_title : title ? title : config.site.title,
|
meta_title ? meta_title : title ? title : config.site.title
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -150,7 +153,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
|
|||||||
<meta
|
<meta
|
||||||
name="twitter:description"
|
name="twitter:description"
|
||||||
content={plainify(
|
content={plainify(
|
||||||
description ? description : config.metadata.meta_description,
|
description ? description : config.metadata.meta_description
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -174,7 +177,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
|
|||||||
<body>
|
<body>
|
||||||
<TwSizeIndicator />
|
<TwSizeIndicator />
|
||||||
<Header />
|
<Header />
|
||||||
<SearchModal client:load />
|
<SearchModal lang={language} client:load />
|
||||||
<main id="main-content">
|
<main id="main-content">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ const { title, image, date, author, categories } = data.data;
|
|||||||
|
|
||||||
const lang = getLangFromUrl(Astro.url);
|
const lang = getLangFromUrl(Astro.url);
|
||||||
const { read_more } = await getTranslations(lang as keyof ContentEntryMap);
|
const { read_more } = await getTranslations(lang as keyof ContentEntryMap);
|
||||||
|
|
||||||
|
const slugParts = data.slug.split("/");
|
||||||
|
slugParts[0] = "blog";
|
||||||
|
const modifiedSlug = slugParts.join("/");
|
||||||
|
data.slug = modifiedSlug;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="bg-body dark:bg-darkmode-body">
|
<div class="bg-body dark:bg-darkmode-body">
|
||||||
|
|||||||
@@ -11,19 +11,20 @@ if (supportedLang.includes(paths[0])) {
|
|||||||
lang = paths.shift()!;
|
lang = paths.shift()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let baseHref = lang ? `/${lang}` : "/";
|
||||||
let parts = [
|
let parts = [
|
||||||
{
|
{
|
||||||
label: "Home",
|
label: "Home",
|
||||||
href: `/${lang}`,
|
href: baseHref,
|
||||||
"aria-label":
|
"aria-label":
|
||||||
Astro.url.pathname === `/${lang}` || Astro.url.pathname === `/${lang}/`
|
Astro.url.pathname === baseHref || Astro.url.pathname === `${baseHref}/`
|
||||||
? "page"
|
? "page"
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
paths.forEach((label: string, i: number) => {
|
paths.forEach((label: string, i: number) => {
|
||||||
const href = `/${lang}/${paths.slice(0, i + 1).join("/")}`;
|
const href = `${baseHref}${paths.slice(0, i + 1).join("/")}`;
|
||||||
label !== "page" &&
|
label !== "page" &&
|
||||||
parts.push({
|
parts.push({
|
||||||
label: humanize(label.replace(".html", "").replace(/[-_]/g, " ")) || "",
|
label: humanize(label.replace(".html", "").replace(/[-_]/g, " ")) || "",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const LanguageSwitcher = ({
|
|||||||
lang: string;
|
lang: string;
|
||||||
pathname: string;
|
pathname: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { default_language } = config.settings;
|
const { default_language, default_language_in_subdir } = config.settings;
|
||||||
|
|
||||||
// Function to remove trailing slash if necessary
|
// Function to remove trailing slash if necessary
|
||||||
const removeTrailingSlash = (path: string) => {
|
const removeTrailingSlash = (path: string) => {
|
||||||
@@ -21,22 +21,29 @@ const LanguageSwitcher = ({
|
|||||||
|
|
||||||
// Sort languages by weight and filter out disabled languages
|
// Sort languages by weight and filter out disabled languages
|
||||||
const sortedLanguages = languages
|
const sortedLanguages = languages
|
||||||
|
// @ts-ignore
|
||||||
.filter(language => !config.settings.disable_languages.includes(language.languageCode))
|
.filter(language => !config.settings.disable_languages.includes(language.languageCode))
|
||||||
.sort((a, b) => a.weight - b.weight);
|
.sort((a, b) => a.weight - b.weight);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mr-5">
|
<div className={`mr-5 ${sortedLanguages.length > 1 ? "block" : "hidden"}`}>
|
||||||
<select
|
<select
|
||||||
className="border border-dark text-dark bg-transparent dark:border-darkmode-primary dark:text-white py-1 rounded-sm cursor-pointer focus:ring-0 focus:border-dark dark:focus:border-darkmode-primary"
|
className="border border-dark text-dark bg-transparent dark:border-darkmode-primary dark:text-white py-1 rounded-sm cursor-pointer focus:ring-0 focus:border-dark dark:focus:border-darkmode-primary"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const selectedLang = e.target.value;
|
const selectedLang = e.target.value;
|
||||||
let newPath;
|
let newPath;
|
||||||
const baseUrl = window.location.origin;
|
const baseUrl = window.location.origin;
|
||||||
|
|
||||||
if (selectedLang === default_language) {
|
if (selectedLang === default_language) {
|
||||||
newPath = `${baseUrl}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
|
if (default_language_in_subdir) {
|
||||||
|
newPath = `${baseUrl}/${default_language}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
|
||||||
|
} else {
|
||||||
|
newPath = `${baseUrl}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
newPath = `/${selectedLang}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
|
newPath = `/${selectedLang}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.href = newPath;
|
window.location.href = newPath;
|
||||||
}}
|
}}
|
||||||
value={lang}
|
value={lang}
|
||||||
@@ -55,4 +62,4 @@ const LanguageSwitcher = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LanguageSwitcher;
|
export default LanguageSwitcher;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import searchData from ".json/search.json";
|
import searchData from ".json/search.json";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import SearchResult, { type ISearchItem } from "./SearchResult";
|
import SearchResult, { type ISearchItem } from "./SearchResult";
|
||||||
|
import config from "@/config/config.json";
|
||||||
|
const { default_language } = config.settings;
|
||||||
|
|
||||||
const SearchModal = () => {
|
const SearchModal = ({ lang }: { lang: string | undefined }) => {
|
||||||
|
lang = lang || default_language;
|
||||||
const [searchString, setSearchString] = useState("");
|
const [searchString, setSearchString] = useState("");
|
||||||
|
|
||||||
// handle input change
|
// handle input change
|
||||||
@@ -39,9 +42,13 @@ const SearchModal = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// filter language specific search data
|
||||||
|
const filterSearchData = searchData.filter((item) => item.lang === lang);
|
||||||
|
|
||||||
|
|
||||||
// get search result
|
// get search result
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
const searchResult = doSearch(searchData);
|
const searchResult = doSearch(filterSearchData);
|
||||||
const endTime = performance.now();
|
const endTime = performance.now();
|
||||||
const totalTime = ((endTime - startTime) / 1000).toFixed(3);
|
const totalTime = ((endTime - startTime) / 1000).toFixed(3);
|
||||||
|
|
||||||
@@ -169,10 +176,15 @@ const SearchModal = () => {
|
|||||||
name="search"
|
name="search"
|
||||||
value={searchString}
|
value={searchString}
|
||||||
onChange={handleSearch}
|
onChange={handleSearch}
|
||||||
|
autoFocus
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SearchResult searchResult={searchResult} searchString={searchString} />
|
<SearchResult
|
||||||
|
searchResult={searchResult}
|
||||||
|
searchString={searchString}
|
||||||
|
lang={lang}
|
||||||
|
/>
|
||||||
<div className="search-wrapper-footer">
|
<div className="search-wrapper-footer">
|
||||||
<span className="flex items-center">
|
<span className="flex items-center">
|
||||||
<kbd>
|
<kbd>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { slugSelector } from "@/lib/utils/languageParser";
|
||||||
import { plainify, titleify } from "@/lib/utils/textConverter";
|
import { plainify, titleify } from "@/lib/utils/textConverter";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export interface ISearchItem {
|
export interface ISearchItem {
|
||||||
|
lang: string;
|
||||||
group: string;
|
group: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
frontmatter: {
|
frontmatter: {
|
||||||
@@ -33,10 +35,13 @@ export interface ISearchGroup {
|
|||||||
const SearchResult = ({
|
const SearchResult = ({
|
||||||
searchResult,
|
searchResult,
|
||||||
searchString,
|
searchString,
|
||||||
|
lang
|
||||||
}: {
|
}: {
|
||||||
searchResult: ISearchItem[];
|
searchResult: ISearchItem[];
|
||||||
searchString: string;
|
searchString: string;
|
||||||
|
lang: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
// generate search result group
|
// generate search result group
|
||||||
const generateSearchGroup = (searchResult: ISearchItem[]) => {
|
const generateSearchGroup = (searchResult: ISearchItem[]) => {
|
||||||
const joinDataByGroup: ISearchGroup[] = searchResult.reduce(
|
const joinDataByGroup: ISearchGroup[] = searchResult.reduce(
|
||||||
@@ -83,6 +88,7 @@ const SearchResult = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// match underline
|
// match underline
|
||||||
const matchUnderline = (text: string, substring: string) => {
|
const matchUnderline = (text: string, substring: string) => {
|
||||||
const parts = text?.split(new RegExp(`(${substring})`, "gi"));
|
const parts = text?.split(new RegExp(`(${substring})`, "gi"));
|
||||||
@@ -148,12 +154,14 @@ const SearchResult = ({
|
|||||||
<img
|
<img
|
||||||
src={item.frontmatter.image}
|
src={item.frontmatter.image}
|
||||||
alt={item.frontmatter.title}
|
alt={item.frontmatter.title}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="search-result-item-body">
|
<div className="search-result-item-body">
|
||||||
<a
|
<a
|
||||||
href={`/${item.slug}`}
|
href={`${slugSelector(item.slug, lang)}`}
|
||||||
className="search-result-item-title search-result-item-link"
|
className="search-result-item-title search-result-item-link"
|
||||||
>
|
>
|
||||||
{matchUnderline(item.frontmatter.title, searchString)}
|
{matchUnderline(item.frontmatter.title, searchString)}
|
||||||
@@ -188,8 +196,8 @@ const SearchResult = ({
|
|||||||
{matchUnderline(category, searchString)}
|
{matchUnderline(category, searchString)}
|
||||||
{item.frontmatter.categories &&
|
{item.frontmatter.categories &&
|
||||||
index !==
|
index !==
|
||||||
item.frontmatter.categories.length -
|
item.frontmatter.categories.length -
|
||||||
1 && <>, </>}
|
1 && <>, </>}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
@@ -211,7 +219,7 @@ const SearchResult = ({
|
|||||||
{matchUnderline(tag, searchString)}
|
{matchUnderline(tag, searchString)}
|
||||||
{item.frontmatter.tags &&
|
{item.frontmatter.tags &&
|
||||||
index !==
|
index !==
|
||||||
item.frontmatter.tags.length - 1 && <>, </>}
|
item.frontmatter.tags.length - 1 && <>, </>}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import ThemeSwitcher from "@/components/ThemeSwitcher.astro";
|
|||||||
import config from "@/config/config.json";
|
import config from "@/config/config.json";
|
||||||
import languages from "@/config/language.json";
|
import languages from "@/config/language.json";
|
||||||
import LanguageSwitcher from "@/helpers/LanguageSwitcher";
|
import LanguageSwitcher from "@/helpers/LanguageSwitcher";
|
||||||
import { getLangFromUrl, getTranslations, slugSelector } from "@/lib/utils/languageParser";
|
import {
|
||||||
|
getLangFromUrl,
|
||||||
|
getTranslations,
|
||||||
|
slugSelector,
|
||||||
|
} from "@/lib/utils/languageParser";
|
||||||
import type { ContentEntryMap } from "astro:content";
|
import type { ContentEntryMap } from "astro:content";
|
||||||
import { IoSearch } from "react-icons/io5";
|
import { IoSearch } from "react-icons/io5";
|
||||||
|
|
||||||
@@ -133,12 +137,10 @@ if (disabledLanguages.includes(lang)) {
|
|||||||
}
|
}
|
||||||
{/* Theme switcher */}
|
{/* Theme switcher */}
|
||||||
<ThemeSwitcher className="mr-5" />
|
<ThemeSwitcher className="mr-5" />
|
||||||
|
|
||||||
{/* Language switcher */}
|
{/* Language switcher */}
|
||||||
{
|
<LanguageSwitcher client:load lang={lang} pathname={pathname} />
|
||||||
languages.length > 1 && (
|
|
||||||
<LanguageSwitcher client:load lang={lang} pathname={pathname} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{/* Navigation button */}
|
{/* Navigation button */}
|
||||||
{
|
{
|
||||||
navigation_button.enable && (
|
navigation_button.enable && (
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const { testimonial } = Astro.props;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="testimonial-slider-pagination mt-9 flex items-center justify-center text-center" />
|
<div class="testimonial-slider-pagination mt-9 flex items-center justify-center text-center" />
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import config from "@/config/config.json";
|
import config from "@/config/config.json";
|
||||||
import languages from "@/config/language.json";
|
import languages from "@/config/language.json";
|
||||||
|
|
||||||
export const getSinglePage = async <C extends CollectionKey>(
|
export const getSP = async <C extends CollectionKey>(
|
||||||
collectionName: C,
|
collectionName: C,
|
||||||
lang: keyof ContentEntryMap | undefined
|
lang: keyof ContentEntryMap | undefined
|
||||||
): Promise<CollectionEntry<C>[]> => {
|
): Promise<CollectionEntry<C>[]> => {
|
||||||
@@ -40,7 +40,7 @@ export const getSinglePage = async <C extends CollectionKey>(
|
|||||||
return removeDrafts;
|
return removeDrafts;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getListPage = async <C extends CollectionKey>(
|
export const getLP = async <C extends CollectionKey>(
|
||||||
collectionName: C,
|
collectionName: C,
|
||||||
lang: keyof ContentEntryMap | undefined
|
lang: keyof ContentEntryMap | undefined
|
||||||
): Promise<CollectionEntry<C>[]> => {
|
): Promise<CollectionEntry<C>[]> => {
|
||||||
@@ -67,4 +67,68 @@ export const getListPage = async <C extends CollectionKey>(
|
|||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getSinglePage = async <C extends CollectionKey>(
|
||||||
|
collectionName: C,
|
||||||
|
lang: keyof ContentEntryMap | undefined,
|
||||||
|
subCollectionName?: string
|
||||||
|
): Promise<CollectionEntry<C>[]> => {
|
||||||
|
const { default_language } = config.settings;
|
||||||
|
|
||||||
|
const selectedLanguageCode = lang || default_language;
|
||||||
|
|
||||||
|
const language = languages.find(
|
||||||
|
(l: any) => l.languageCode === selectedLanguageCode
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!language) {
|
||||||
|
throw new Error("Language not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { contentDir } = language;
|
||||||
|
|
||||||
|
const path = subCollectionName
|
||||||
|
? `${contentDir}/${subCollectionName}`
|
||||||
|
: contentDir;
|
||||||
|
|
||||||
|
const pages: CollectionEntry<C>[] = (await getCollection(
|
||||||
|
collectionName as any,
|
||||||
|
({ id }: any) => {
|
||||||
|
return id.startsWith(path) && !id.endsWith("-index.md");
|
||||||
|
}
|
||||||
|
)) as CollectionEntry<C>[];
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const removeDrafts = pages.filter((data) => !data.data.draft);
|
||||||
|
|
||||||
|
return removeDrafts;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getListPage = async <C extends CollectionKey>(
|
||||||
|
collectionName: C,
|
||||||
|
lang: keyof ContentEntryMap | undefined
|
||||||
|
): Promise<CollectionEntry<C>[]> => {
|
||||||
|
const { default_language } = config.settings;
|
||||||
|
|
||||||
|
const selectedLanguageCode = lang || default_language;
|
||||||
|
|
||||||
|
const language = languages.find(
|
||||||
|
(l: any) => l.languageCode == selectedLanguageCode
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!language) {
|
||||||
|
throw new Error("Language not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { contentDir } = language;
|
||||||
|
|
||||||
|
const pages: CollectionEntry<C>[] = (await getCollection(
|
||||||
|
collectionName as any,
|
||||||
|
({ id }: any) => {
|
||||||
|
return id.startsWith(contentDir);
|
||||||
|
}
|
||||||
|
)) as CollectionEntry<C>[];
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
};
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const getTaxonomy = async (collection: string, name: string) => {
|
|||||||
actualCollection = language.contentDir;
|
actualCollection = language.contentDir;
|
||||||
} else {
|
} else {
|
||||||
const defaultLanguageMatch = languages.find(
|
const defaultLanguageMatch = languages.find(
|
||||||
(l) => l.languageCode === default_language,
|
(l) => l.languageCode === default_language
|
||||||
);
|
);
|
||||||
if (defaultLanguageMatch) {
|
if (defaultLanguageMatch) {
|
||||||
actualCollection = defaultLanguageMatch.contentDir;
|
actualCollection = defaultLanguageMatch.contentDir;
|
||||||
@@ -24,10 +24,10 @@ export const getTaxonomy = async (collection: string, name: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const singlePages = await getCollection(
|
const singlePages = await getCollection(
|
||||||
actualCollection as keyof ContentEntryMap,
|
"blog" as keyof ContentEntryMap,
|
||||||
({ id }: any) => {
|
({ id }: any) => {
|
||||||
return id.startsWith("blog") && !id.endsWith("-index.md");
|
return id.startsWith(actualCollection) && !id.endsWith("-index.md");
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
||||||
let taxonomies: string[] = [];
|
let taxonomies: string[] = [];
|
||||||
@@ -52,7 +52,7 @@ export const getAllTaxonomy = async (collection: string, name: string) => {
|
|||||||
actualCollection = language.contentDir;
|
actualCollection = language.contentDir;
|
||||||
} else {
|
} else {
|
||||||
const defaultLanguageMatch = languages.find(
|
const defaultLanguageMatch = languages.find(
|
||||||
(l) => l.languageCode === default_language,
|
(l) => l.languageCode === default_language
|
||||||
);
|
);
|
||||||
if (defaultLanguageMatch) {
|
if (defaultLanguageMatch) {
|
||||||
actualCollection = defaultLanguageMatch.contentDir;
|
actualCollection = defaultLanguageMatch.contentDir;
|
||||||
@@ -60,10 +60,10 @@ export const getAllTaxonomy = async (collection: string, name: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const singlePages = await getCollection(
|
const singlePages = await getCollection(
|
||||||
actualCollection as keyof ContentEntryMap,
|
"blog" as keyof ContentEntryMap,
|
||||||
({ id }: any) => {
|
({ id }: any) => {
|
||||||
return id.startsWith("blog") && !id.endsWith("-index.md");
|
return id.startsWith(actualCollection) && !id.endsWith("-index.md");
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
const taxonomyPages = singlePages.map((page: any) => page.data[name]);
|
||||||
let taxonomies: string[] = [];
|
let taxonomies: string[] = [];
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const filteredSupportedLang = supportedLang.filter(
|
|||||||
export { filteredSupportedLang as supportedLang };
|
export { filteredSupportedLang as supportedLang };
|
||||||
|
|
||||||
export const slugSelector = (url: string, lang: string) => {
|
export const slugSelector = (url: string, lang: string) => {
|
||||||
const { default_language, default_language_in_path } = config.settings;
|
const { default_language, default_language_in_subdir } = config.settings;
|
||||||
const { trailing_slash } = config.site;
|
const { trailing_slash } = config.site;
|
||||||
|
|
||||||
let constructedUrl;
|
let constructedUrl;
|
||||||
@@ -90,28 +90,21 @@ export const slugSelector = (url: string, lang: string) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add language path if necessary
|
||||||
|
if (lang === default_language && default_language_in_subdir) {
|
||||||
|
constructedUrl = `/${lang}${constructedUrl}`;
|
||||||
|
}
|
||||||
|
|
||||||
// Adjust for trailing slash
|
// Adjust for trailing slash
|
||||||
if (trailing_slash) {
|
if (trailing_slash) {
|
||||||
if (!constructedUrl.endsWith("/")) {
|
if (!constructedUrl.endsWith("/")) {
|
||||||
constructedUrl += "/";
|
constructedUrl += "/";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (constructedUrl.endsWith("/")) {
|
if (constructedUrl.endsWith("/") && constructedUrl !== "/") {
|
||||||
constructedUrl = constructedUrl.slice(0, -1);
|
constructedUrl = constructedUrl.slice(0, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure home URL is absolute
|
|
||||||
if (constructedUrl === "") {
|
|
||||||
constructedUrl = "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add language path if necessary
|
|
||||||
if (lang === default_language) {
|
|
||||||
constructedUrl = default_language_in_path
|
|
||||||
? `/${lang}${constructedUrl}`
|
|
||||||
: constructedUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return constructedUrl;
|
return constructedUrl;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export async function getStaticPaths() {
|
|||||||
supportedLang.map(async (lang) => {
|
supportedLang.map(async (lang) => {
|
||||||
const pages = await getSinglePage("pages", lang as keyof ContentEntryMap);
|
const pages = await getSinglePage("pages", lang as keyof ContentEntryMap);
|
||||||
|
|
||||||
return pages.map((page: any) => ({
|
return pages.map((page) => ({
|
||||||
params: {
|
params: {
|
||||||
lang: lang || undefined,
|
lang: lang || undefined,
|
||||||
regular: page.slug.split("/").pop(),
|
regular: page.slug.split("/").pop(),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Base from "@/layouts/Base.astro";
|
|||||||
import { getListPage } from "@/lib/contentParser.astro";
|
import { getListPage } from "@/lib/contentParser.astro";
|
||||||
import { supportedLang } from "@/lib/utils/languageParser";
|
import { supportedLang } from "@/lib/utils/languageParser";
|
||||||
import { markdownify } from "@/lib/utils/textConverter";
|
import { markdownify } from "@/lib/utils/textConverter";
|
||||||
import type { ContentCollectionKey, ContentEntryMap } from "astro:content";
|
import type { ContentEntryMap } from "astro:content";
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
const paths = supportedLang.map((lang) => ({
|
const paths = supportedLang.map((lang) => ({
|
||||||
@@ -14,10 +14,7 @@ export function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { lang } = Astro.params;
|
const { lang } = Astro.params;
|
||||||
const about: any = await getListPage(
|
const about = await getListPage("about", lang as keyof ContentEntryMap);
|
||||||
"about" as ContentCollectionKey,
|
|
||||||
lang as keyof ContentEntryMap
|
|
||||||
);
|
|
||||||
|
|
||||||
const { Content } = await about[0].render();
|
const { Content } = await about[0].render();
|
||||||
const { title, description, meta_title, image } = about[0].data;
|
const { title, description, meta_title, image } = about[0].data;
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ export async function getStaticPaths() {
|
|||||||
|
|
||||||
const paths = await Promise.all(
|
const paths = await Promise.all(
|
||||||
supportedLang.map(async (lang) => {
|
supportedLang.map(async (lang) => {
|
||||||
const authors: any = await getSinglePage(
|
const authors = await getSinglePage(
|
||||||
COLLECTION_FOLDER,
|
COLLECTION_FOLDER,
|
||||||
lang as keyof ContentEntryMap
|
lang as keyof ContentEntryMap
|
||||||
);
|
);
|
||||||
|
|
||||||
return authors.map((author: any) => ({
|
return authors.map((author) => ({
|
||||||
params: {
|
params: {
|
||||||
lang: lang || undefined,
|
lang: lang || undefined,
|
||||||
single: author.slug.split("/").pop(),
|
single: author.slug.split("/").pop(),
|
||||||
@@ -42,7 +42,7 @@ const { Content } = await author.render();
|
|||||||
const BLOG_FOLDER = "blog";
|
const BLOG_FOLDER = "blog";
|
||||||
const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap);
|
const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap);
|
||||||
const postFilterByAuthor = posts.filter(
|
const postFilterByAuthor = posts.filter(
|
||||||
(post: any) => slugify(post.data.author) === slugify(title)
|
(post) => slugify(post.data.author) === slugify(title)
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { lang } = Astro.params;
|
const { lang } = Astro.params;
|
||||||
const authorIndex: any = await getListPage(
|
const authorIndex = await getListPage(
|
||||||
COLLECTION_FOLDER,
|
COLLECTION_FOLDER,
|
||||||
lang as keyof ContentEntryMap
|
lang as keyof ContentEntryMap
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ export async function getStaticPaths() {
|
|||||||
|
|
||||||
const paths = await Promise.all(
|
const paths = await Promise.all(
|
||||||
supportedLang.map(async (lang) => {
|
supportedLang.map(async (lang) => {
|
||||||
const posts: any = await getSinglePage(
|
const posts = await getSinglePage(
|
||||||
BLOG_FOLDER,
|
BLOG_FOLDER,
|
||||||
lang as keyof ContentEntryMap
|
lang as keyof ContentEntryMap
|
||||||
);
|
);
|
||||||
|
|
||||||
return posts.map((post: any) => ({
|
return posts.map((post) => ({
|
||||||
params: {
|
params: {
|
||||||
lang: lang || undefined,
|
lang: lang || undefined,
|
||||||
single: post.slug.split("/").pop(),
|
single: post.slug.split("/").pop(),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
const { lang } = Astro.params;
|
const { lang } = Astro.params;
|
||||||
const BLOG_FOLDER = "blog";
|
const BLOG_FOLDER = "blog";
|
||||||
const postIndex: any = await getListPage(
|
const postIndex = await getListPage(
|
||||||
BLOG_FOLDER,
|
BLOG_FOLDER,
|
||||||
lang as keyof ContentEntryMap
|
lang as keyof ContentEntryMap
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import Base from "@/layouts/Base.astro";
|
|||||||
import { getListPage } from "@/lib/contentParser.astro";
|
import { getListPage } from "@/lib/contentParser.astro";
|
||||||
import { getTranslations, supportedLang } from "@/lib/utils/languageParser";
|
import { getTranslations, supportedLang } from "@/lib/utils/languageParser";
|
||||||
import PageHeader from "@/partials/PageHeader.astro";
|
import PageHeader from "@/partials/PageHeader.astro";
|
||||||
import type { CollectionKey } from "astro:content";
|
|
||||||
import { type ContentEntryMap } from "astro:content";
|
import { type ContentEntryMap } from "astro:content";
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
@@ -15,10 +14,7 @@ export function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { lang } = Astro.params;
|
const { lang } = Astro.params;
|
||||||
const contact: any = await getListPage(
|
const contact = await getListPage("contact", lang as keyof ContentEntryMap);
|
||||||
"contact" as CollectionKey,
|
|
||||||
lang as keyof ContentEntryMap
|
|
||||||
);
|
|
||||||
|
|
||||||
const { contact_form_action }: { contact_form_action: string } = config.params;
|
const { contact_form_action }: { contact_form_action: string } = config.params;
|
||||||
const { title, description, meta_title, image } = contact[0].data;
|
const { title, description, meta_title, image } = contact[0].data;
|
||||||
|
|||||||
@@ -6,18 +6,9 @@ import { supportedLang } from "@/lib/utils/languageParser";
|
|||||||
import { markdownify } from "@/lib/utils/textConverter";
|
import { markdownify } from "@/lib/utils/textConverter";
|
||||||
import CallToAction from "@/partials/CallToAction.astro";
|
import CallToAction from "@/partials/CallToAction.astro";
|
||||||
import Testimonial from "@/partials/Testimonial.astro";
|
import Testimonial from "@/partials/Testimonial.astro";
|
||||||
import type { Button, Feature } from "@/types";
|
import type { Feature } from "@/types";
|
||||||
import type { ContentCollectionKey, ContentEntryMap } from "astro:content";
|
import type { ContentEntryMap } from "astro:content";
|
||||||
import { FaCheck } from "react-icons/fa";
|
import { FaCheck } from "react-icons/fa";
|
||||||
interface Homepage {
|
|
||||||
banner: {
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
image: string;
|
|
||||||
button: Button;
|
|
||||||
};
|
|
||||||
features: Feature[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export function getStaticPaths() {
|
||||||
const paths = supportedLang.map((lang) => ({
|
const paths = supportedLang.map((lang) => ({
|
||||||
@@ -27,20 +18,19 @@ export function getStaticPaths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { lang } = Astro.params;
|
const { lang } = Astro.params;
|
||||||
const homepage: any = await getListPage(
|
const homepage = await getListPage("homepage", lang as keyof ContentEntryMap);
|
||||||
"homepage" as ContentCollectionKey,
|
const { banner, features } = homepage[0].data;
|
||||||
lang as keyof ContentEntryMap
|
|
||||||
);
|
|
||||||
const { banner, features }: Homepage = homepage[0].data;
|
|
||||||
|
|
||||||
const testimonial = await getSinglePage(
|
const testimonial = await getSinglePage(
|
||||||
"sections/testimonial" as ContentCollectionKey,
|
"sections",
|
||||||
lang as keyof ContentEntryMap
|
lang as keyof ContentEntryMap,
|
||||||
|
"testimonial"
|
||||||
);
|
);
|
||||||
|
|
||||||
const call_to_action = await getSinglePage(
|
const call_to_action = await getSinglePage(
|
||||||
"sections/call-to-action" as ContentCollectionKey,
|
"sections",
|
||||||
lang as keyof ContentEntryMap
|
lang as keyof ContentEntryMap,
|
||||||
|
"call-to-action"
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user