Files
Cell 5f1e79f49c feat(i18n): add RTL support for Arabic, Persian and Urdu (#831)
* feat(i18n): add RTL support and Arabic/Persian translations

- Add `dir` attribute to `<html>` via `.Site.Language.Direction`
- Convert physical CSS properties to logical properties across ~30 SCSS files
- Add `[dir="rtl"]` overrides for elements that need physical direction (code blocks, translate, icons)
- Add `logical-direction.html` template function for config value normalization
- Add RTL-aware deprecation warnings for old "left"/"right" config values
- Rename github corner, TOC position, reading progress config values from "left"/"right" to "start"/"end"
- Add Arabic (ar.toml) and Persian (fa.toml) i18n translation files
- Update multilingual documentation with RTL language configuration guide

* feat(shortcodes): add RTL support for tabs and refactor border-radius mixin

- Rename tabs placement values from "left"/"right" to "start"/"end" with deprecation warnings
- Convert all physical directional properties in tabs SCSS to logical properties
- Add RTL overrides for translate and box-shadow in tabs
- Add "start"/"end" support to border-radius mixin using CSS logical properties
- Refactor fixit-decryptor to use border-radius(start/end) mixin

* feat(assets): add RTL support for toc-dialog slide animation

The mobile toc-dialog always slid in from the right (100vw). In RTL
mode it should slide from the left (-100vw), matching the
border-inline-start/margin-inline-end anchoring.

* feat(assets): add RTL support for post-tag comma separator

* refactor(assets): extract RTL styles into dedicated _rtl.scss

* feat(assets): add RTL support for theme-switch and directional icons

* feat(i18n): add RTL support and improve i18n

- Add RTL typography corrections for Arabic-script languages (:lang(ar/fa/ur))
- Remove fa-list-ol from RTL flip list (numbers get mirrored)
- Add Urdu translation file (i18n/ur.toml)
- Rename noMoretTranslations to noTranslations and simplify all translations
- Update json-viewer-element from 1.0.4 to 1.0.6
- Add RTL test posts (index.en.md, index.ar.md)
- Fix layout partials for RTL support

See https://fixit.lruihao.cn/docs/content-management/introduction/#rtl-language-support
2026-08-24 00:22:34 +08:00

209 lines
4.7 KiB
SCSS

@use "sass:color";
@use "core/functions" as *;
@use "core/mixins" as *;
@use "variables" as *;
// Collection Navigation
.single .collection-card {
font-size: 0.875rem;
margin-block: 1rem;
padding: 1rem 1.25rem;
position: relative;
user-select: none;
background-color: light-dark(color.adjust($global-background-color, $lightness: -4%), color.adjust($global-background-color-dark, $lightness: 4%));
@include border-radius(0.5rem);
&:has(.collection-nav-item:nth-child(2))::before {
content: '';
position: absolute;
inset-inline-start: 50%;
bottom: 0.75rem;
width: 1px;
height: 2rem;
background: linear-gradient(
to bottom,
light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)),
light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.08)) 50%,
light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)) 100%
);
}
.collection-title {
@include link(false, false);
}
.collection-nav {
display: flex;
justify-content: space-between;
gap: 1rem;
&:not(:empty) {
margin-top: 0.5rem;
}
.collection-nav-item {
flex-grow: 1;
max-width: calc(50% - 0.5rem);
font-weight: 500;
display: flex;
align-items: center;
transition: all 0.3s ease-out;
&:only-child {
max-width: 100%;
}
i {
flex-shrink: 0;
[dir="rtl"] & {
scale: -1 1;
}
}
span {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&[rel='next'] {
text-align: end;
}
&[rel='prev']:hover {
translate: -4px 0;
}
&[rel='next']:hover {
translate: 4px 0;
}
}
}
@include media('print') {
display: none !important;
}
}
// Collection aside container
.aside-collection {
position: sticky;
box-sizing: border-box;
margin-bottom: 8rem;
@include overflow-wrap(break-word);
@include sticky-top-offset;
@include media('print') {
display: none !important;
}
}
// Collection List
.collection-details {
&:not(:last-of-type) {
margin-bottom: 0.5rem;
}
&.open {
.collection-summary {
background-color: light-dark(color.adjust($global-background-color, $lightness: -5%), color.adjust($global-background-color-dark, $lightness: 5%));
}
}
.collection-summary {
display: flex;
align-items: baseline;
gap: 0.25em;
padding: 0.2em 0.5em;
user-select: none;
background-color: light-dark(color.adjust($global-background-color, $lightness: -5%), color.adjust($global-background-color-dark, $lightness: 5%));
> i.fa-layer-group {
flex-shrink: 0;
}
.collection-name {
flex-grow: 1;
font-weight: bold;
font-size: fi-var(collection-title-font-size);
&::before {
content: attr(title) '・';
}
}
.collection-count {
flex-shrink: 0;
color: fi-var(global-font-secondary-color);
}
.details-icon {
flex-shrink: 0;
}
}
.collection-content {
font-size: fi-var(collection-list-font-size);
background-color: light-dark(color.adjust($global-background-color, $lightness: -3%), color.adjust($global-background-color-dark, $lightness: 3%));
.collection-list {
margin: 0;
padding-inline: 1.6em 0.8em;
padding-block: 0.4em;
text-indent: -0.8em;
list-style: none;
overflow-y: auto;
max-height: 60vh;
@include scrollbar-width(none, 0);
.collection-item > a::before,
.collection-item > span::before {
content: '|';
font-weight: 600;
margin-inline-end: 0.5em;
position: relative;
bottom: 2px;
color: fi-var(single-link-color);
}
.collection-item > .active {
font-weight: bold;
color: fi-var(single-link-color);
&::before {
color: fi-var(single-link-hover-color);
}
}
}
.collection-nav-simple {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5em;
background-color: light-dark(color.adjust($global-background-color, $lightness: -5%), color.adjust($global-background-color-dark, $lightness: 5%));
[dir="rtl"] & i {
scale: -1 1;
}
a.collection-nav-item {
padding-inline: 2px;
@include border-radius(full);
transition: background-color 0.3s ease-out;
&:hover {
background-color: light-dark(color.adjust($global-background-color, $lightness: -10%), color.adjust($global-background-color-dark, $lightness: 10%));
}
}
> i.collection-nav-item {
padding: 4px 2px;
cursor: not-allowed;
}
}
}
}