diff --git a/README.md b/README.md index 65f468c..ff5efce 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ So far, it includes the following examples: 1. 🌐 URL API 1. 🗒️ Selection API 1. 📃 Page Visibility API +1. 💽 Storage API # 🤝 Open Source diff --git a/src/modules/apis/data.ts b/src/modules/apis/data.ts index 195d42b..6b1b85b 100644 --- a/src/modules/apis/data.ts +++ b/src/modules/apis/data.ts @@ -398,6 +398,24 @@ export const data: Array<Demo> = [ apiDocURL: '', canIUseURL: 'https://caniuse.com/pagevisibility', }, + }, + { + id: 'storage', + emoji: '💽', + title: 'Storage API', + description: 'The Storage interface of the Web Storage API provides access to a particular domain\'s session or local storage. It allows, for example, the addition, modification, or deletion of stored data items.', + meta: { + author: { + name: 'Ade Adedoja', + social: { + email: 'damdey@gmail.com', + github: 'ade1705', + twitter: 'TrussDamola', + }, + }, + apiDocURL: '', + canIUseURL: 'https://caniuse.com/storage', + }, }, { id: 'selection-api', diff --git a/src/modules/apis/storage/index.ts b/src/modules/apis/storage/index.ts new file mode 100644 index 0000000..a3b64a3 --- /dev/null +++ b/src/modules/apis/storage/index.ts @@ -0,0 +1,68 @@ +import {StorageType} from "@/modules/demos/storage"; + +export const hasSupport = (): boolean => { + return 'localStorage' in window && 'sessionStorage' in window; +} + +type StorageCallback = (session: StorageType, isSuccessful: boolean) => void; + +const localStorageHandler = { + set(callback: StorageCallback): void { + const localStorageKeyElement = document.getElementById('js-input-local-storage--key') as HTMLInputElement; + const localStorageValueElement = document.getElementById('js-input-local-storage--value') as HTMLInputElement; + try { + localStorage.setItem(localStorageKeyElement.value, localStorageValueElement.value); + localStorageKeyElement.value = ""; + localStorageValueElement.value = ""; + callback(StorageType.LOCAL, true); + } catch (e) { + callback(StorageType.LOCAL, false); + console.error(`Unable to set localStorage ${e}`); + } + }, + get(): Record<string, string> { + return ({...localStorage}); + }, + clear(callback: () => void): void { + try { + localStorage.clear(); + callback(); + } catch (e) { + console.error(`Unable to clear localStorage ${e}`); + } + }, +} + +const sessionStorageHandler = { + set(callback: StorageCallback): void { + const sessionStorageKeyElement = document.getElementById('js-input-session-storage--key') as HTMLInputElement; + const sessionStorageValueElement = document.getElementById('js-input-session-storage--value') as HTMLInputElement; + try { + sessionStorage.setItem(sessionStorageKeyElement.value, sessionStorageValueElement.value); + sessionStorageKeyElement.value = ""; + sessionStorageValueElement.value = ""; + callback(StorageType.SESSION, true); + } catch (e) { + callback(StorageType.SESSION, false); + console.error(`Unable to set sessionStorage ${e}`); + } + }, + get(): Record<string, string> { + return ({...sessionStorage}); + }, + clear(callback: () => void): void { + try { + sessionStorage.clear(); + callback(); + } catch (e) { + console.error(`Unable to clear sessionStorage ${e}`); + } + }, +} + +const run = { + sessionStorageHandler, + localStorageHandler, +}; + +export default run; diff --git a/src/modules/demos/storage/index.tsx b/src/modules/demos/storage/index.tsx new file mode 100644 index 0000000..c42cf62 --- /dev/null +++ b/src/modules/demos/storage/index.tsx @@ -0,0 +1,320 @@ +import run, { hasSupport } from '../../apis/storage'; +import React, {useEffect, useState} from "react"; +import {Input} from "@/components/Input"; +import {Button} from "@/components/Button"; + +export enum StorageType { + LOCAL = 'Local Storage', + SESSION = 'Session Storage', +} + +function Storage() { + const [localStorageData, setLocalStorageData] = useState<Record<string, string>>({}); + const [sessionStorageData, setSessionStorageData] = useState<Record<string, string>>({}); + const [storageType, setStorageType] = useState<StorageType|null>(null); + const [isSuccessful, setIsSuccessful] = useState<boolean|null>(null); + + + const initData = () => { + setLocalStorageData(run.localStorageHandler.get()); + setSessionStorageData(run.sessionStorageHandler.get()); + setStorageType(null); + } + + const callback = (storageType: StorageType, isSuccessful: boolean): void => { + initData(); + setStorageType(storageType); + setIsSuccessful(isSuccessful); + setTimeout(() => setIsSuccessful(null), 2000); + } + + useEffect(() => { + initData(); + }, []); + + if (!hasSupport) { + return <h1>Unsupported</h1>; + } + + return ( + <> + <> + {isSuccessful !== null && ( + <div className="tw-p-4 tw-mb-4 tw-text-sm tw-text-blue-700 tw-bg-blue-100 tw-rounded-lg tw-dark:tw-bg-blue-200 tw-dark:text-blue-800" + role="alert"> + <span className="tw-font-medium">{isSuccessful ? 'Success!' : 'Error'}</span> + {isSuccessful + ? <span> Key/Value pair saved successfully to {storageType}.</span> + : <span> Error saving Key/Value pair</span> + } + </div> + )} + <h2 className="tw-text-xl tw-font-bold tw-mb-3"> + Local Storage + <small + className="tw-underline tw-text-sm tw-ml-2 tw-cursor-pointer" + onClick={() => run.localStorageHandler.clear(initData)} + > + Clear Local Storage + </small> + </h2> + <div className="tw-mb-6"> + <div className="tw-grid tw-grid-cols-3 tw-gap-4"> + <div> + <Input + id="js-input-local-storage--key" + type="text" + name="key" + placeholder="Key" + /> + </div> + <div> + <Input + id="js-input-local-storage--value" + type="text" + name="value" + placeholder="Value" + /> + </div> + <Button onClick={() => run.localStorageHandler.set(callback)}>Save</Button> + </div> + <div + className=" + tw-mt-4 + tw-shadow + tw-overflow-hidden + tw-border-b + tw-border-gray-200 + sm:tw-rounded-lg + " + > + <table + className=" + tw-w-full + tw-min-w-full + tw-divide-y + tw-divide-gray-200 + " + > + <thead className="tw-bg-gray-100"> + <tr> + <th + scope="col" + className=" + tw-px-6 + tw-py-3 + tw-text-left + tw-text-xs + tw-font-medium + tw-text-gray-500 + tw-uppercase + tw-tracking-wider + " + > + Key + </th> + <th + scope="col" + className=" + tw-px-6 + tw-py-3 + tw-text-left + tw-text-xs + tw-font-medium + tw-text-gray-500 + tw-uppercase + tw-tracking-wider + " + > + Value + </th> + </tr> + </thead> + <tbody + className=" + tw-bg-white + tw-divide-y + tw-divide-gray-200 + " + > + {Object.keys(localStorageData).map((key: string, index: number) => { + return ( + <tr key={key + index}> + <td + className=" + tw-px-6 + tw-py-4 + tw-whitespace-nowrap + " + > + <div + className=" + tw-text-sm + tw-text-gray-900 + " + > + {key} + </div> + </td> + <td + className=" + tw-px-6 + tw-py-4 + tw-whitespace-nowrap + " + > + <span + className=" + tw-text-sm + tw-text-gray-900 + " + > + {localStorageData[key]} + </span> + </td> + </tr> + ); + })} + </tbody> + </table> + </div> + </div> + </> + + <> + <h2 className="tw-text-xl tw-font-bold tw-mb-3"> + Session Storage + <small + className="tw-underline tw-text-sm tw-ml-2 tw-cursor-pointer" + onClick={() => run.sessionStorageHandler.clear(initData)} + > + Clear Session Storage + </small> + </h2> + <div className="tw-mb-6"> + <div className="tw-grid tw-grid-cols-3 tw-gap-4"> + <div> + <Input + id="js-input-session-storage--key" + type="text" + name="key" + placeholder="Key" + /> + </div> + <div> + <Input + id="js-input-session-storage--value" + type="text" + name="value" + placeholder="Value" + /> + </div> + <Button onClick={() => run.sessionStorageHandler.set(callback)}>Save</Button> + </div> + <div + className=" + tw-mt-4 + tw-shadow + tw-overflow-hidden + tw-border-b + tw-border-gray-200 + sm:tw-rounded-lg + " + > + <table + className=" + tw-w-full + tw-min-w-full + tw-divide-y + tw-divide-gray-200 + " + > + <thead className="tw-bg-gray-100"> + <tr> + <th + scope="col" + className=" + tw-px-6 + tw-py-3 + tw-text-left + tw-text-xs + tw-font-medium + tw-text-gray-500 + tw-uppercase + tw-tracking-wider + " + > + Key + </th> + <th + scope="col" + className=" + tw-px-6 + tw-py-3 + tw-text-left + tw-text-xs + tw-font-medium + tw-text-gray-500 + tw-uppercase + tw-tracking-wider + " + > + Value + </th> + </tr> + </thead> + <tbody + className=" + tw-bg-white + tw-divide-y + tw-divide-gray-200 + " + > + {Object.keys(sessionStorageData).map((key: string, index: number) => { + return ( + <tr key={key + index}> + <td + className=" + tw-px-6 + tw-py-4 + tw-whitespace-nowrap + " + > + <div + className=" + tw-text-sm + tw-text-gray-900 + " + > + {key} + </div> + </td> + <td + className=" + tw-px-6 + tw-py-4 + tw-whitespace-nowrap + " + > + <span + className=" + tw-text-sm + tw-text-gray-900 + " + > + {sessionStorageData[key]} + </span> + </td> + </tr> + ); + })} + </tbody> + </table> + </div> + </div> + </> + </> + ); +} + +export default Storage;