mirror of
https://github.com/BradNut/react-hooks-library
synced 2025-09-08 17:40:20 +00:00
Added local storage, script, and theme hooks.
This commit is contained in:
parent
5cab62fd7e
commit
43a73aae8a
12 changed files with 157 additions and 7 deletions
|
|
@ -4,4 +4,6 @@
|
||||||
--blue: #4f8cdd;
|
--blue: #4f8cdd;
|
||||||
--black: #3b2c41;
|
--black: #3b2c41;
|
||||||
--green: #a3ffc1;
|
--green: #a3ffc1;
|
||||||
|
--bg: #fff;
|
||||||
|
--text: #333;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ import Inc from './components/Inc';
|
||||||
import Mount from './components/Mount';
|
import Mount from './components/Mount';
|
||||||
import Hover from './components/Hover';
|
import Hover from './components/Hover';
|
||||||
import Cookie from "./components/Cookie";
|
import Cookie from "./components/Cookie";
|
||||||
|
import Script from './components/Script';
|
||||||
|
import Local from './components/Local';
|
||||||
|
import Theme from './components/Theme';
|
||||||
import { PageWrapper } from "./state";
|
import { PageWrapper } from "./state";
|
||||||
import Nav from "./components/Nav";
|
import Nav from "./components/Nav";
|
||||||
import Menu from "./Menu";
|
import Menu from "./Menu";
|
||||||
|
|
@ -25,10 +28,13 @@ function App() {
|
||||||
<Nav />
|
<Nav />
|
||||||
<Container>
|
<Container>
|
||||||
<h2>Super Cool</h2>
|
<h2>Super Cool</h2>
|
||||||
|
<Theme />
|
||||||
|
<Script />
|
||||||
<Toggle />
|
<Toggle />
|
||||||
<Inc />
|
<Inc />
|
||||||
<Mount />
|
<Mount />
|
||||||
<Cookie />
|
<Cookie />
|
||||||
|
<Local />
|
||||||
<Hover />
|
<Hover />
|
||||||
|
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ export const Container = styled.div`
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-bottom: 60px;
|
padding-bottom: 60px;
|
||||||
|
color: var(--text);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CardGrid = styled.div`
|
export const CardGrid = styled.div`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import React from 'react';
|
|
||||||
import { Card } from '../Elements';
|
import { Card } from '../Elements';
|
||||||
import black from "../black.png"
|
import black from "../black.png"
|
||||||
import { useHover, useWindowWidth, useMeasure } from '../hooks';
|
import { useHover, useWindowWidth, useMeasure } from '../hooks';
|
||||||
|
|
@ -6,15 +5,15 @@ import { useHover, useWindowWidth, useMeasure } from '../hooks';
|
||||||
export const Hover = () => {
|
export const Hover = () => {
|
||||||
const [ isHovered, bind ] = useHover();
|
const [ isHovered, bind ] = useHover();
|
||||||
const width = useWindowWidth();
|
const width = useWindowWidth();
|
||||||
const [{ref}, bounds] = useMeasure();
|
// const [{ref}, bounds] = useMeasure();
|
||||||
console.log('bounds', bounds);
|
// console.log('bounds', bounds);
|
||||||
|
|
||||||
if (width < 500) return null;
|
if (width < 500) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Card
|
<Card
|
||||||
ref={ref}
|
// ref={ref}
|
||||||
{...bind}
|
{...bind}
|
||||||
style={{ background: isHovered ? "var(--purp)" : "var(--black)" }}
|
style={{ background: isHovered ? "var(--purp)" : "var(--black)" }}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
14
src/components/Local.js
Normal file
14
src/components/Local.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { useLocalStorage } from "../hooks";
|
||||||
|
|
||||||
|
const Local = () => {
|
||||||
|
const [ value, setValue ] = useLocalStorage("tester", "I am initial");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>{value || ''}</h1>
|
||||||
|
<input type="text" value={value} onChange={(e) => setValue(e.target.value)} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Local;
|
||||||
15
src/components/Script.js
Normal file
15
src/components/Script.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { useScript } from "../hooks"
|
||||||
|
|
||||||
|
const Script = () => {
|
||||||
|
const [ isLoaded, isError ] = useScript('https://www.google.com/recaptcha/api.js');
|
||||||
|
console.log('isLoaded, isError', isLoaded, isError);
|
||||||
|
if (!isLoaded) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Script</h3>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Script;
|
||||||
16
src/components/Theme.js
Normal file
16
src/components/Theme.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { useTheme } from "../hooks";
|
||||||
|
|
||||||
|
const Theme = () => {
|
||||||
|
const [theme, setTheme] = useTheme();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<select name="" id="" defaultValue={theme}
|
||||||
|
onChange={(e) => setTheme(e.target.value)}>
|
||||||
|
<option value="light">Light</option>
|
||||||
|
<option value="dark">Dark</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Theme;
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
export * from './useCookie';
|
export * from './useCookie';
|
||||||
export * from './useHover';
|
export * from './useHover';
|
||||||
export * from './useInc';
|
export * from './useInc';
|
||||||
|
export * from './useLocalStorage';
|
||||||
export * from './useMeasure';
|
export * from './useMeasure';
|
||||||
export * from './useMount';
|
export * from './useMount';
|
||||||
export * from './useScrollFreeze';
|
export * from './useScrollFreeze';
|
||||||
|
export * from './useScript';
|
||||||
|
export * from './useTheme';
|
||||||
export * from './useToggle';
|
export * from './useToggle';
|
||||||
export * from './useWindowWidth';
|
export * from './useWindowWidth';
|
||||||
|
|
|
||||||
12
src/hooks/useLocalStorage.js
Normal file
12
src/hooks/useLocalStorage.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
export const useLocalStorage = (key, initial) => {
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
const [ value, setValue ] = useState(item || initial);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.localStorage.setItem(key, value);
|
||||||
|
}, [value, key, initial]);
|
||||||
|
|
||||||
|
return [ value, setValue ];
|
||||||
|
};
|
||||||
59
src/hooks/useScript.js
Normal file
59
src/hooks/useScript.js
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
let cached = [];
|
||||||
|
|
||||||
|
export const useScript = (src) => {
|
||||||
|
const [ status, setStatus ] = useState({
|
||||||
|
loaded: false,
|
||||||
|
error: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (cached.includes(src)) {
|
||||||
|
setStatus({
|
||||||
|
loaded: true,
|
||||||
|
error: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cached.push(src);
|
||||||
|
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = src;
|
||||||
|
script.async = true;
|
||||||
|
|
||||||
|
const onLoad = () => {
|
||||||
|
setStatus({
|
||||||
|
loaded: true,
|
||||||
|
error: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const onError = () => {
|
||||||
|
const i = cached.indexOf(src);
|
||||||
|
if (i >= 0) {
|
||||||
|
cached.splice(i, 1);
|
||||||
|
}
|
||||||
|
// cached = cached.filter(item => item !== src);
|
||||||
|
|
||||||
|
script.remove();
|
||||||
|
|
||||||
|
setStatus({
|
||||||
|
loaded: true,
|
||||||
|
error: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
script.addEventListener('load', onLoad);
|
||||||
|
script.addEventListener('error', onError);
|
||||||
|
|
||||||
|
document.body.appendChild(script);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
script.removeEventListener('load', onLoad);
|
||||||
|
script.removeEventListener('error', onError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [src]);
|
||||||
|
|
||||||
|
return [ status.loaded, status.error ];
|
||||||
|
}
|
||||||
14
src/hooks/useTheme.js
Normal file
14
src/hooks/useTheme.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useLocalStorage } from './useLocalStorage';
|
||||||
|
|
||||||
|
export const useTheme = () => {
|
||||||
|
const [theme, setTheme] = useLocalStorage('theme', 'light');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Removing all class names on body before setting, could keep and only remove what we want
|
||||||
|
document.body.className = "";
|
||||||
|
document.body.classList.add(theme);
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
return [theme, setTheme];
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,22 @@
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark {
|
||||||
|
--bg: #333;
|
||||||
|
--text: #fff;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue