diff --git a/docs/configuration.md b/docs/configuration.md index e4cc24e02..ecceafdf6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -776,6 +776,19 @@ without the `#` in the URL and SEO optimization. > }; > ``` +## rtl + +- Type: `Boolean` +- Default: `false` + +Enables Right-to-Left (RTL) layout for the documentation. When set to `true`, the sidebar will appear on the right, text will be aligned to the right, and the overall layout will be mirrored for RTL languages. + +```js +window.$docsify = { + rtl: true, +}; +``` + ## routes - Type: `Object` diff --git a/src/core/Docsify.js b/src/core/Docsify.js index dbf7755ce..1957b2f34 100644 --- a/src/core/Docsify.js +++ b/src/core/Docsify.js @@ -25,6 +25,11 @@ export class Docsify extends Fetch( this.initRender(); // Render base DOM this.initEvent(); // Bind events this.initFetch(); // Fetch data + + if (this.config.rtl) { + document.body.classList.add('rtl'); + } + this.callHook('mounted'); } diff --git a/src/core/config.js b/src/core/config.js index bfcd0d0c2..6f9e60750 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -36,6 +36,7 @@ export default function (vm) { repo: '', routes: {}, routerMode: 'hash', + rtl: false, subMaxLevel: 0, // themeColor: '', topMargin: 0, diff --git a/src/themes/shared/__index.css b/src/themes/shared/__index.css index 3ff0512e8..bbe5d917e 100644 --- a/src/themes/shared/__index.css +++ b/src/themes/shared/__index.css @@ -11,3 +11,4 @@ @import '_util.css'; @import '_mq.css'; @import '_classes.css'; +@import '_rtl.css'; diff --git a/src/themes/shared/_rtl.css b/src/themes/shared/_rtl.css new file mode 100644 index 000000000..99d77a183 --- /dev/null +++ b/src/themes/shared/_rtl.css @@ -0,0 +1,23 @@ +/* RTL specific styles */ +body.rtl { + direction: rtl; + text-align: right; +} + +/* Adjust sidebar for RTL */ +body.rtl .sidebar { + left: auto; + right: 0; +} + +body.rtl .content { + margin-left: auto; + margin-right: 300px; /* Assuming default sidebar width is 300px */ +} + +body.rtl .app-nav { + left: auto; + right: 0; +} + +/* Add more specific RTL adjustments as needed */ diff --git a/test/e2e/rtl.test.js b/test/e2e/rtl.test.js new file mode 100644 index 000000000..6f6105aea --- /dev/null +++ b/test/e2e/rtl.test.js @@ -0,0 +1,46 @@ +import docsifyInit from '../helpers/docsify-init.js'; +import { test, expect } from './fixtures/docsify-init-fixture.js'; + +test.describe('RTL Mode', () => { + test('should render in RTL mode when rtl:true is set', async ({ page }) => { + // Initialize docsify with RTL configuration + await docsifyInit({ + config: { + rtl: true, + // Add a sidebar to ensure it's rendered and we can test its position + loadSidebar: true, + }, + markdown: { + homepage: '# Test RTL Page', + sidebar: ` +* [Home](/) +* [Page2](/page2) + `, + }, + // _logHTML: true, // Uncomment for debugging if needed + }); + + // Check if body has 'rtl' class + await expect(page.locator('body')).toHaveClass(/rtl/); + + // Check sidebar visibility and position + const sidebar = page.locator('.sidebar'); + await expect(sidebar).toBeVisible(); + + // Check computed style for sidebar position + // This is generally more robust than bounding box calculations if CSS is clear + await expect(sidebar).toHaveCSS('right', '0px'); + + // Optional: Bounding box check (can be more fragile due to scrollbars, etc.) + // const sidebarBoundingBox = await sidebar.boundingBox(); + // const viewportWidth = page.viewportSize().width; + // expect(sidebarBoundingBox.x + sidebarBoundingBox.width).toBeCloseTo(viewportWidth, 2); // Allow 2px tolerance + + // Check content area position (to ensure it's not overlapping with the right-aligned sidebar) + const content = page.locator('.content'); + await expect(content).toBeVisible(); + // The CSS for .content in RTL is `margin-right: 300px;` + // We can check if its left side is not at 0, or its right margin is indeed 300px + await expect(content).toHaveCSS('margin-right', '300px'); + }); +});