init commit
This commit is contained in:
63
shared/components/src/stores/media-query.ts
Normal file
63
shared/components/src/stores/media-query.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
// Based on https://github.com/cibernox/svelte-media
|
||||
import { readable } from 'svelte/store';
|
||||
import { ArtworkConfig } from '@amp/web-app-components/config/components/artwork';
|
||||
import { getMediaConditions } from '@amp/web-app-components/src/utils/getMediaConditions';
|
||||
|
||||
const { BREAKPOINTS } = ArtworkConfig.get();
|
||||
const mqConditions = getMediaConditions(BREAKPOINTS);
|
||||
|
||||
const DEFAULT_SETTING = 'medium';
|
||||
|
||||
/**
|
||||
* Filters media query results and outputs the breakpoint name with a matching media query.
|
||||
*
|
||||
* @param {Object} mqls media query configurations (pulled from getMediaConditions())
|
||||
* @returns {String|undefined} breakpoint string that matches current media query
|
||||
*/
|
||||
function calculateMediaQuery(mqls: Record<string, MediaQueryList>): string {
|
||||
return Object.entries(mqls)
|
||||
.filter(([_, query]) => query.matches)
|
||||
.map(([name, _]) => name)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows to build a store that tracks which of the given media query conditions matches.
|
||||
* @param initialValue The inital value for the store. It only bears importance in server side rendering
|
||||
* as it will update immediately in the browser
|
||||
* @param mediaQueryConditions The dictionary with the media query names and the MQ condition to match against.
|
||||
* @returns Svelte.Store<string> The name of the matching media query
|
||||
*/
|
||||
export function buildMediaQueryStore(
|
||||
initialValue: string,
|
||||
mediaQueryConditions: Record<string, string> = mqConditions,
|
||||
) {
|
||||
return readable(initialValue, (set) => {
|
||||
if (
|
||||
typeof window === 'undefined' ||
|
||||
typeof matchMedia === 'undefined'
|
||||
) {
|
||||
set(initialValue);
|
||||
return;
|
||||
}
|
||||
|
||||
let mqls = {};
|
||||
let updateMediaQuery = () => set(calculateMediaQuery(mqls));
|
||||
|
||||
for (const key in mediaQueryConditions) {
|
||||
mqls[key] = window.matchMedia(mediaQueryConditions[key]);
|
||||
// `addListener` is deprecated but should still be used for compatibility with more browsers.
|
||||
mqls[key].addListener(updateMediaQuery);
|
||||
}
|
||||
|
||||
updateMediaQuery();
|
||||
|
||||
return function (): void {
|
||||
for (let key in mqls) {
|
||||
// `removeListener` is deprecated but should still be used for compatibility with more browsers.
|
||||
mqls[key].removeListener(updateMediaQuery);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export const mediaQueries = buildMediaQueryStore(DEFAULT_SETTING, mqConditions);
|
||||
21
shared/components/src/stores/navigation-folders-open.ts
Normal file
21
shared/components/src/stores/navigation-folders-open.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { type Writable, writable } from 'svelte/store';
|
||||
|
||||
type FolderState = Writable<boolean>;
|
||||
const folderStates = new Map<string, FolderState>();
|
||||
|
||||
export function subscribeFolderOpenState(
|
||||
id: string,
|
||||
defaultState?: boolean,
|
||||
): FolderState {
|
||||
let stateById = folderStates.get(id);
|
||||
if (!stateById) {
|
||||
folderStates.set(id, writable(defaultState ?? false));
|
||||
stateById = folderStates.get(id);
|
||||
}
|
||||
|
||||
return stateById;
|
||||
}
|
||||
|
||||
export function resetFoldersOpenState() {
|
||||
folderStates.clear();
|
||||
}
|
||||
27
shared/components/src/stores/prefers-reduced-motion.ts
Normal file
27
shared/components/src/stores/prefers-reduced-motion.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { readable } from 'svelte/store';
|
||||
|
||||
const DEFAULT_SETTING = false;
|
||||
|
||||
export const prefersReducedMotion = readable(DEFAULT_SETTING, (set) => {
|
||||
if (typeof window === 'undefined' || typeof matchMedia === 'undefined') {
|
||||
set(DEFAULT_SETTING);
|
||||
return;
|
||||
}
|
||||
|
||||
const motionQuery = matchMedia('(prefers-reduced-motion)');
|
||||
|
||||
/* istanbul ignore next */
|
||||
const motionQueryListener = (): void => {
|
||||
set(motionQuery.matches);
|
||||
};
|
||||
|
||||
// `addListener` is deprecated but should still be used for compatibility with more browsers.
|
||||
motionQuery.addListener(motionQueryListener);
|
||||
|
||||
set(motionQuery.matches);
|
||||
|
||||
return function (): void {
|
||||
// `removeListener` is deprecated but should still be used for compatibility with more browsers.
|
||||
motionQuery.removeListener(motionQueryListener);
|
||||
};
|
||||
});
|
||||
12
shared/components/src/stores/sidebar-hidden.ts
Normal file
12
shared/components/src/stores/sidebar-hidden.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { derived } from 'svelte/store';
|
||||
import { buildMediaQueryStore } from '@amp/web-app-components/src/stores/media-query';
|
||||
|
||||
export const sidebarHiddenQuery = buildMediaQueryStore('visible', {
|
||||
hidden: '(max-width: 483px)',
|
||||
visible: '(min-width: 484px)',
|
||||
});
|
||||
|
||||
export const sidebarIsHidden = derived(
|
||||
sidebarHiddenQuery,
|
||||
($sidebarHiddenQuery) => $sidebarHiddenQuery === 'hidden',
|
||||
);
|
||||
Reference in New Issue
Block a user