Merge pull request #1 from tfmurad/v2

V2
This commit is contained in:
Al Murad Uzzaman
2024-07-31 15:53:53 +06:00
committed by GitHub
57 changed files with 396 additions and 192 deletions
+26 -26
View File
@@ -15,47 +15,47 @@
"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"
}
}
+5 -2
View File
@@ -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 issue -->
## 🐞 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). Its 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).
<!-- licence -->
## 📝 License
Copyright (c) 2023 - Present, Designed & Developed by [Zeon Studio](https://zeon.studio/)
+22 -16
View File
@@ -9,11 +9,11 @@ const CONTENT_DEPTH = 3;
const BLOG_FOLDER = "blog";
// get data from markdown
const getData = (folder, groupDepth) => {
// get paths
const getData = (folder, groupDepth, langIndex = 0) => {
const getPaths = languages
.map((lang) => {
const dir = path.join(CONTENT_ROOT, lang.contentDir, folder);
.map((lang, index) => {
const langFolder = lang.contentDir ? lang.contentDir : lang.languageCode;
const dir = path.join(CONTENT_ROOT, folder, langFolder);
return fs
.readdirSync(dir)
.filter(
@@ -21,29 +21,37 @@ const getData = (folder, groupDepth) => {
!filename.startsWith("-") &&
(filename.endsWith(".md") || filename.endsWith(".mdx")),
)
.map((filename) => {
.flatMap((filename) => {
const filepath = path.join(dir, filename);
const stats = fs.statSync(filepath);
const isFolder = stats.isDirectory();
if (isFolder) {
return getData(filepath, groupDepth);
return getData(filepath, groupDepth, index);
} else {
const file = fs.readFileSync(filepath, "utf-8");
const { data, content } = matter(file);
const pathParts = filepath.split(path.sep);
const slug =
data.slug ||
pathParts
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(/\.[^/.]+$/, "");
const group = pathParts[groupDepth];
slug = `${BLOG_FOLDER}/${slug.split("/").slice(1).join("/")}`;
}
data.slug = slug;
const group = "blog";
return {
lang: lang.languageCode,
lang: languages[index].languageCode, // Set the correct language code dynamically
group: group,
slug: slug,
slug: data.slug,
frontmatter: data,
content: content,
};
@@ -52,9 +60,7 @@ const getData = (folder, groupDepth) => {
})
.flat();
const publishedPages = getPaths.filter(
(page) => !page.frontmatter?.draft && page,
);
const publishedPages = getPaths.filter((page) => !page.frontmatter?.draft);
return publishedPages;
};
@@ -70,7 +76,7 @@ try {
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));
+43 -13
View File
@@ -1,20 +1,49 @@
const fs = require("fs");
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",
"src/layouts/components/ThemeSwitcher.astro",
];
const configFiles = [
{
filePath: "tailwind.config.js",
patterns: ["darkmode:\\s*{[^}]*},", 'darkMode:\\s*"class",'],
},
{ filePath: "src/config/theme.json", patterns: ["colors.darkmode"] },
];
];
rootDirs.forEach(removeDarkModeFromPages);
configFiles.forEach(removeDarkMode);
const filePaths = [
{
filePath: "src/layouts/partials/Header.astro",
patterns: [
"<ThemeSwitchers*(?:\\s+[^>]+)?\\s*(?:\\/\\>|>([\\s\\S]*?)<\\/ThemeSwitchers*>)",
],
},
];
function removeDarkModeFromFiles(filePath, regexPatterns) {
filePaths.forEach(({ filePath, patterns }) => {
removeDarkModeFromFiles(filePath, patterns);
});
deleteAssetList.forEach(deleteAsset);
function deleteAsset(asset) {
try {
fs.unlinkSync(asset);
console.log(`${path.basename(asset)} deleted successfully!`);
} catch (error) {
console.error(`${asset} not found`);
}
}
rootDirs.forEach(removeDarkModeFromPages);
configFiles.forEach(removeDarkMode);
function removeDarkModeFromFiles(filePath, regexPatterns) {
const fileContent = fs.readFileSync(filePath, "utf8");
let updatedContent = fileContent;
regexPatterns.forEach((pattern) => {
@@ -22,9 +51,9 @@ function removeDarkModeFromFiles(filePath, regexPatterns) {
updatedContent = updatedContent.replace(regex, "");
});
fs.writeFileSync(filePath, updatedContent, "utf8");
}
}
function removeDarkModeFromPages(directoryPath) {
function removeDarkModeFromPages(directoryPath) {
const files = fs.readdirSync(directoryPath);
files.forEach((file) => {
@@ -38,9 +67,9 @@ function removeDarkModeFromPages(directoryPath) {
]);
}
});
}
}
function removeDarkMode(configFile) {
function removeDarkMode(configFile) {
const { filePath, patterns } = configFile;
if (filePath === "tailwind.config.js") {
removeDarkModeFromFiles(filePath, patterns);
@@ -49,9 +78,9 @@ function removeDarkMode(configFile) {
patterns.forEach((pattern) => deleteNestedProperty(contentFile, pattern));
fs.writeFileSync(filePath, JSON.stringify(contentFile));
}
}
}
function deleteNestedProperty(obj, propertyPath) {
function deleteNestedProperty(obj, propertyPath) {
const properties = propertyPath.split(".");
let currentObj = obj;
for (let i = 0; i < properties.length - 1; i++) {
@@ -63,4 +92,5 @@ function deleteNestedProperty(obj, propertyPath) {
}
}
delete currentObj[properties[properties.length - 1]];
}
}
})();
+1 -1
View File
@@ -22,7 +22,7 @@
"blog_folder": "blog",
"default_language": "en",
"disable_languages": [],
"default_language_in_path": false
"default_language_in_subdir": false
},
"params": {
+88 -1
View File
@@ -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,
};
+9 -6
View File
@@ -9,6 +9,7 @@ import "@/styles/main.scss";
import { AstroFont } from "astro-font";
import { ViewTransitions } from "astro:transitions";
import SearchModal from "./helpers/SearchModal";
import { getLangFromUrl } from "@/lib/utils/languageParser";
// font families
const pf = theme.fonts.font_family.primary;
@@ -40,6 +41,8 @@ export interface Props {
// distructure frontmatters
const { title, meta_title, description, image, noindex, canonical, lang } =
Astro.props;
const language = lang || getLangFromUrl(Astro.url);
---
<!doctype html>
@@ -108,7 +111,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
<meta
name="description"
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
property="og:title"
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
property="og:description"
content={plainify(
description ? description : config.metadata.meta_description,
description ? description : config.metadata.meta_description
)}
/>
<meta property="og:type" content="website" />
@@ -142,7 +145,7 @@ const { title, meta_title, description, image, noindex, canonical, lang } =
<meta
name="twitter:title"
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
name="twitter:description"
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>
<TwSizeIndicator />
<Header />
<SearchModal client:load />
<SearchModal lang={language} client:load />
<main id="main-content">
<slot />
</main>
+5
View File
@@ -18,6 +18,11 @@ const { title, image, date, author, categories } = data.data;
const lang = getLangFromUrl(Astro.url);
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">
+4 -3
View File
@@ -11,19 +11,20 @@ if (supportedLang.includes(paths[0])) {
lang = paths.shift()!;
}
let baseHref = lang ? `/${lang}` : "/";
let parts = [
{
label: "Home",
href: `/${lang}`,
href: baseHref,
"aria-label":
Astro.url.pathname === `/${lang}` || Astro.url.pathname === `/${lang}/`
Astro.url.pathname === baseHref || Astro.url.pathname === `${baseHref}/`
? "page"
: undefined,
},
];
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" &&
parts.push({
label: humanize(label.replace(".html", "").replace(/[-_]/g, " ")) || "",
+9 -2
View File
@@ -9,7 +9,7 @@ const LanguageSwitcher = ({
lang: string;
pathname: string;
}) => {
const { default_language } = config.settings;
const { default_language, default_language_in_subdir } = config.settings;
// Function to remove trailing slash if necessary
const removeTrailingSlash = (path: string) => {
@@ -21,22 +21,29 @@ const LanguageSwitcher = ({
// Sort languages by weight and filter out disabled languages
const sortedLanguages = languages
// @ts-ignore
.filter(language => !config.settings.disable_languages.includes(language.languageCode))
.sort((a, b) => a.weight - b.weight);
return (
<div className="mr-5">
<div className={`mr-5 ${sortedLanguages.length > 1 ? "block" : "hidden"}`}>
<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"
onChange={(e) => {
const selectedLang = e.target.value;
let newPath;
const baseUrl = window.location.origin;
if (selectedLang === default_language) {
if (default_language_in_subdir) {
newPath = `${baseUrl}/${default_language}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
} else {
newPath = `${baseUrl}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
}
} else {
newPath = `/${selectedLang}${removeTrailingSlash(pathname.replace(`/${lang}`, ""))}`;
}
window.location.href = newPath;
}}
value={lang}
+15 -3
View File
@@ -1,8 +1,11 @@
import searchData from ".json/search.json";
import React, { useEffect, useState } from "react";
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("");
// 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
const startTime = performance.now();
const searchResult = doSearch(searchData);
const searchResult = doSearch(filterSearchData);
const endTime = performance.now();
const totalTime = ((endTime - startTime) / 1000).toFixed(3);
@@ -169,10 +176,15 @@ const SearchModal = () => {
name="search"
value={searchString}
onChange={handleSearch}
autoFocus
autoComplete="off"
/>
</div>
<SearchResult searchResult={searchResult} searchString={searchString} />
<SearchResult
searchResult={searchResult}
searchString={searchString}
lang={lang}
/>
<div className="search-wrapper-footer">
<span className="flex items-center">
<kbd>
+9 -1
View File
@@ -1,7 +1,9 @@
import { slugSelector } from "@/lib/utils/languageParser";
import { plainify, titleify } from "@/lib/utils/textConverter";
import React from "react";
export interface ISearchItem {
lang: string;
group: string;
slug: string;
frontmatter: {
@@ -33,10 +35,13 @@ export interface ISearchGroup {
const SearchResult = ({
searchResult,
searchString,
lang
}: {
searchResult: ISearchItem[];
searchString: string;
lang: string;
}) => {
// generate search result group
const generateSearchGroup = (searchResult: ISearchItem[]) => {
const joinDataByGroup: ISearchGroup[] = searchResult.reduce(
@@ -83,6 +88,7 @@ const SearchResult = ({
);
};
// match underline
const matchUnderline = (text: string, substring: string) => {
const parts = text?.split(new RegExp(`(${substring})`, "gi"));
@@ -148,12 +154,14 @@ const SearchResult = ({
<img
src={item.frontmatter.image}
alt={item.frontmatter.title}
width={100}
height={100}
/>
</div>
)}
<div className="search-result-item-body">
<a
href={`/${item.slug}`}
href={`${slugSelector(item.slug, lang)}`}
className="search-result-item-title search-result-item-link"
>
{matchUnderline(item.frontmatter.title, searchString)}
+7 -5
View File
@@ -4,7 +4,11 @@ import ThemeSwitcher from "@/components/ThemeSwitcher.astro";
import config from "@/config/config.json";
import languages from "@/config/language.json";
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 { IoSearch } from "react-icons/io5";
@@ -133,12 +137,10 @@ if (disabledLanguages.includes(lang)) {
}
{/* Theme switcher */}
<ThemeSwitcher className="mr-5" />
{/* Language switcher */}
{
languages.length > 1 && (
<LanguageSwitcher client:load lang={lang} pathname={pathname} />
)
}
{/* Navigation button */}
{
navigation_button.enable && (
+1 -1
View File
@@ -67,7 +67,7 @@ const { testimonial } = Astro.props;
</div>
</div>
</div>
),
)
)}
</div>
<div class="testimonial-slider-pagination mt-9 flex items-center justify-center text-center" />
+66 -2
View File
@@ -9,7 +9,7 @@ import {
import config from "@/config/config.json";
import languages from "@/config/language.json";
export const getSinglePage = async <C extends CollectionKey>(
export const getSP = async <C extends CollectionKey>(
collectionName: C,
lang: keyof ContentEntryMap | undefined
): Promise<CollectionEntry<C>[]> => {
@@ -40,7 +40,7 @@ export const getSinglePage = async <C extends CollectionKey>(
return removeDrafts;
};
export const getListPage = async <C extends CollectionKey>(
export const getLP = async <C extends CollectionKey>(
collectionName: C,
lang: keyof ContentEntryMap | undefined
): Promise<CollectionEntry<C>[]> => {
@@ -67,4 +67,68 @@ export const getListPage = async <C extends CollectionKey>(
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;
};
---
+8 -8
View File
@@ -16,7 +16,7 @@ export const getTaxonomy = async (collection: string, name: string) => {
actualCollection = language.contentDir;
} else {
const defaultLanguageMatch = languages.find(
(l) => l.languageCode === default_language,
(l) => l.languageCode === default_language
);
if (defaultLanguageMatch) {
actualCollection = defaultLanguageMatch.contentDir;
@@ -24,10 +24,10 @@ export const getTaxonomy = async (collection: string, name: string) => {
}
const singlePages = await getCollection(
actualCollection as keyof ContentEntryMap,
"blog" as keyof ContentEntryMap,
({ 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]);
let taxonomies: string[] = [];
@@ -52,7 +52,7 @@ export const getAllTaxonomy = async (collection: string, name: string) => {
actualCollection = language.contentDir;
} else {
const defaultLanguageMatch = languages.find(
(l) => l.languageCode === default_language,
(l) => l.languageCode === default_language
);
if (defaultLanguageMatch) {
actualCollection = defaultLanguageMatch.contentDir;
@@ -60,10 +60,10 @@ export const getAllTaxonomy = async (collection: string, name: string) => {
}
const singlePages = await getCollection(
actualCollection as keyof ContentEntryMap,
"blog" as keyof ContentEntryMap,
({ 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]);
let taxonomies: string[] = [];
+7 -14
View File
@@ -76,7 +76,7 @@ const filteredSupportedLang = supportedLang.filter(
export { filteredSupportedLang as supportedLang };
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;
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
if (trailing_slash) {
if (!constructedUrl.endsWith("/")) {
constructedUrl += "/";
}
} else {
if (constructedUrl.endsWith("/")) {
if (constructedUrl.endsWith("/") && constructedUrl !== "/") {
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;
};
+1 -1
View File
@@ -10,7 +10,7 @@ export async function getStaticPaths() {
supportedLang.map(async (lang) => {
const pages = await getSinglePage("pages", lang as keyof ContentEntryMap);
return pages.map((page: any) => ({
return pages.map((page) => ({
params: {
lang: lang || undefined,
regular: page.slug.split("/").pop(),
+2 -5
View File
@@ -4,7 +4,7 @@ import Base from "@/layouts/Base.astro";
import { getListPage } from "@/lib/contentParser.astro";
import { supportedLang } from "@/lib/utils/languageParser";
import { markdownify } from "@/lib/utils/textConverter";
import type { ContentCollectionKey, ContentEntryMap } from "astro:content";
import type { ContentEntryMap } from "astro:content";
export function getStaticPaths() {
const paths = supportedLang.map((lang) => ({
@@ -14,10 +14,7 @@ export function getStaticPaths() {
}
const { lang } = Astro.params;
const about: any = await getListPage(
"about" as ContentCollectionKey,
lang as keyof ContentEntryMap
);
const about = await getListPage("about", lang as keyof ContentEntryMap);
const { Content } = await about[0].render();
const { title, description, meta_title, image } = about[0].data;
+3 -3
View File
@@ -14,12 +14,12 @@ export async function getStaticPaths() {
const paths = await Promise.all(
supportedLang.map(async (lang) => {
const authors: any = await getSinglePage(
const authors = await getSinglePage(
COLLECTION_FOLDER,
lang as keyof ContentEntryMap
);
return authors.map((author: any) => ({
return authors.map((author) => ({
params: {
lang: lang || undefined,
single: author.slug.split("/").pop(),
@@ -42,7 +42,7 @@ const { Content } = await author.render();
const BLOG_FOLDER = "blog";
const posts = await getSinglePage(BLOG_FOLDER, lang as keyof ContentEntryMap);
const postFilterByAuthor = posts.filter(
(post: any) => slugify(post.data.author) === slugify(title)
(post) => slugify(post.data.author) === slugify(title)
);
---
+1 -1
View File
@@ -16,7 +16,7 @@ export function getStaticPaths() {
}
const { lang } = Astro.params;
const authorIndex: any = await getListPage(
const authorIndex = await getListPage(
COLLECTION_FOLDER,
lang as keyof ContentEntryMap
);
+2 -2
View File
@@ -10,12 +10,12 @@ export async function getStaticPaths() {
const paths = await Promise.all(
supportedLang.map(async (lang) => {
const posts: any = await getSinglePage(
const posts = await getSinglePage(
BLOG_FOLDER,
lang as keyof ContentEntryMap
);
return posts.map((post: any) => ({
return posts.map((post) => ({
params: {
lang: lang || undefined,
single: post.slug.split("/").pop(),
+1 -1
View File
@@ -19,7 +19,7 @@ export function getStaticPaths() {
}
const { lang } = Astro.params;
const BLOG_FOLDER = "blog";
const postIndex: any = await getListPage(
const postIndex = await getListPage(
BLOG_FOLDER,
lang as keyof ContentEntryMap
);
+1 -5
View File
@@ -4,7 +4,6 @@ import Base from "@/layouts/Base.astro";
import { getListPage } from "@/lib/contentParser.astro";
import { getTranslations, supportedLang } from "@/lib/utils/languageParser";
import PageHeader from "@/partials/PageHeader.astro";
import type { CollectionKey } from "astro:content";
import { type ContentEntryMap } from "astro:content";
export function getStaticPaths() {
@@ -15,10 +14,7 @@ export function getStaticPaths() {
}
const { lang } = Astro.params;
const contact: any = await getListPage(
"contact" as CollectionKey,
lang as keyof ContentEntryMap
);
const contact = await getListPage("contact", lang as keyof ContentEntryMap);
const { contact_form_action }: { contact_form_action: string } = config.params;
const { title, description, meta_title, image } = contact[0].data;
+10 -20
View File
@@ -6,18 +6,9 @@ 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 type { ContentCollectionKey, ContentEntryMap } 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) => ({
@@ -27,20 +18,19 @@ export function getStaticPaths() {
}
const { lang } = Astro.params;
const homepage: any = await getListPage(
"homepage" as ContentCollectionKey,
lang as keyof ContentEntryMap
);
const { banner, features }: Homepage = homepage[0].data;
const homepage = await getListPage("homepage", lang as keyof ContentEntryMap);
const { banner, features } = homepage[0].data;
const testimonial = await getSinglePage(
"sections/testimonial" as ContentCollectionKey,
lang as keyof ContentEntryMap
"sections",
lang as keyof ContentEntryMap,
"testimonial"
);
const call_to_action = await getSinglePage(
"sections/call-to-action" as ContentCollectionKey,
lang as keyof ContentEntryMap
"sections",
lang as keyof ContentEntryMap,
"call-to-action"
);
---