mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 11:29:33 +08:00
feat: add RTL language support (#531)
* feat: add RTL language support - Add `SITE.dir` config option. - Replace physical Tailwind classes with logical property classes. Resolves #439 * docs: add `dir` section in doc
This commit is contained in:
@@ -12,7 +12,7 @@ import { SITE } from "@/config";
|
|||||||
href="/"
|
href="/"
|
||||||
class="focus-outline mt-8 mb-2 flex hover:text-foreground/75"
|
class="focus-outline mt-8 mb-2 flex hover:text-foreground/75"
|
||||||
>
|
>
|
||||||
<IconChevronLeft class="inline-block size-6" />
|
<IconChevronLeft class="inline-block size-6 rtl:rotate-180" />
|
||||||
<span>Go back</span>
|
<span>Go back</span>
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import IconArrowNarrowUp from "@/assets/icons/IconArrowNarrowUp.svg";
|
|||||||
<div
|
<div
|
||||||
id="btt-btn-container"
|
id="btt-btn-container"
|
||||||
class:list={[
|
class:list={[
|
||||||
"fixed right-4 bottom-8 z-50",
|
"fixed end-4 bottom-8 z-50",
|
||||||
"md:sticky md:right-auto md:float-end md:mr-1",
|
"md:sticky md:end-auto md:float-end md:me-1",
|
||||||
"translate-y-14 opacity-0 transition duration-500",
|
"translate-y-14 opacity-0 transition duration-500",
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const isActive = (path: string) => {
|
|||||||
<a
|
<a
|
||||||
id="skip-to-content"
|
id="skip-to-content"
|
||||||
href="#main-content"
|
href="#main-content"
|
||||||
class="absolute -top-full left-16 z-50 bg-background px-3 py-2 text-accent backdrop-blur-lg transition-all focus:top-4"
|
class="absolute start-16 -top-full z-50 bg-background px-3 py-2 text-accent backdrop-blur-lg transition-all focus:top-4"
|
||||||
>
|
>
|
||||||
Skip to content
|
Skip to content
|
||||||
</a>
|
</a>
|
||||||
@@ -47,7 +47,7 @@ const isActive = (path: string) => {
|
|||||||
</a>
|
</a>
|
||||||
<nav
|
<nav
|
||||||
id="nav-menu"
|
id="nav-menu"
|
||||||
class="flex w-full flex-col items-center sm:ml-2 sm:flex-row sm:justify-end sm:space-x-4 sm:py-0"
|
class="flex w-full flex-col items-center sm:ms-2 sm:flex-row sm:justify-end sm:space-x-4 sm:py-0"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
id="menu-btn"
|
id="menu-btn"
|
||||||
@@ -65,7 +65,7 @@ const isActive = (path: string) => {
|
|||||||
"mt-4 grid w-44 grid-cols-2 place-content-center gap-2",
|
"mt-4 grid w-44 grid-cols-2 place-content-center gap-2",
|
||||||
"[&>li>a]:block [&>li>a]:px-4 [&>li>a]:py-3 [&>li>a]:text-center [&>li>a]:font-medium [&>li>a]:hover:text-accent sm:[&>li>a]:px-2 sm:[&>li>a]:py-1",
|
"[&>li>a]:block [&>li>a]:px-4 [&>li>a]:py-3 [&>li>a]:text-center [&>li>a]:font-medium [&>li>a]:hover:text-accent sm:[&>li>a]:px-2 sm:[&>li>a]:py-1",
|
||||||
"hidden",
|
"hidden",
|
||||||
"sm:mt-0 sm:ml-0 sm:flex sm:w-auto sm:gap-x-5 sm:gap-y-0",
|
"sm:mt-0 sm:flex sm:w-auto sm:gap-x-5 sm:gap-y-0",
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<li class="col-span-2">
|
<li class="col-span-2">
|
||||||
|
|||||||
@@ -18,21 +18,21 @@ const { page } = Astro.props;
|
|||||||
<LinkButton
|
<LinkButton
|
||||||
disabled={!page.url.prev}
|
disabled={!page.url.prev}
|
||||||
href={page.url.prev as string}
|
href={page.url.prev as string}
|
||||||
class:list={["mr-4 select-none", { "opacity-50": !page.url.prev }]}
|
class:list={["me-4 select-none", { "opacity-50": !page.url.prev }]}
|
||||||
ariaLabel="Previous"
|
ariaLabel="Previous"
|
||||||
>
|
>
|
||||||
<IconArrowLeft class="inline-block" />
|
<IconArrowLeft class="inline-block rtl:rotate-180" />
|
||||||
Prev
|
Prev
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
{page.currentPage} / {page.lastPage}
|
{page.currentPage} / {page.lastPage}
|
||||||
<LinkButton
|
<LinkButton
|
||||||
disabled={!page.url.next}
|
disabled={!page.url.next}
|
||||||
href={page.url.next as string}
|
href={page.url.next as string}
|
||||||
class:list={["ml-4 select-none", { "opacity-50": !page.url.next }]}
|
class:list={["ms-4 select-none", { "opacity-50": !page.url.next }]}
|
||||||
ariaLabel="Next"
|
ariaLabel="Next"
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
<IconArrowRight class="inline-block" />
|
<IconArrowRight class="inline-block rtl:rotate-180" />
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,15 +20,15 @@ const { tag, tagName, size = "sm" } = Astro.props;
|
|||||||
href={`/tags/${tag}/`}
|
href={`/tags/${tag}/`}
|
||||||
transition:name={tag}
|
transition:name={tag}
|
||||||
class:list={[
|
class:list={[
|
||||||
"relative pr-2 text-lg underline decoration-dashed group-hover:-top-0.5 group-hover:text-accent focus-visible:p-1",
|
"relative pe-2 text-lg underline decoration-dashed group-hover:-top-0.5 group-hover:text-accent focus-visible:p-1",
|
||||||
{ "text-sm": size === "sm" },
|
{ "text-sm": size === "sm" },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<IconHash
|
<IconHash
|
||||||
class:list={[
|
class:list={[
|
||||||
"inline-block opacity-80",
|
"inline-block opacity-80",
|
||||||
{ "-mr-3.5 size-4": size === "sm" },
|
{ "-me-3.5 size-4": size === "sm" },
|
||||||
{ "-mr-5 size-6": size === "lg" },
|
{ "-me-5 size-6": size === "lg" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<span>{tagName}</span>
|
<span>{tagName}</span>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const SITE = {
|
|||||||
url: "https://github.com/satnaing/astro-paper/edit/main/",
|
url: "https://github.com/satnaing/astro-paper/edit/main/",
|
||||||
},
|
},
|
||||||
dynamicOgImage: true,
|
dynamicOgImage: true,
|
||||||
|
dir: "ltr", // "rtl" | "auto"
|
||||||
lang: "en", // html lang code. Set this empty and default will be "en"
|
lang: "en", // html lang code. Set this empty and default will be "en"
|
||||||
timezone: "Asia/Bangkok", // Default global timezone (IANA format) https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
timezone: "Asia/Bangkok", // Default global timezone (IANA format) https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export const SITE = {
|
|||||||
url: "https://github.com/satnaing/astro-paper/edit/main/",
|
url: "https://github.com/satnaing/astro-paper/edit/main/",
|
||||||
},
|
},
|
||||||
dynamicOgImage: true, // enable automatic dynamic og-image generation
|
dynamicOgImage: true, // enable automatic dynamic og-image generation
|
||||||
|
dir: "ltr", // "rtl" | "auto"
|
||||||
lang: "en", // html lang code. Set this empty and default will be "en"
|
lang: "en", // html lang code. Set this empty and default will be "en"
|
||||||
timezone: "Asia/Bangkok", // Default global timezone (IANA format) https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
timezone: "Asia/Bangkok", // Default global timezone (IANA format) https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
} as const;
|
} as const;
|
||||||
@@ -66,6 +67,7 @@ Here are SITE configuration options
|
|||||||
| `showBackButton` | Determines whether to display the `Go back` button in each blog post. |
|
| `showBackButton` | Determines whether to display the `Go back` button in each blog post. |
|
||||||
| `editPost` | This option allows users to suggest changes to a blog post by providing an edit link under blog post titles. This feature can be disabled by setting `SITE.editPost.enabled` to `false`. |
|
| `editPost` | This option allows users to suggest changes to a blog post by providing an edit link under blog post titles. This feature can be disabled by setting `SITE.editPost.enabled` to `false`. |
|
||||||
| `dynamicOgImage` | This option controls whether to [generate dynamic og-image](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/) if no `ogImage` is specified in the blog post frontmatter. If you have many blog posts, you might want to disable this feature. See the [trade-off](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/#trade-off) for more details. |
|
| `dynamicOgImage` | This option controls whether to [generate dynamic og-image](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/) if no `ogImage` is specified in the blog post frontmatter. If you have many blog posts, you might want to disable this feature. See the [trade-off](https://astro-paper.pages.dev/posts/dynamic-og-image-generation-in-astropaper-blog-posts/#trade-off) for more details. |
|
||||||
|
| `dir` | Specifies the text direction of the entire blog. Used as [HTML dir attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir) in `<html dir="ltr">`. Supported values: `ltr` \| `rtl` \| `auto` |
|
||||||
| `lang` | Used as HTML ISO Language code in `<html lang"en">`. Default is `en`. |
|
| `lang` | Used as HTML ISO Language code in `<html lang"en">`. Default is `en`. |
|
||||||
| `timezone` | This option allows you to specify your timezone using the [IANA format](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Setting this ensures consistent timestamps across your localhost and deployed site, eliminating time differences. |
|
| `timezone` | This option allows you to specify your timezone using the [IANA format](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Setting this ensures consistent timestamps across your localhost and deployed site, eliminating time differences. |
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,11 @@ const structuredData = {
|
|||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang=`${SITE.lang ?? "en"}` class={`${scrollSmooth && "scroll-smooth"}`}>
|
<html
|
||||||
|
dir={SITE.dir}
|
||||||
|
lang=`${SITE.lang ?? "en"}`
|
||||||
|
class={`${scrollSmooth && "scroll-smooth"}`}
|
||||||
|
>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ const nextPost =
|
|||||||
href={getPath(prevPost.id, prevPost.filePath)}
|
href={getPath(prevPost.id, prevPost.filePath)}
|
||||||
class="flex w-full gap-1 hover:opacity-75"
|
class="flex w-full gap-1 hover:opacity-75"
|
||||||
>
|
>
|
||||||
<IconChevronLeft class="inline-block flex-none" />
|
<IconChevronLeft class="inline-block flex-none rtl:rotate-180" />
|
||||||
<div>
|
<div>
|
||||||
<span>Previous Post</span>
|
<span>Previous Post</span>
|
||||||
<div class="text-sm text-accent/85">{prevPost.title}</div>
|
<div class="text-sm text-accent/85">{prevPost.title}</div>
|
||||||
@@ -144,13 +144,13 @@ const nextPost =
|
|||||||
nextPost && (
|
nextPost && (
|
||||||
<a
|
<a
|
||||||
href={getPath(nextPost.id, nextPost.filePath)}
|
href={getPath(nextPost.id, nextPost.filePath)}
|
||||||
class="flex w-full justify-end gap-1 text-right hover:opacity-75 sm:col-start-2"
|
class="flex w-full justify-end gap-1 text-end hover:opacity-75 sm:col-start-2"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span>Next Post</span>
|
<span>Next Post</span>
|
||||||
<div class="text-sm text-accent/85">{nextPost.title}</div>
|
<div class="text-sm text-accent/85">{nextPost.title}</div>
|
||||||
</div>
|
</div>
|
||||||
<IconChevronRight class="inline-block flex-none" />
|
<IconChevronRight class="inline-block flex-none rtl:rotate-180" />
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ const nextPost =
|
|||||||
heading.classList.add("group");
|
heading.classList.add("group");
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.className =
|
link.className =
|
||||||
"heading-link ml-2 opacity-0 group-hover:opacity-100 focus:opacity-100";
|
"heading-link ms-2 opacity-0 group-hover:opacity-100 focus:opacity-100";
|
||||||
link.href = "#" + heading.id;
|
link.href = "#" + heading.id;
|
||||||
|
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
@@ -235,7 +235,7 @@ const nextPost =
|
|||||||
|
|
||||||
const copyButton = document.createElement("button");
|
const copyButton = document.createElement("button");
|
||||||
copyButton.className =
|
copyButton.className =
|
||||||
"copy-code absolute right-3 -top-3 rounded bg-muted px-2 py-1 text-xs leading-4 text-foreground font-medium";
|
"copy-code absolute end-3 -top-3 rounded bg-muted px-2 py-1 text-xs leading-4 text-foreground font-medium";
|
||||||
copyButton.innerHTML = copyButtonLabel;
|
copyButton.innerHTML = copyButtonLabel;
|
||||||
codeBlock.setAttribute("tabindex", "0");
|
codeBlock.setAttribute("tabindex", "0");
|
||||||
codeBlock.appendChild(copyButton);
|
codeBlock.appendChild(copyButton);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const recentPosts = sortedPosts.filter(({ data }) => !data.featured);
|
|||||||
<IconRss
|
<IconRss
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
class="scale-125 stroke-accent stroke-3"
|
class="scale-125 stroke-accent stroke-3 rtl:-rotate-90"
|
||||||
/>
|
/>
|
||||||
<span class="sr-only">RSS Feed</span>
|
<span class="sr-only">RSS Feed</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -61,7 +61,7 @@ const recentPosts = sortedPosts.filter(({ data }) => !data.featured);
|
|||||||
// only display if at least one social link is enabled
|
// only display if at least one social link is enabled
|
||||||
SOCIALS.length > 0 && (
|
SOCIALS.length > 0 && (
|
||||||
<div class="mt-4 flex flex-col sm:flex-row sm:items-center">
|
<div class="mt-4 flex flex-col sm:flex-row sm:items-center">
|
||||||
<div class="mr-2 mb-1 whitespace-nowrap sm:mb-0">Social Links:</div>
|
<div class="me-2 mb-1 whitespace-nowrap sm:mb-0">Social Links:</div>
|
||||||
<Socials />
|
<Socials />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -103,7 +103,7 @@ const recentPosts = sortedPosts.filter(({ data }) => !data.featured);
|
|||||||
<div class="my-8 text-center">
|
<div class="my-8 text-center">
|
||||||
<LinkButton href="/posts/">
|
<LinkButton href="/posts/">
|
||||||
All Posts
|
All Posts
|
||||||
<IconArrowRight class="inline-block" />
|
<IconArrowRight class="inline-block rtl:-rotate-180" />
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Reference in New Issue
Block a user