From 79b09904a6aa96ef4d71082934bdd2f76eec2021 Mon Sep 17 00:00:00 2001 From: Louis Escher <66965600+louisescher@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:56:52 +0100 Subject: [PATCH] Add theme helper, theme toggle component, docs (#377) * Create draft PR for #351 [skip ci] * version and prep docs * Style adjustments to docs * Revert text change * update og images to conform to twitter guidelines * update lockfile * fix lint errors * refactor docs to cleanup the whole thing * remove now unneeded package * update typedoc config * dep cleanup * Refactor Integration.astro to display "N/A" for unreleased packages * update pageTitle to support integrations * add sponsors section * up * Refactor Sponsors.astro to add target and rel attributes to sponsor link * Update sidebar label * Refactor Integration.astro to add support for plugins * add note to styles * update label * Refactor Astro config to add support for @studiocms/blog plugin * fix * Refactor Astro config to remove isScoped and scope properties * Refactor Astro config to remove unused code and improve package name parsing * Refactor Sponsors component styles to center align links and headings * fix icon * Refactor packagecatalog config to remove extra code and improve package name parsing * fix config reference * Refactor PackageCatalog component to filter and sort packages based on pkgType prop * Refactor PackageCatalog component to use 'catalog' prop instead of 'pkgType' * Refactor Astro.props in Integration.astro to include publiclyUsable prop * Refactor config.ts to include redirectSchema * refactor * Refactor Astro.config.mts to include @shikijs/twoslash integration * Refactor Astro.config.mts to use StudioCMSOptions instead of StudioCMSOptionsSchema._input * Dashboard additions removals (#354) * Purge mentions of Astro Studio * Add UI docs (getting started & button) * Update packages/studiocms/src/index.ts Co-authored-by: Adam Matthiesen * Fix border rounding * Shrink hero * Update www/docs/astro.config.mts Co-authored-by: Adam Matthiesen * Finish button docs, fix merge conflicts * Add more UI lib docs, adjust UI package - Fixed a typo that caused a typedoc warning. -Fixed a CSS leak in the UI library. - Adjusted the DropdownHelper API (added an individual show toggle and renamed some functions) - Looooooooooots more docs stuff * Update button.mdx * Adjust wording * Update dropdown.mdx * Add more UI docs, fix UI lib css * Adjust sponsors css, add more UI lib docs * Improve code snippets * Document textarea, toggle, and user * Changes to UI lib, new UI lib docs * Fix missing comma * Update custom.css * mention include styles * Adjustments for twoslash * Update custom.css * Twoslash more like twobitch * Funny markdown support :) * Made twoslash appear correctly * Add changesets * Add explicitTrigger for twoslash --------- Co-authored-by: Reuben Tier Co-authored-by: Adam Matthiesen * start of adding transformers and their css * more twoslash! * Update '@astrojs/starlight' version to 0.28.3 * Update dependencies for '@astrojs/starlight', '@astrojs/db', '@astrojs/node', '@astrojs/react', and '@astrojs/web-vitals' * test * apply fix * update docs and re-enable astro check * Update configuration.mdx with link to reference pages * Add description for StudioCMS DevApps * Refactor StudioCMS package.json exports * more progress * Update Astro version to 4.16.3 and adjust button position in custom.css * update default bracketPairs comment * update to conform to new astro docs and update other links * add ts-nocheck to prevent warnings/errors for shiki transformer * revert * new title transformer for shiki * add titles * cleanup * update demo link in code snippet * Update custom.css styles for code snippets * Update studiocms/src/index.ts and www/docs/src/content/docs/config-reference/options-schema.mdx * Refactor import statement in defineStudioCMSConfig.ts * fix the TS error that was being caused by a `.` instead of a `,` * some css styling for the copy button * update css * Update custom.css with new color tokens and styling for highlighted words and diffs * remove spacing * Update custom.css to add background color for highlighted words and diffs * Update custom.css to adjust background colors for highlighted words and diffs * fixed css * Update custom.css to remove inline-block display for diff spans * Remove test comment, fix copy SVGs, color changes * Add image zoom, remove carousel, adjust hero buttons * refactor css file into multiple files * Refactor shiki transformers and update import paths * Refactor Docs landing page * Refactor SplitCard component CSS * Refactor Youtube.astro component CSS * Refactor why-studioCMS.mdx file * Refactor card CSS to include all the cards from starlight * Refactor index.mdx to include instructions for setting up Turso database * Refactor Getting started guide and remove unused components * Refactor getting started guide * Refactor config references * Refactor config references and add Renderer type * Refactor StudioCMS custom renderer documentation to include information about defining custom renderers and their usage. * cleanup docs * Refactor environment variable documentation and add ReadMore component * Refactor YouTube and landing card components * Refactor Discord button styling in index.mdx and starlight.css * Refactor starlight.css: Add gap to LinkButton button styling * fix * Refactor SplitCard component: Add padding to split container * Refactor SplitCard component: Remove unnecessary padding in split container * Refactor landing page: Update StudioCMS card icon * Custom head component to preload the fonts * Add new component for planned Contributor guide page * Update sidebar component name, and update SiteTitle component * Update astro.config.mts: Add 'x.com' link to StudioCMS social media * Contributing guide! * Update astro.config.mts: Add remotePatterns for images Add new Contributing guide * Update FacePile component: Adjust avatar size and alignment * Update contributing guide * Update contributing guide: Add link to contributing guide in README.md * Update astro.config.mts: Add badge to @studiocms/ui label * Update contributing guide: Update link to contributors list in contributing.mdx * Update dependencies: Add hast-util-to-string, html-escaper, rehype-slug, rehype-autolink-headings, rehype-external-links, and @types/html-escaper * Update anchor link icon style * Update anchor link icon style and display of content elements * Update dependencies: Add shiki-transformer-color-highlight and unified * Update contributor list component and styles * Refactor getContributorsByPath function to remove ignored commit keywords and improve author handling * cleanup * Update external link icon and remove underline from anchor links * Update SiteTitle.astro * Add bun as a package manager option * Refactor getContributorsByPath function to improve author handling and remove ignored commit keywords * Refactor TursoCLI command builder for improved handling of authentication and database commands * Refactor to use dynamic sponsor links * Update strings.ts * Update why-studioCMS.mdx * Feat(devapps): Wordpress Importer (#360) * initial progress * okay well it works! * Add Wordpress importer app * Add WordPress Importer app and update README.md * update readme * update docs * Add Toolbar app image and update README.md * remove unnecessary footnote * Refactor wp-api converters and utils This commit refactors the wp-api converters and utils in the studiocms_devapps package. It introduces the following changes: - Added async/await functionality to ConvertToPageData and ConvertToPostData functions. - Implemented fetching and downloading of title images for pages and posts. - Updated the apiEndpoint function to include the 'media' type. These changes improve the efficiency and functionality of the wp-api converters and utils. * Refactor wp-api converters and utils, and add closeOnOutsideClick function * Refactor createWindowElement function and add closeOnOutsideClick function * Refactor TypeDoc configuration to include additional files * Refactor devApps configuration to include WP API Importer * typo * Refactor wp-api converters and utils, and fix success check in wp-importer * Refactor to remove warning as per @dreyfus92 * Update www/docs/src/content/docs/start-here/why-studioCMS.mdx Co-authored-by: Adam Matthiesen * Update www/docs/src/content/docs/start-here/why-studioCMS.mdx Co-authored-by: Adam Matthiesen * Update www/docs/src/content/docs/start-here/why-studioCMS.mdx Co-authored-by: Adam Matthiesen * Update www/docs/src/content/docs/start-here/why-studioCMS.mdx Co-authored-by: Adam Matthiesen * Update title in how-it-works/index.mdx * Fix twoslash popups overflowing parent container * Add theme helper, theme toggle component, docs * Remove unused function call * Update index.ts * Fix a typo in the JSDoc * Update theme-helper.mdx Added an example for how to store the theme * Update theme-helper.mdx --------- Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com> Co-authored-by: Adam Matthiesen Co-authored-by: Reuben Tier --- .changeset/sharp-zoos-tickle.md | 5 + .../src/schemas/config/index.ts | 1 - packages/studiocms_ui/src/components.ts | 1 + .../src/components/ThemeToggle.astro | 40 ++++++ packages/studiocms_ui/src/components/index.ts | 1 + .../studiocms_ui/src/utils/ThemeHelper.ts | 127 ++++++++++++++++++ pnpm-lock.yaml | 2 +- .../src/components/ThemeHelperScript.astro | 11 ++ www/docs/src/components/Youtube.astro | 16 +-- .../studiocms-ui/components/theme-helper.mdx | 113 ++++++++++++++++ .../studiocms-ui/components/theme-toggle.mdx | 55 ++++++++ www/web/package.json | 1 - 12 files changed, 362 insertions(+), 11 deletions(-) create mode 100644 .changeset/sharp-zoos-tickle.md create mode 100644 packages/studiocms_ui/src/components/ThemeToggle.astro create mode 100644 packages/studiocms_ui/src/utils/ThemeHelper.ts create mode 100644 www/docs/src/components/ThemeHelperScript.astro create mode 100644 www/docs/src/content/docs/customizing/studiocms-ui/components/theme-helper.mdx create mode 100644 www/docs/src/content/docs/customizing/studiocms-ui/components/theme-toggle.mdx diff --git a/.changeset/sharp-zoos-tickle.md b/.changeset/sharp-zoos-tickle.md new file mode 100644 index 000000000..7f1811374 --- /dev/null +++ b/.changeset/sharp-zoos-tickle.md @@ -0,0 +1,5 @@ +--- +"@studiocms/ui": patch +--- + +Added a theme helper and theme toggle component diff --git a/packages/studiocms_core/src/schemas/config/index.ts b/packages/studiocms_core/src/schemas/config/index.ts index fc7933e7a..d689ec5e5 100644 --- a/packages/studiocms_core/src/schemas/config/index.ts +++ b/packages/studiocms_core/src/schemas/config/index.ts @@ -75,5 +75,4 @@ export const StudioCMSOptionsSchema = z .default({}); export type StudioCMSOptions = typeof StudioCMSOptionsSchema._input; - export type StudioCMSConfig = typeof StudioCMSOptionsSchema._output; diff --git a/packages/studiocms_ui/src/components.ts b/packages/studiocms_ui/src/components.ts index e4ae92774..09998d4fc 100644 --- a/packages/studiocms_ui/src/components.ts +++ b/packages/studiocms_ui/src/components.ts @@ -14,6 +14,7 @@ export { Select } from './components/index'; export { SearchSelect } from './components/index'; export { Dropdown, DropdownHelper } from './components/index'; export { User } from './components/index'; +export { ThemeToggle } from './components/index'; export { Sidebar, diff --git a/packages/studiocms_ui/src/components/ThemeToggle.astro b/packages/studiocms_ui/src/components/ThemeToggle.astro new file mode 100644 index 000000000..bc6472b5c --- /dev/null +++ b/packages/studiocms_ui/src/components/ThemeToggle.astro @@ -0,0 +1,40 @@ +--- +import type { ComponentProps } from "astro/types"; +import Button from "./Button.astro"; + +interface Props extends ComponentProps {}; + +const props = Astro.props; +--- + + + + + + diff --git a/packages/studiocms_ui/src/components/index.ts b/packages/studiocms_ui/src/components/index.ts index 072e5be65..46bf1c7e1 100644 --- a/packages/studiocms_ui/src/components/index.ts +++ b/packages/studiocms_ui/src/components/index.ts @@ -14,6 +14,7 @@ export { default as Select } from "./Select.astro"; export { default as SearchSelect } from "./SearchSelect.astro"; export { default as Dropdown } from "./Dropdown/Dropdown.astro"; export { default as User } from "./User.astro"; +export { default as ThemeToggle } from './ThemeToggle.astro'; export { default as Sidebar } from "./Sidebar/Single.astro"; export { default as DoubleSidebar } from "./Sidebar/Double.astro"; diff --git a/packages/studiocms_ui/src/utils/ThemeHelper.ts b/packages/studiocms_ui/src/utils/ThemeHelper.ts new file mode 100644 index 000000000..ffffb794f --- /dev/null +++ b/packages/studiocms_ui/src/utils/ThemeHelper.ts @@ -0,0 +1,127 @@ +type Theme = 'dark' | 'light' | 'system'; +type ThemeChangeCallback = (newTheme: Theme, oldTheme: Theme) => void; + +/** + * A helper to toggle, set and get the current StudioCMS UI theme. + */ +class ThemeHelper { + private themeManagerElement: HTMLElement; + private observer: MutationObserver | undefined; + private themeChangeCallbacks: ThemeChangeCallback[] = []; + + /** + * A helper to toggle, set and get the current StudioCMS UI theme. + * @param themeProvider The element that should carry the data-theme attribute (replaces the document root) + */ + constructor(themeProvider?: HTMLElement) { + this.themeManagerElement = themeProvider || document.documentElement; + } + + /** + * Get the current theme. + * @param {boolean} resolveSystemTheme Whether to resolve the `system` theme to the actual theme (`dark` or `light`) + * @returns {Theme} The current theme. + */ + public getTheme = (resolveSystemTheme?: T): T extends true ? 'dark' | 'light' : Theme => { + const theme = this.themeManagerElement.dataset.theme as Theme || 'system'; + + if (!resolveSystemTheme) { + // Side note: Don't ask me why this type wizardry is needed but it gives proper return types so I don't care + return theme as T extends true ? 'dark' | 'light' : Theme; + } + + if (this.themeManagerElement.dataset.theme !== 'system') { + return this.themeManagerElement.dataset.theme as 'dark' | 'light'; + } + + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark'; + } + + if (window.matchMedia('(prefers-color-scheme: light)').matches) { + return 'light'; + } + + // This should (in theory) never happen since, at time of writing, window.matchMedia is supported + // by 96.83% of all browsers in use. (https://caniuse.com/mdn-api_window_matchmedia) + throw new Error('Unable to resolve theme. (Most likely cause: window.matchMedia is not supported by the browser)'); + }; + + /** + * Sets the current theme. + * @param theme The new theme. One of `dark`, `light` or `system`. + */ + public setTheme = (theme: Theme): void => { + this.themeManagerElement.dataset.theme = theme; + }; + + /** + * Toggles the current theme. + * + * If the theme is set to `system` (or no theme is set via the root element), + * the theme is set depending on the user's color scheme preference (set in the browser). + */ + public toggleTheme = (): void => { + const theme = this.getTheme(); + + if (theme === 'dark') { + this.setTheme('light'); + return; + } + + if (theme === 'light') { + this.setTheme('dark'); + return; + } + + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + this.setTheme('light'); + return; + } + + if (window.matchMedia('(prefers-color-scheme: light)').matches) { + this.setTheme('dark'); + return; + } + }; + + /** + * Register an element to act as a toggle! When clicked, it will toggle the theme. + * @param toggle The HTML element that should act as the toggle + */ + public registerToggle = (toggle: HTMLElement | null): void => { + if (!toggle) { + console.error('Element passed to toggle registration does not exist.'); + return; + }; + + toggle.addEventListener('click', this.toggleTheme); + }; + + /** + * Allows for adding a callback that gets called whenever the theme changes, + * @param callback The callback to be executed + */ + public onThemeChange = (callback: ThemeChangeCallback): void => { + if (!this.observer) { + this.observer = new MutationObserver(this.themeManagerMutationHandler); + this.observer.observe(this.themeManagerElement, { attributes: true, attributeOldValue: true, attributeFilter: ['data-theme'] }); + } + + this.themeChangeCallbacks.push(callback); + }; + + /** + * Simply gets the first mutation and calls all registered callbacks. + * @param mutations The mutations array from the observer. Due to the specified options, this will always be a 1-length array, + */ + private themeManagerMutationHandler = (mutations: MutationRecord[]): void => { + if (!mutations[0]) return; + + for (const callback of this.themeChangeCallbacks) { + callback(this.getTheme(), mutations[0].oldValue as Theme || 'system'); + } + }; +} + +export { ThemeHelper, type Theme }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed25aba40..1fe3f2010 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12179,4 +12179,4 @@ snapshots: zod@3.23.8: {} - zwitch@2.0.4: {} + zwitch@2.0.4: {} \ No newline at end of file diff --git a/www/docs/src/components/ThemeHelperScript.astro b/www/docs/src/components/ThemeHelperScript.astro new file mode 100644 index 000000000..dde1575bc --- /dev/null +++ b/www/docs/src/components/ThemeHelperScript.astro @@ -0,0 +1,11 @@ + diff --git a/www/docs/src/components/Youtube.astro b/www/docs/src/components/Youtube.astro index 6e16aaca6..ea35f9614 100644 --- a/www/docs/src/components/Youtube.astro +++ b/www/docs/src/components/Youtube.astro @@ -1,12 +1,12 @@ --- -import { YouTube } from 'astro-embed'; - -interface Props { - id: string; - title?: string; -} - -const { id, title } = Astro.props; +import { YouTube } from 'astro-embed'; + +interface Props { + id: string; + title?: string; +} + +const { id, title } = Astro.props; --- diff --git a/www/docs/src/content/docs/customizing/studiocms-ui/components/theme-helper.mdx b/www/docs/src/content/docs/customizing/studiocms-ui/components/theme-helper.mdx new file mode 100644 index 000000000..c310ef553 --- /dev/null +++ b/www/docs/src/content/docs/customizing/studiocms-ui/components/theme-helper.mdx @@ -0,0 +1,113 @@ +--- +title: Theme Helper +--- +import { Tabs, TabItem } from '@astrojs/starlight/components'; +import PreviewCard from '~/components/PreviewCard.astro'; +import ThemeHelperScript from '~/components/ThemeHelperScript.astro'; + +To make managing the active theme easier, we provide a helper class to get, set and toggle the theme. Additionally, +you can provide callbacks for when the theme gets changed! + +## Usage + +:::caution +The `ThemeHelper` can only be used client-side (in `