diff --git a/source/content-scripts/scss/components/theme-cycler.scss b/source/content-scripts/scss/components/theme-cycler.scss new file mode 100644 index 0000000..408c985 --- /dev/null +++ b/source/content-scripts/scss/components/theme-cycler.scss @@ -0,0 +1,12 @@ +.tish-theme-cycler { + align-items: center; + border: 1px solid var(--button-color); + display: flex; + gap: 4px; + margin-bottom: 0.4rem; + padding: 4px; + + p { + margin: 0; + } +} diff --git a/source/content-scripts/scss/main.scss b/source/content-scripts/scss/main.scss index 2aa5408..e10dc72 100644 --- a/source/content-scripts/scss/main.scss +++ b/source/content-scripts/scss/main.scss @@ -1,5 +1,6 @@ @use "shepherd-defaults"; @use "shepherd-custom"; +@use "components/theme-cycler"; [data-tildes-shepherd-counter] { position: relative; diff --git a/source/tours/components/exports.ts b/source/tours/components/exports.ts new file mode 100644 index 0000000..fd21f26 --- /dev/null +++ b/source/tours/components/exports.ts @@ -0,0 +1 @@ +export * from "./theme-cycler.js"; diff --git a/source/tours/components/theme-cycler.tsx b/source/tours/components/theme-cycler.tsx new file mode 100644 index 0000000..50c384a --- /dev/null +++ b/source/tours/components/theme-cycler.tsx @@ -0,0 +1,115 @@ +import {Component} from "preact"; + +type Props = Record; + +type State = { + delayIndex: number; + intervalId: number | undefined; +}; + +export class ThemeCycler extends Component { + delayValues: number[] = [100, 250, 500, 1000, 2500, 5000, 10_000]; + + constructor(props: Props) { + super(props); + + this.state = { + delayIndex: 4, + intervalId: undefined, + }; + } + + cycle = () => { + const themeSelect = + document.querySelector("#theme") ?? undefined; + if (themeSelect === undefined) { + return; + } + + const themeOptions = Array.from(themeSelect.options); + const nextIndex = themeOptions.findIndex((option) => option.selected) + 1; + + themeSelect.selectedIndex = + // If the next option can't be found, we're at the end so start back at zero. + themeOptions[nextIndex] === undefined ? 0 : nextIndex; + + // Emit a change event so the Tildes JS handles changing the theme. + themeSelect.dispatchEvent(new Event("change")); + }; + + decreaseDelay = () => { + const {delayIndex, intervalId} = this.state; + if (delayIndex <= 0) { + return; + } + + this.setState({delayIndex: delayIndex - 1}, () => { + if (intervalId !== undefined) { + this.startInterval(); + } + }); + }; + + increaseDelay = () => { + const {delayIndex, intervalId} = this.state; + if (delayIndex >= this.delayValues.length - 1) { + return; + } + + this.setState({delayIndex: delayIndex + 1}, () => { + if (intervalId !== undefined) { + this.startInterval(); + } + }); + }; + + startInterval = () => { + const {delayIndex, intervalId} = this.state; + if (intervalId !== undefined) { + window.clearInterval(intervalId); + } + + this.setState({ + intervalId: window.setInterval(this.cycle, this.delayValues[delayIndex]), + }); + }; + + toggle = () => { + const {intervalId} = this.state; + if (intervalId === undefined) { + this.startInterval(); + this.cycle(); + } else { + window.clearInterval(intervalId); + this.setState({intervalId: undefined}); + } + }; + + render() { + const isEnabled = this.state.intervalId !== undefined; + const delay = this.delayValues[this.state.delayIndex]; + + return ( +
+

Theme Cycler ({delay / 1000}s)

+ + + +
+ ); + } +}