diff --git a/packages/starlight-view-modes/components/HeaderButtons.astro b/packages/starlight-view-modes/components/HeaderButtons.astro index 4ba12c7..112549b 100644 --- a/packages/starlight-view-modes/components/HeaderButtons.astro +++ b/packages/starlight-view-modes/components/HeaderButtons.astro @@ -9,7 +9,7 @@ justify-content: center; align-items: center; gap: 1rem; - + } #view-modes-header-div::before { content: ""; @@ -53,7 +53,7 @@ body.view-modes-zen-mode-header-disabled #view-modes-zen-mode-off-header > svg:h } - + - \ No newline at end of file diff --git a/packages/starlight-view-modes/components/MobileViewModes.astro b/packages/starlight-view-modes/components/MobileViewModes.astro index 6e3ef22..7633061 100644 --- a/packages/starlight-view-modes/components/MobileViewModes.astro +++ b/packages/starlight-view-modes/components/MobileViewModes.astro @@ -9,7 +9,7 @@ justify-content: center; align-items: center; gap: 1rem; - + } #view-modes-header-div-mobile::before { content: ""; @@ -49,7 +49,7 @@ body.view-modes-presentation-mode #view-modes-presentation-mode-off-header-mobil } - + - \ No newline at end of file diff --git a/packages/starlight-view-modes/components/SidebarSublist.astro b/packages/starlight-view-modes/components/SidebarSublist.astro new file mode 100644 index 0000000..688b13d --- /dev/null +++ b/packages/starlight-view-modes/components/SidebarSublist.astro @@ -0,0 +1,173 @@ +--- + +import { Icon } from 'astro-icon/components'; +function flattenSidebar(sidebar: SidebarEntry[]): Link[] { + return sidebar.flatMap((entry) => + entry.type === 'group' ? flattenSidebar(entry.entries) : entry + ); +} + +interface Link { + type: 'link'; + label: string; + href: string; + isCurrent: boolean; + badge: any | undefined; + attrs: any; +} + +interface Group { + type: 'group'; + label: string; + entries: (Link | Group)[]; + collapsed: boolean; + badge: any | undefined; +} + +type SidebarEntry = Link | Group; + +interface Props { + sublist: SidebarEntry[]; + nested?: boolean; +} + +const { sublist, nested } = Astro.props; +--- + + + + diff --git a/packages/starlight-view-modes/components/SidebarToggle.astro b/packages/starlight-view-modes/components/SidebarToggle.astro new file mode 100644 index 0000000..28ad06d --- /dev/null +++ b/packages/starlight-view-modes/components/SidebarToggle.astro @@ -0,0 +1,160 @@ + + + diff --git a/packages/starlight-view-modes/components/ViewModes.astro b/packages/starlight-view-modes/components/ViewModes.astro index 0e16cd9..e83e930 100644 --- a/packages/starlight-view-modes/components/ViewModes.astro +++ b/packages/starlight-view-modes/components/ViewModes.astro @@ -254,4 +254,4 @@ body.view-modes-presentation-mode.view-modes-zen-mode-table-of-contents-enabled document.body.classList.add("view-modes-zen-mode-template-doc"); } }); - + \ No newline at end of file diff --git a/packages/starlight-view-modes/index.ts b/packages/starlight-view-modes/index.ts index 54417d4..daa35e5 100644 --- a/packages/starlight-view-modes/index.ts +++ b/packages/starlight-view-modes/index.ts @@ -1,199 +1,251 @@ -import type { StarlightPlugin, StarlightUserConfig } from "@astrojs/starlight/types"; -import { AstroError } from "astro/errors"; -import { z } from "astro/zod"; +import type { + StarlightPlugin, + StarlightUserConfig, +} from '@astrojs/starlight/types'; +import { AstroError } from 'astro/errors'; +import { z } from 'astro/zod'; -import { starlightViewModesIntegration } from "./libs/integration"; +import { starlightViewModesIntegration } from './libs/integration'; +import icon from "astro-icon"; const starlightViewModesConfigSchema = z - .object({ - /** - * Indicates if Zen mode is enabled. When enabled, the user is able to active Zen mode which - * provides a distraction-free interface by hiding everything except the main content. - * - * @type {boolean} - * @default true - */ - zenModeEnabled: z.boolean().default(true), - - /** - * Choose the position of the close button for the Zen mode. It is only visible when the Zen mode - * is active and can be in one of four corners: top left, top right, bottom left, or bottom right. - * - * @type {enum} - * @default "top-right" - */ - zenModeCloseButtonPosition: z - .enum(["top-left", "top-right", "bottom-left", "bottom-right"]) - .default("top-right"), - - /** - * Indicates if the header should be shown if the user is actively in Zen mode. - * - * @type {boolean} - * @default false - */ - zenModeShowHeader: z.boolean().default(false), - - /** - * Indicates if the sidebar should be shown if the user is actively in Zen mode. - * - * @type {boolean} - * @default false - */ - zenModeShowSidebar: z.boolean().default(false), - - /** - * Indicates if the table of contents should be shown if the user is actively in Zen mode. - * - * @type {boolean} - * @default false - */ - zenModeShowTableOfContents: z.boolean().default(true), - - /** - * Indicates if the footer should be shown if the user is actively in Zen mode. - * - * @type {boolean} - * @default true - */ - zenModeShowFooter: z.boolean().default(true), - - /** - * This option can enable or disable a button in the table of contents sidebar that will switch into Zen Mode or back from Zen Mode. - * - * @type {boolean} - * @default true - */ - zenModeShowSwitchInTableOfContents: z.boolean().default(true), - - /** - * This option can enable or disable a button in the header that will switch into Zen Mode or back from Zen Mode. - * - * @type {boolean} - * @default true - */ - zenModeShowSwitchInHeader: z.boolean().default(true), - - /** - * This option can enable or disable a button in the header of mobile devices that will switch into Zen Mode or back from Zen Mode. - * - * @type {boolean} - * @default true - */ - zenModeShowSwitchInHeaderMobile: z.boolean().default(true), - - /** - * Indicates if Presentation Mode is enabled. When enabled, the user is able to active Presentation Mode which - * converts the main content into a presentation-like view intended for teaching or presentation purposes. - * - * @type {boolean} - * @default false - */ - presentationModeEnabled: z.boolean().default(false), - - /** - * Choose the position of the close button for the Presentation mode. It is only visible when the Presentation mode - * is active and can be in one of four corners: top left, top right, bottom left, or bottom right. - * - * @type {enum} - * @default "top-right" - */ - presentationModeCloseButtonPosition: z - .enum(["top-left", "top-right", "bottom-left", "bottom-right"]) - .default("top-right"), - - // /** - // * Choose the position of the control button for the Presentation Mode. It is only visible when the Presentation Mode - // * is active and can be in one of eight corners: top left, top middle, top right, middle right, bottom left, bottom middle, bottom right, or middle left. - // * - // * @type {enum} - // * @default "middle-right" - // */ - // presentationModeControlButtonPosition: z - // .enum([ - // "top-left", - // "top-middle", - // "top-right", - // "middle-right", - // "bottom-left", - // "bottom-middle", - // "bottom-right", - // "middle-left", - // ]) - // .default("middle-right"), - - /** - * This option can enable or disable a button in the header that will switch into Presentation Mode or back from Presentation Mode. - * - * @type {boolean} - * @default true - */ - presentationModeShowSwitchInHeader: z.boolean().default(true), - - /** - * This option can enable or disable a button in the header of mobile devices that will switch into Presentation Mode or back from Presentation Mode. - * - * @type {boolean} - * @default true - */ - presentationModeShowSwitchInHeaderMobile: z.boolean().default(true), - - /** - * This option can enable or disable a button in the table of contents sidebar that will switch into Presentation Mode or back from Presentation Mode. - * - * @type {boolean} - * @default true - */ - presentationModeShowSwitchInTableOfContents: z.boolean().default(true), - }) - .default({}); + .object({ + /** + * Indicates if Zen mode is enabled. When enabled, the user is able to active Zen mode which + * provides a distraction-free interface by hiding everything except the main content. + * + * @type {boolean} + * @default true + */ + zenModeEnabled: z.boolean().default(true), + + /** + * Choose the position of the close button for the Zen mode. It is only visible when the Zen mode + * is active and can be in one of four corners: top left, top right, bottom left, or bottom right. + * + * @type {enum} + * @default "top-right" + */ + zenModeCloseButtonPosition: z + .enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']) + .default('top-right'), + + /** + * Indicates if the header should be shown if the user is actively in Zen mode. + * + * @type {boolean} + * @default false + */ + zenModeShowHeader: z.boolean().default(false), + + /** + * Indicates if the sidebar should be shown if the user is actively in Zen mode. + * + * @type {boolean} + * @default false + */ + zenModeShowSidebar: z.boolean().default(false), + + /** + * Indicates if the table of contents should be shown if the user is actively in Zen mode. + * + * @type {boolean} + * @default false + */ + zenModeShowTableOfContents: z.boolean().default(true), + + /** + * Indicates if the footer should be shown if the user is actively in Zen mode. + * + * @type {boolean} + * @default true + */ + zenModeShowFooter: z.boolean().default(true), + + /** + * This option can enable or disable a button in the table of contents sidebar that will switch into Zen Mode or back from Zen Mode. + * + * @type {boolean} + * @default true + */ + zenModeShowSwitchInTableOfContents: z.boolean().default(true), + + /** + * This option can enable or disable a button in the header that will switch into Zen Mode or back from Zen Mode. + * + * @type {boolean} + * @default true + */ + zenModeShowSwitchInHeader: z.boolean().default(true), + + /** + * This option can enable or disable a button in the header of mobile devices that will switch into Zen Mode or back from Zen Mode. + * + * @type {boolean} + * @default true + */ + zenModeShowSwitchInHeaderMobile: z.boolean().default(true), + + /** + * Indicates if Presentation Mode is enabled. When enabled, the user is able to active Presentation Mode which + * converts the main content into a presentation-like view intended for teaching or presentation purposes. + * + * @type {boolean} + * @default false + */ + presentationModeEnabled: z.boolean().default(false), + + /** + * Choose the position of the close button for the Presentation mode. It is only visible when the Presentation mode + * is active and can be in one of four corners: top left, top right, bottom left, or bottom right. + * + * @type {enum} + * @default "top-right" + */ + presentationModeCloseButtonPosition: z + .enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']) + .default('top-right'), + + // /** + // * Choose the position of the control button for the Presentation Mode. It is only visible when the Presentation Mode + // * is active and can be in one of eight corners: top left, top middle, top right, middle right, bottom left, bottom middle, bottom right, or middle left. + // * + // * @type {enum} + // * @default "middle-right" + // */ + // presentationModeControlButtonPosition: z + // .enum([ + // "top-left", + // "top-middle", + // "top-right", + // "middle-right", + // "bottom-left", + // "bottom-middle", + // "bottom-right", + // "middle-left", + // ]) + // .default("middle-right"), + + /** + * This option can enable or disable a button in the header that will switch into Presentation Mode or back from Presentation Mode. + * + * @type {boolean} + * @default true + */ + presentationModeShowSwitchInHeader: z.boolean().default(true), + + /** + * This option can enable or disable a button in the header of mobile devices that will switch into Presentation Mode or back from Presentation Mode. + * + * @type {boolean} + * @default true + */ + presentationModeShowSwitchInHeaderMobile: z.boolean().default(true), + + /** + * This option can enable or disable a button in the table of contents sidebar that will switch into Presentation Mode or back from Presentation Mode. + * + * @type {boolean} + * @default true + */ + presentationModeShowSwitchInTableOfContents: z.boolean().default(true), + + + /** + * Indicates if the ability to toggle the collapse expanded state of the left sidebar is enabled. + * + * @type {boolean} + * @default true + */ + leftSidebarEnabled: z.boolean().default(true), + + + /** + * Indicates if the ability to toggle the collapse expanded state of the left sidebar is enabled. + * + * @type {boolean} + * @default true + */ + rightSidebarEnabled: z.boolean().default(true), + + + astroIconIntegration: z.any().default( + icon({ + include:{ + mdi:["chevron-left","chevron-right","chevron-down"] + } + }) + ), + }) + .default({}); export default function starlightViewModes( - userConfig?: StarlightViewModesUserConfig + userConfig?: StarlightViewModesUserConfig ): StarlightPlugin { - const parsedConfig = starlightViewModesConfigSchema.safeParse(userConfig); - - if (!parsedConfig.success) { - throw new AstroError( - `The provided plugin configuration is invalid.\n${parsedConfig.error.issues - .map((issue) => issue.message) - .join("\n")}`, - `See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/trueberryless/starlight-view-modes/issues` - ); - } - - return { - name: "starlight-view-modes", - hooks: { - setup({ addIntegration, config, logger, updateConfig }) { - const updatedConfig: Partial = { - components: { ...config.components }, - }; - - if (!updatedConfig.components) { - updatedConfig.components = {}; - } - - // If the user has already has a custom override for the PageSidebar component, don't override it. - if (config.components?.PageSidebar) { - logger.warn( - "It looks like you already have a `PageSidebar` component override in your Starlight configuration." - ); - logger.warn( - "To render `@astrojs/starlight-view-modes`, remove the override for the `PageSidebar` component.\n" - ); - } else { - // Otherwise, add the PageSidebar component override to the user's configuration. - updatedConfig.components.PageSidebar = - "starlight-view-modes/overrides/PageSidebar.astro"; - } - - addIntegration(starlightViewModesIntegration(parsedConfig.data)); - updateConfig(updatedConfig); - }, - }, - }; + const parsedConfig = starlightViewModesConfigSchema.safeParse(userConfig); + + if (!parsedConfig.success) { + throw new AstroError( + `The provided plugin configuration is invalid.\n${parsedConfig.error.issues + .map((issue) => issue.message) + .join('\n')}`, + `See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/trueberryless/starlight-view-modes/issues` + ); + } + + return { + name: 'starlight-view-modes', + hooks: { + setup({ addIntegration, config, logger, updateConfig }) { + + const updatedConfig: Partial = { + components: { ...config.components }, + + }; + + if (!updatedConfig.components) { + updatedConfig.components = {}; + } + + // If the user has already has a custom override for the PageSidebar component, don't override it. + if (config.components?.PageSidebar) { + logger.warn( + 'It looks like you already have a `PageSidebar` component override in your Starlight configuration.' + ); + logger.warn( + 'To render `@astrojs/starlight-view-modes`, remove the override for the `PageSidebar` component.\n' + ); + } else { + // Otherwise, add the PageSidebar component override to the user's configuration. + updatedConfig.components.PageSidebar = + 'starlight-view-modes/overrides/PageSidebar.astro'; + } + if (config.components?.Sidebar) { + logger.warn( + 'It looks like you already have a `Sidebar` component override in your Starlight configuration.' + ); + logger.warn( + 'To render `@astrojs/starlight-view-modes`, remove the override for the `Sidebar` component.\n' + ); + } else { + // Otherwise, add the Sidebar component override to the user's configuration. + updatedConfig.components.Sidebar = + 'starlight-view-modes/overrides/Sidebar.astro'; + } + addIntegration( + parsedConfig.data.astroIconIntegration + ) + // addIntegration(icon()); + addIntegration(starlightViewModesIntegration(parsedConfig.data)); + updateConfig(updatedConfig); + }, + }, + }; } -export type StarlightViewModesUserConfig = z.input; -export type StarlightViewModesConfig = z.output; +export type StarlightViewModesUserConfig = z.input< + typeof starlightViewModesConfigSchema +>; +export type StarlightViewModesConfig = z.output< + typeof starlightViewModesConfigSchema +>; diff --git a/packages/starlight-view-modes/libs/PresentationModePositionStateMachine.js b/packages/starlight-view-modes/libs/PresentationModePositionStateMachine.js index ff77b3d..a8427f6 100644 --- a/packages/starlight-view-modes/libs/PresentationModePositionStateMachine.js +++ b/packages/starlight-view-modes/libs/PresentationModePositionStateMachine.js @@ -1,84 +1,84 @@ export class PresentationModePositionStateMachine { - constructor(config, presentationModeOff) { - this.config = config; - this.presentationModeOff = presentationModeOff; - } + constructor(config, presentationModeOff) { + this.config = config; + this.presentationModeOff = presentationModeOff; + } - updatePosition() { - this.setDynamicPosition(); + updatePosition() { + this.setDynamicPosition(); - if (!window.matchMedia("(min-width: 50rem)").matches) { - this.setBottomPosition(); - } + if (!window.matchMedia('(min-width: 50rem)').matches) { + this.setBottomPosition(); } + } - setDynamicPosition() { - if ( - this.config.presentationModeCloseButtonPosition === "top-right" || - this.config.presentationModeCloseButtonPosition === "bottom-right" - ) { - this.presentationModeOff?.style.setProperty("right", "1rem"); - this.presentationModeOff?.style.removeProperty("left"); - } else { - this.presentationModeOff?.style.setProperty("left", "1rem"); - this.presentationModeOff?.style.removeProperty("right"); - } + setDynamicPosition() { + if ( + this.config.presentationModeCloseButtonPosition === 'top-right' || + this.config.presentationModeCloseButtonPosition === 'bottom-right' + ) { + this.presentationModeOff?.style.setProperty('right', '1rem'); + this.presentationModeOff?.style.removeProperty('left'); + } else { + this.presentationModeOff?.style.setProperty('left', '1rem'); + this.presentationModeOff?.style.removeProperty('right'); + } - if ( - this.config.presentationModeCloseButtonPosition === "top-right" || - this.config.presentationModeCloseButtonPosition === "top-left" - ) { - this.presentationModeOff?.style.setProperty("top", "1rem"); - this.presentationModeOff?.style.removeProperty("bottom"); - } else { - this.presentationModeOff?.style.setProperty("bottom", "1rem"); - this.presentationModeOff?.style.removeProperty("top"); - } + if ( + this.config.presentationModeCloseButtonPosition === 'top-right' || + this.config.presentationModeCloseButtonPosition === 'top-left' + ) { + this.presentationModeOff?.style.setProperty('top', '1rem'); + this.presentationModeOff?.style.removeProperty('bottom'); + } else { + this.presentationModeOff?.style.setProperty('bottom', '1rem'); + this.presentationModeOff?.style.removeProperty('top'); } + } - setBottomPosition() { - // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung - this.presentationModeOff?.style.setProperty("bottom", "1rem"); - this.presentationModeOff?.style.removeProperty("top"); // Entferne die top-Position, falls vorhanden + setBottomPosition() { + // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung + this.presentationModeOff?.style.setProperty('bottom', '1rem'); + this.presentationModeOff?.style.removeProperty('top'); // Entferne die top-Position, falls vorhanden - // Position links oder rechts wird weiterhin basierend auf der config gesetzt - if ( - this.config.presentationModeCloseButtonPosition === "top-right" || - this.config.presentationModeCloseButtonPosition === "bottom-right" - ) { - this.presentationModeOff?.style.setProperty("right", "1rem"); - this.presentationModeOff?.style.removeProperty("left"); // Entferne die left-Position, falls vorhanden - } else { - this.presentationModeOff?.style.setProperty("left", "1rem"); - this.presentationModeOff?.style.removeProperty("right"); // Entferne die right-Position, falls vorhanden - } + // Position links oder rechts wird weiterhin basierend auf der config gesetzt + if ( + this.config.presentationModeCloseButtonPosition === 'top-right' || + this.config.presentationModeCloseButtonPosition === 'bottom-right' + ) { + this.presentationModeOff?.style.setProperty('right', '1rem'); + this.presentationModeOff?.style.removeProperty('left'); // Entferne die left-Position, falls vorhanden + } else { + this.presentationModeOff?.style.setProperty('left', '1rem'); + this.presentationModeOff?.style.removeProperty('right'); // Entferne die right-Position, falls vorhanden } + } - setRightPosition() { - // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung - this.presentationModeOff?.style.setProperty("right", "1rem"); - this.presentationModeOff?.style.removeProperty("left"); // Entferne die left-Position, falls vorhanden + setRightPosition() { + // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung + this.presentationModeOff?.style.setProperty('right', '1rem'); + this.presentationModeOff?.style.removeProperty('left'); // Entferne die left-Position, falls vorhanden - // Position oben oder unten wird weiterhin basierend auf der config gesetzt - if ( - this.config.presentationModeCloseButtonPosition === "top-right" || - this.config.presentationModeCloseButtonPosition === "top-left" - ) { - this.presentationModeOff?.style.setProperty("top", "1rem"); - this.presentationModeOff?.style.removeProperty("bottom"); // Entferne die bottom-Position, falls vorhanden - } else { - this.presentationModeOff?.style.setProperty("bottom", "1rem"); - this.presentationModeOff?.style.removeProperty("top"); // Entferne die top-Position, falls vorhanden - } + // Position oben oder unten wird weiterhin basierend auf der config gesetzt + if ( + this.config.presentationModeCloseButtonPosition === 'top-right' || + this.config.presentationModeCloseButtonPosition === 'top-left' + ) { + this.presentationModeOff?.style.setProperty('top', '1rem'); + this.presentationModeOff?.style.removeProperty('bottom'); // Entferne die bottom-Position, falls vorhanden + } else { + this.presentationModeOff?.style.setProperty('bottom', '1rem'); + this.presentationModeOff?.style.removeProperty('top'); // Entferne die top-Position, falls vorhanden } + } - setBottomRightPosition() { - // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung - this.presentationModeOff?.style.setProperty("bottom", "1rem"); - this.presentationModeOff?.style.removeProperty("top"); // Entferne die top-Position, falls vorhanden + setBottomRightPosition() { + // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung + this.presentationModeOff?.style.setProperty('bottom', '1rem'); + this.presentationModeOff?.style.removeProperty('top'); // Entferne die top-Position, falls vorhanden - // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung - this.presentationModeOff?.style.setProperty("right", "1rem"); - this.presentationModeOff?.style.removeProperty("left"); // Entferne die left-Position, falls vorhanden - } + // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung + this.presentationModeOff?.style.setProperty('right', '1rem'); + this.presentationModeOff?.style.removeProperty('left'); // Entferne die left-Position, falls vorhanden + } } diff --git a/packages/starlight-view-modes/libs/SharedMethods.js b/packages/starlight-view-modes/libs/SharedMethods.js index 7da4e6d..97f9a3c 100644 --- a/packages/starlight-view-modes/libs/SharedMethods.js +++ b/packages/starlight-view-modes/libs/SharedMethods.js @@ -1,76 +1,96 @@ -import config from "virtual:starlight-view-modes-config"; +import config from 'virtual:starlight-view-modes-config'; + + export function activateZenMode() { - document.body.classList.add("view-modes-zen-mode"); + document.body.classList.add('view-modes-zen-mode'); - const zenModeOnText = document.getElementById("view-modes-zen-mode-on-text"); - if (zenModeOnText) zenModeOnText.innerText = "Deactivate Zen Mode"; + const zenModeOnText = document.getElementById('view-modes-zen-mode-on-text'); + if (zenModeOnText) zenModeOnText.innerText = 'Deactivate Zen Mode'; - const zenModeOffHeader = document.getElementById("view-modes-zen-mode-off-header"); - if (zenModeOffHeader) zenModeOffHeader.title = "Deactivate Zen Mode"; + const zenModeOffHeader = document.getElementById( + 'view-modes-zen-mode-off-header' + ); + if (zenModeOffHeader) zenModeOffHeader.title = 'Deactivate Zen Mode'; - const zenModeOffHeaderMobile = document.getElementById("view-modes-zen-mode-off-header-mobile"); - if (zenModeOffHeaderMobile) zenModeOffHeaderMobile.title = "Deactivate Zen Mode"; + const zenModeOffHeaderMobile = document.getElementById( + 'view-modes-zen-mode-off-header-mobile' + ); + if (zenModeOffHeaderMobile) + zenModeOffHeaderMobile.title = 'Deactivate Zen Mode'; - sessionStorage.setItem("viewModesZenMode", "true"); + sessionStorage.setItem('viewModesZenMode', 'true'); } export function deactivateZenMode() { - document.body.classList.remove("view-modes-zen-mode"); + document.body.classList.remove('view-modes-zen-mode'); - const zenModeOnText = document.getElementById("view-modes-zen-mode-on-text"); - if (zenModeOnText) zenModeOnText.innerText = "Activate Zen Mode"; + const zenModeOnText = document.getElementById('view-modes-zen-mode-on-text'); + if (zenModeOnText) zenModeOnText.innerText = 'Activate Zen Mode'; - const zenModeOffHeader = document.getElementById("view-modes-zen-mode-off-header"); - if (zenModeOffHeader) zenModeOffHeader.title = "Activate Zen Mode"; + const zenModeOffHeader = document.getElementById( + 'view-modes-zen-mode-off-header' + ); + if (zenModeOffHeader) zenModeOffHeader.title = 'Activate Zen Mode'; - const zenModeOffHeaderMobile = document.getElementById("view-modes-zen-mode-off-header-mobile"); - if (zenModeOffHeaderMobile) zenModeOffHeaderMobile.title = "Activate Zen Mode"; + const zenModeOffHeaderMobile = document.getElementById( + 'view-modes-zen-mode-off-header-mobile' + ); + if (zenModeOffHeaderMobile) + zenModeOffHeaderMobile.title = 'Activate Zen Mode'; - sessionStorage.removeItem("viewModesZenMode"); + sessionStorage.removeItem('viewModesZenMode'); } export function activatePresentationMode() { - document.body.classList.add("view-modes-presentation-mode"); - - const presentationModeOnText = document.getElementById("view-modes-presentation-mode-on-text"); - if (presentationModeOnText) presentationModeOnText.innerText = "Deactivate Presentation Mode"; - - const presentationModeOffHeader = document.getElementById( - "view-modes-presentation-mode-off-header" - ); - if (presentationModeOffHeader) presentationModeOffHeader.title = "Deactivate Presentation Mode"; - - const presentationModeOffHeaderMobile = document.getElementById( - "view-modes-presentation-mode-off-header-mobile" - ); - if (presentationModeOffHeaderMobile) - presentationModeOffHeaderMobile.title = "Deactivate Presentation Mode"; - - sessionStorage.setItem("viewModesPresentationMode", "true"); + document.body.classList.add('view-modes-presentation-mode'); + + const presentationModeOnText = document.getElementById( + 'view-modes-presentation-mode-on-text' + ); + if (presentationModeOnText) + presentationModeOnText.innerText = 'Deactivate Presentation Mode'; + + const presentationModeOffHeader = document.getElementById( + 'view-modes-presentation-mode-off-header' + ); + if (presentationModeOffHeader) + presentationModeOffHeader.title = 'Deactivate Presentation Mode'; + + const presentationModeOffHeaderMobile = document.getElementById( + 'view-modes-presentation-mode-off-header-mobile' + ); + if (presentationModeOffHeaderMobile) + presentationModeOffHeaderMobile.title = 'Deactivate Presentation Mode'; + + sessionStorage.setItem('viewModesPresentationMode', 'true'); } export function deactivatePresentationMode() { - document.body.classList.remove("view-modes-presentation-mode"); - - const presentationModeOnText = document.getElementById("view-modes-presentation-mode-on-text"); - if (presentationModeOnText) presentationModeOnText.innerText = "Activate Presentation Mode"; - - const presentationModeOffHeader = document.getElementById( - "view-modes-presentation-mode-off-header" - ); - if (presentationModeOffHeader) presentationModeOffHeader.title = "Activate Presentation Mode"; - - const presentationModeOffHeaderMobile = document.getElementById( - "view-modes-presentation-mode-off-header-mobile" - ); - if (presentationModeOffHeaderMobile) - presentationModeOffHeaderMobile.title = "Activate Presentation Mode"; - - sessionStorage.removeItem("viewModesPresentationMode"); + document.body.classList.remove('view-modes-presentation-mode'); + + const presentationModeOnText = document.getElementById( + 'view-modes-presentation-mode-on-text' + ); + if (presentationModeOnText) + presentationModeOnText.innerText = 'Activate Presentation Mode'; + + const presentationModeOffHeader = document.getElementById( + 'view-modes-presentation-mode-off-header' + ); + if (presentationModeOffHeader) + presentationModeOffHeader.title = 'Activate Presentation Mode'; + + const presentationModeOffHeaderMobile = document.getElementById( + 'view-modes-presentation-mode-off-header-mobile' + ); + if (presentationModeOffHeaderMobile) + presentationModeOffHeaderMobile.title = 'Activate Presentation Mode'; + + sessionStorage.removeItem('viewModesPresentationMode'); } export function deactivateAllModes() { - deactivateZenMode(); - deactivatePresentationMode(); + deactivateZenMode(); + deactivatePresentationMode(); } diff --git a/packages/starlight-view-modes/libs/ZenModePositionStateMachine.js b/packages/starlight-view-modes/libs/ZenModePositionStateMachine.js index fb78cca..f13aca3 100644 --- a/packages/starlight-view-modes/libs/ZenModePositionStateMachine.js +++ b/packages/starlight-view-modes/libs/ZenModePositionStateMachine.js @@ -1,103 +1,106 @@ export class ZenModePositionStateMachine { - constructor(config, zenModeOff) { - this.config = config; - this.zenModeOff = zenModeOff; - } + constructor(config, zenModeOff) { + this.config = config; + this.zenModeOff = zenModeOff; + } - updatePosition() { - if (this.config.zenModeShowHeader === true && this.config.zenModeShowSidebar === false) { - // Wenn Header angezeigt wird, soll der Button immer unten fixiert sein - this.setBottomPosition(); - } else if ( - this.config.zenModeShowHeader === false && - this.config.zenModeShowSidebar === true - ) { - // Wenn Sidebar angezeigt wird, soll der Button immer rechts fixiert sein - this.setRightPosition(); - } else if ( - this.config.zenModeShowHeader === true && - this.config.zenModeShowSidebar === true - ) { - // Wenn Header angezeigt wird, soll der Button immer unten fixiert sein - // Wenn Sidebar angezeigt wird, soll der Button immer rechts fixiert sein - this.setBottomRightPosition(); - } else { - // Ansonsten normale Positionierungslogik basierend auf der Schaltfläche - this.setDynamicPosition(); - } + updatePosition() { + if ( + this.config.zenModeShowHeader === true && + this.config.zenModeShowSidebar === false + ) { + // Wenn Header angezeigt wird, soll der Button immer unten fixiert sein + this.setBottomPosition(); + } else if ( + this.config.zenModeShowHeader === false && + this.config.zenModeShowSidebar === true + ) { + // Wenn Sidebar angezeigt wird, soll der Button immer rechts fixiert sein + this.setRightPosition(); + } else if ( + this.config.zenModeShowHeader === true && + this.config.zenModeShowSidebar === true + ) { + // Wenn Header angezeigt wird, soll der Button immer unten fixiert sein + // Wenn Sidebar angezeigt wird, soll der Button immer rechts fixiert sein + this.setBottomRightPosition(); + } else { + // Ansonsten normale Positionierungslogik basierend auf der Schaltfläche + this.setDynamicPosition(); + } - if (!window.matchMedia("(min-width: 50rem)").matches) { - this.setBottomPosition(); - } + if (!window.matchMedia('(min-width: 50rem)').matches) { + this.setBottomPosition(); } + } - setDynamicPosition() { - if ( - this.config.zenModeCloseButtonPosition === "top-right" || - this.config.zenModeCloseButtonPosition === "bottom-right" - ) { - this.zenModeOff?.style.setProperty("right", "1rem"); - this.zenModeOff?.style.removeProperty("left"); - } else { - this.zenModeOff?.style.setProperty("left", "1rem"); - this.zenModeOff?.style.removeProperty("right"); - } + setDynamicPosition() { + if ( + this.config.zenModeCloseButtonPosition === 'top-right' || + this.config.zenModeCloseButtonPosition === 'bottom-right' + ) { + this.zenModeOff?.style.setProperty('right', '1rem'); + this.zenModeOff?.style.removeProperty('left'); + } else { + this.zenModeOff?.style.setProperty('left', '1rem'); + this.zenModeOff?.style.removeProperty('right'); + } - if ( - this.config.zenModeCloseButtonPosition === "top-right" || - this.config.zenModeCloseButtonPosition === "top-left" - ) { - this.zenModeOff?.style.setProperty("top", "1rem"); - this.zenModeOff?.style.removeProperty("bottom"); - } else { - this.zenModeOff?.style.setProperty("bottom", "1rem"); - this.zenModeOff?.style.removeProperty("top"); - } + if ( + this.config.zenModeCloseButtonPosition === 'top-right' || + this.config.zenModeCloseButtonPosition === 'top-left' + ) { + this.zenModeOff?.style.setProperty('top', '1rem'); + this.zenModeOff?.style.removeProperty('bottom'); + } else { + this.zenModeOff?.style.setProperty('bottom', '1rem'); + this.zenModeOff?.style.removeProperty('top'); } + } - setBottomPosition() { - // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung - this.zenModeOff?.style.setProperty("bottom", "1rem"); - this.zenModeOff?.style.removeProperty("top"); // Entferne die top-Position, falls vorhanden + setBottomPosition() { + // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung + this.zenModeOff?.style.setProperty('bottom', '1rem'); + this.zenModeOff?.style.removeProperty('top'); // Entferne die top-Position, falls vorhanden - // Position links oder rechts wird weiterhin basierend auf der config gesetzt - if ( - this.config.zenModeCloseButtonPosition === "top-right" || - this.config.zenModeCloseButtonPosition === "bottom-right" - ) { - this.zenModeOff?.style.setProperty("right", "1rem"); - this.zenModeOff?.style.removeProperty("left"); // Entferne die left-Position, falls vorhanden - } else { - this.zenModeOff?.style.setProperty("left", "1rem"); - this.zenModeOff?.style.removeProperty("right"); // Entferne die right-Position, falls vorhanden - } + // Position links oder rechts wird weiterhin basierend auf der config gesetzt + if ( + this.config.zenModeCloseButtonPosition === 'top-right' || + this.config.zenModeCloseButtonPosition === 'bottom-right' + ) { + this.zenModeOff?.style.setProperty('right', '1rem'); + this.zenModeOff?.style.removeProperty('left'); // Entferne die left-Position, falls vorhanden + } else { + this.zenModeOff?.style.setProperty('left', '1rem'); + this.zenModeOff?.style.removeProperty('right'); // Entferne die right-Position, falls vorhanden } + } - setRightPosition() { - // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung - this.zenModeOff?.style.setProperty("right", "1rem"); - this.zenModeOff?.style.removeProperty("left"); // Entferne die left-Position, falls vorhanden + setRightPosition() { + // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung + this.zenModeOff?.style.setProperty('right', '1rem'); + this.zenModeOff?.style.removeProperty('left'); // Entferne die left-Position, falls vorhanden - // Position oben oder unten wird weiterhin basierend auf der config gesetzt - if ( - this.config.zenModeCloseButtonPosition === "top-right" || - this.config.zenModeCloseButtonPosition === "top-left" - ) { - this.zenModeOff?.style.setProperty("top", "1rem"); - this.zenModeOff?.style.removeProperty("bottom"); // Entferne die bottom-Position, falls vorhanden - } else { - this.zenModeOff?.style.setProperty("bottom", "1rem"); - this.zenModeOff?.style.removeProperty("top"); // Entferne die top-Position, falls vorhanden - } + // Position oben oder unten wird weiterhin basierend auf der config gesetzt + if ( + this.config.zenModeCloseButtonPosition === 'top-right' || + this.config.zenModeCloseButtonPosition === 'top-left' + ) { + this.zenModeOff?.style.setProperty('top', '1rem'); + this.zenModeOff?.style.removeProperty('bottom'); // Entferne die bottom-Position, falls vorhanden + } else { + this.zenModeOff?.style.setProperty('bottom', '1rem'); + this.zenModeOff?.style.removeProperty('top'); // Entferne die top-Position, falls vorhanden } + } - setBottomRightPosition() { - // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung - this.zenModeOff?.style.setProperty("bottom", "1rem"); - this.zenModeOff?.style.removeProperty("top"); // Entferne die top-Position, falls vorhanden + setBottomRightPosition() { + // Hier wird der Button immer unten fixiert, unabhängig von der top/bottom-Einstellung + this.zenModeOff?.style.setProperty('bottom', '1rem'); + this.zenModeOff?.style.removeProperty('top'); // Entferne die top-Position, falls vorhanden - // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung - this.zenModeOff?.style.setProperty("right", "1rem"); - this.zenModeOff?.style.removeProperty("left"); // Entferne die left-Position, falls vorhanden - } + // Hier wird der Button immer rechts fixiert, unabhängig von der left/right-Einstellung + this.zenModeOff?.style.setProperty('right', '1rem'); + this.zenModeOff?.style.removeProperty('left'); // Entferne die left-Position, falls vorhanden + } } diff --git a/packages/starlight-view-modes/libs/integration.ts b/packages/starlight-view-modes/libs/integration.ts index 5eada6a..8cd7d15 100644 --- a/packages/starlight-view-modes/libs/integration.ts +++ b/packages/starlight-view-modes/libs/integration.ts @@ -1,19 +1,21 @@ -import type { AstroIntegration } from "astro"; +import type { AstroIntegration } from 'astro'; -import type { StarlightViewModesConfig } from ".."; -import { vitePluginStarlightViewModesConfig } from "./vite"; +import type { StarlightViewModesConfig } from '..'; +import { vitePluginStarlightViewModesConfig } from './vite'; -export function starlightViewModesIntegration(config: StarlightViewModesConfig): AstroIntegration { - return { - name: "starlight-view-modes-integration", - hooks: { - "astro:config:setup": ({ updateConfig }) => { - updateConfig({ - vite: { - plugins: [vitePluginStarlightViewModesConfig(config)], - }, - }); - }, - }, - }; +export function starlightViewModesIntegration( + config: StarlightViewModesConfig +): AstroIntegration { + return { + name: 'starlight-view-modes-integration', + hooks: { + 'astro:config:setup': ({ updateConfig }) => { + updateConfig({ + vite: { + plugins: [vitePluginStarlightViewModesConfig(config)], + }, + }); + }, + }, + }; } diff --git a/packages/starlight-view-modes/libs/vite.ts b/packages/starlight-view-modes/libs/vite.ts index 306cf46..a20ef42 100644 --- a/packages/starlight-view-modes/libs/vite.ts +++ b/packages/starlight-view-modes/libs/vite.ts @@ -1,21 +1,49 @@ -import type { ViteUserConfig } from "astro"; - -import type { StarlightViewModesConfig } from ".."; - -export function vitePluginStarlightViewModesConfig(config: StarlightViewModesConfig): VitePlugin { - const moduleId = "virtual:starlight-view-modes-config"; - const resolvedModuleId = `\0${moduleId}`; - const moduleContent = `export default ${JSON.stringify(config)}`; - - return { - name: "vite-plugin-starlight-view-modes-config", - load(id) { - return id === resolvedModuleId ? moduleContent : undefined; - }, - resolveId(id) { - return id === moduleId ? resolvedModuleId : undefined; - }, - }; +import type { ViteUserConfig } from 'astro'; +import { resolve } from 'path'; +import type { StarlightViewModesConfig } from '..'; + +export function vitePluginStarlightViewModesConfig( + config: StarlightViewModesConfig +): VitePlugin { + const moduleId = 'virtual:starlight-view-modes-config'; + const resolvedModuleId = `\0${moduleId}`; + const moduleContent = `export default ${JSON.stringify(config)}`; + + // Path to the utils directory within @astrojs/starlight + const utilsPath = resolve( + process.cwd(), + 'node_modules/@astrojs/starlight/utils' + ); + + return { + name: 'vite-plugin-starlight-view-modes-config', + + load(id) { + if (id === resolvedModuleId) { + return moduleContent; + } + + // Handle the utils path for the virtual import + if (id === 'virtual:starlight/utils') { + return `export * from '${utilsPath}';`; + } + + return undefined; + }, + + resolveId(id) { + if (id === moduleId) { + return resolvedModuleId; + } + + // Resolve the virtual import for utils/navigation + if (id === 'virtual:starlight/utils') { + return id; + } + + return undefined; + }, + }; } -type VitePlugin = NonNullable[number]; +type VitePlugin = NonNullable[number]; diff --git a/packages/starlight-view-modes/overrides/PageSidebar.astro b/packages/starlight-view-modes/overrides/PageSidebar.astro index 110d0d7..f5a0a33 100644 --- a/packages/starlight-view-modes/overrides/PageSidebar.astro +++ b/packages/starlight-view-modes/overrides/PageSidebar.astro @@ -1,15 +1,31 @@ --- import type { Props } from '../props'; - import MobileTableOfContents from 'virtual:starlight/components/MobileTableOfContents'; import TableOfContents from 'virtual:starlight/components/TableOfContents'; import ViewModes from '../components/ViewModes.astro'; import DeactivationButtons from '../components/DeactivationButtons.astro'; import HeaderButtons from '../components/HeaderButtons.astro'; import MobileViewModes from '../components/MobileViewModes.astro'; +import SidebarToggle from '../components/SidebarToggle.astro'; +import { Icon } from 'astro-icon/components'; + + --- + { + + Astro.props.toc && ( <>
@@ -17,8 +33,14 @@ import MobileViewModes from '../components/MobileViewModes.astro';