List items and modal

This commit is contained in:
Max Lynch
2020-12-22 12:37:43 -06:00
parent 49c497670a
commit 9a37a9f7db
80 changed files with 231 additions and 47 deletions
+15
View File
@@ -0,0 +1,15 @@
import classNames from 'classnames';
const Button = ({ children, className, ...props }) => (
<button
{...props}
class={classNames(
'inline-block text-xs font-medium leading-6 text-center uppercase transition rounded-lg ripple focus:outline-none',
className
)}
>
{children}
</button>
);
export default Button;
+7 -4
View File
@@ -1,10 +1,13 @@
import classNames from 'classnames'; import classNames from 'classnames';
const Content = ({ className, visible, children }) => ( const Content = ({ className, visible, children, ...props }) => (
<div className={classNames(`h-full overflow-auto py-2 absolute top-0`, className, { <div
{...props}
className={classNames(`h-full w-full overflow-auto py-2 absolute top-0`, className, {
visible, visible,
invisible: !visible invisible: !visible,
})}> })}
>
{children} {children}
</div> </div>
); );
+3
View File
@@ -0,0 +1,3 @@
const EdgeDrag = () => null;
export default EdgeDrag;
+3
View File
@@ -0,0 +1,3 @@
const List = ({ children, ...props }) => <div {...props}>{children}</div>;
export default List;
+9
View File
@@ -0,0 +1,9 @@
import classNames from 'classnames';
const ListItem = ({ children, className, ...props }) => (
<div className={classNames('p-4', className)} {...props}>
{children}
</div>
);
export default ListItem;
+3 -7
View File
@@ -4,7 +4,7 @@ import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useDrag } from 'react-use-gesture'; import { useDrag } from 'react-use-gesture';
const Menu = ({ open, onClose, children }) => { const Menu = ({ open, onClose, children, className, ...props }) => {
const ref = useRef(); const ref = useRef();
const [x, setX] = useState(-100000); const [x, setX] = useState(-100000);
const [rect, setRect] = useState(null); const [rect, setRect] = useState(null);
@@ -68,6 +68,7 @@ const Menu = ({ open, onClose, children }) => {
return ( return (
<div <div
{...props}
{...bind()} {...bind()}
ref={ref} ref={ref}
style={{ style={{
@@ -78,15 +79,10 @@ const Menu = ({ open, onClose, children }) => {
}} }}
className={classNames( className={classNames(
'fixed z-40 transform transform-gpu translate w-48 h-full bg-gray-100', 'fixed z-40 transform transform-gpu translate w-48 h-full bg-gray-100',
className,
{ {
'transition-transform': !dragging, 'transition-transform': !dragging,
} }
/*
{
'-translate-x-full': !open,
'-translate-x-0': open,
}
*/
)} )}
> >
{children} {children}
+34 -12
View File
@@ -1,5 +1,5 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { useLayoutEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useDrag } from 'react-use-gesture'; import { useDrag } from 'react-use-gesture';
const Modal = ({ open, onClose, children }) => { const Modal = ({ open, onClose, children }) => {
@@ -7,24 +7,46 @@ const Modal = ({ open, onClose, children }) => {
const [dragging, setDragging] = useState(false); const [dragging, setDragging] = useState(false);
const [rect, setRect] = useState(null); const [rect, setRect] = useState(null);
const [y, setY] = useState(100000); const [y, setY] = useState(100000);
const [safeAreaTop, setSafeAreaTop] = useState(0);
const _open = useCallback(() => {
setY(safeAreaTop);
}, [safeAreaTop]);
const _close = useCallback(() => {
if (!rect) {
return;
}
setY(rect.height + safeAreaTop);
}, [safeAreaTop, rect]);
// Get pixel value of safe area insets
useEffect(() => {
const safeAreaTop = parseInt(
getComputedStyle(document.documentElement).getPropertyValue('--safe-area-top')
);
setSafeAreaTop(safeAreaTop);
}, []);
// Get the layout rectangle for the modal
useLayoutEffect(() => { useLayoutEffect(() => {
const rect = ref.current?.getBoundingClientRect(); const rect = ref.current?.getBoundingClientRect();
setRect(rect); setRect(rect);
setY(-rect.width); _close();
}, []); }, []);
// If open changes, open/close the modal
useLayoutEffect(() => { useLayoutEffect(() => {
if (open) { if (open) {
setY(0); _open();
} else if (rect) { } else {
setY(rect.height); _close();
} }
}, [rect, open]); }, [rect, open, _open, _close]);
const bind = useDrag( const bind = useDrag(
({ down, movement: [mx, my] }) => { ({ down, movement: [mx, my] }) => {
setY(my < 0 ? 0 : my); setY(my < 0 ? safeAreaTop : my + safeAreaTop);
if (down) { if (down) {
setDragging(true); setDragging(true);
@@ -32,16 +54,16 @@ const Modal = ({ open, onClose, children }) => {
setDragging(false); setDragging(false);
} }
// If the drag ended, snap the menu back // If the drag ended, snap the menu back open or close it
if (!down) { if (!down) {
const mid = rect.height; const mid = rect.height;
if (y > mid / 2) { if (y > mid / 2) {
// Close // Close
setY(rect.height); _close();
onClose(); onClose();
} else { } else {
// Re-open // Re-open
setY(0); _open();
} }
} }
}, },
@@ -55,13 +77,13 @@ const Modal = ({ open, onClose, children }) => {
ref={ref} ref={ref}
{...bind()} {...bind()}
className={classNames( className={classNames(
'fixed z-40 top-5 transform transform-gpu ranslate w-full h-full bg-white rounded-t-lg', 'fixed z-40 top-5 transform transform-gpu ranslate w-full h-full bg-white rounded-t-xl',
{ {
'ease-in-out duration-300 transition-transformation': !dragging, 'ease-in-out duration-300 transition-transformation': !dragging,
} }
)} )}
style={{ style={{
height: `calc(100% - 1.25rem)`, height: `calc(100% - env(safe-area-inset-top, 0px) - 1.25rem)`,
touchAction: 'pan-y', touchAction: 'pan-y',
transform: `translateY(${y}px)`, transform: `translateY(${y}px)`,
}} }}
+24
View File
@@ -0,0 +1,24 @@
import Content from '../Content';
import { Virtuoso } from 'react-virtuoso';
import List from '../List';
import ListItem from '../ListItem';
const Feed = ({ selected }) => {
return (
<Content visible={selected} className="p-4">
<List className="h-full w-full">
{selected && (
<Virtuoso
totalCount={1000}
overscan={200}
style={{ height: '100%', width: '100%' }}
itemContent={index => <ListItem>Item {index}</ListItem>}
/>
)}
</List>
</Content>
);
};
export default Feed;
-12
View File
@@ -1,12 +0,0 @@
import { homeItems } from "../../data";
import Content from "../Content";
const Profile = ({ selected }) => {
return (
<Content visible={selected} className="p-4">
<h2>Profile</h2>
</Content>
)
}
export default Profile;
+78
View File
@@ -312,6 +312,19 @@
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
}, },
"@virtuoso.dev/react-urx": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@virtuoso.dev/react-urx/-/react-urx-0.2.2.tgz",
"integrity": "sha512-PH2suwXIqFSbAfdkM6COQTRVqKVIC4DWUPPmZVTSWrdPJx6m45rxifAS91a5X3kl9RPaCWD0fBN0ztzWG6BdGQ==",
"requires": {
"@virtuoso.dev/urx": "^0.2.2"
}
},
"@virtuoso.dev/urx": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@virtuoso.dev/urx/-/urx-0.2.2.tgz",
"integrity": "sha512-CbzbWVCtyG2XFSZ+X0K9jNjTpKI+p4dn61ZUM+cpKwCp2HK9jCRWchnOFovqvWqELoGP65TmGNNF06OjCDlk0A=="
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@@ -665,6 +678,11 @@
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
}, },
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"asn1.js": { "asn1.js": {
"version": "5.4.1", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
@@ -1372,6 +1390,11 @@
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
}, },
"core-js": {
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz",
"integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg=="
},
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@@ -3869,6 +3892,11 @@
"sha.js": "^2.4.8" "sha.js": "^2.4.8"
} }
}, },
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"picomatch": { "picomatch": {
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
@@ -4156,6 +4184,14 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
}, },
"promise": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
"integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
"requires": {
"asap": "~2.0.6"
}
},
"promise-inflight": { "promise-inflight": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -4269,6 +4305,14 @@
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
}, },
"raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"requires": {
"performance-now": "^2.1.0"
}
},
"randombytes": { "randombytes": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -4318,6 +4362,19 @@
"object-assign": "^4.1.1" "object-assign": "^4.1.1"
} }
}, },
"react-app-polyfill": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz",
"integrity": "sha512-OfBnObtnGgLGfweORmdZbyEz+3dgVePQBb3zipiaDsMHV1NpWm0rDFYIVXFV/AK+x4VIIfWHhrdMIeoTLyRr2g==",
"requires": {
"core-js": "^3.5.0",
"object-assign": "^4.1.1",
"promise": "^8.0.3",
"raf": "^3.4.1",
"regenerator-runtime": "^0.13.3",
"whatwg-fetch": "^3.0.0"
}
},
"react-dom": { "react-dom": {
"version": "17.0.1", "version": "17.0.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz",
@@ -4354,6 +4411,17 @@
"integrity": "sha512-lpn39vmrDu/zB2bNx7rjaL0+Gjm17a9mzn53bX9IP4TIjMUxXlsB0IkiFj/B23F0vq1A9ozDLGHl2OaXkKJcBg==", "integrity": "sha512-lpn39vmrDu/zB2bNx7rjaL0+Gjm17a9mzn53bX9IP4TIjMUxXlsB0IkiFj/B23F0vq1A9ozDLGHl2OaXkKJcBg==",
"dev": true "dev": true
}, },
"react-virtuoso": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-1.1.1.tgz",
"integrity": "sha512-ljUxZQUdJtMpobTKL1hLHsJJSznAH5bupEuLFKxlA6gVSfayxnldNZyhRVdoZmHqfVvsaNwQETw246uernMdpw==",
"requires": {
"@virtuoso.dev/react-urx": "^0.2.0",
"@virtuoso.dev/urx": "^0.2.0",
"react-app-polyfill": "^1.0.6",
"resize-observer-polyfill": "^1.5.1"
}
},
"readable-stream": { "readable-stream": {
"version": "3.6.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -4423,6 +4491,11 @@
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
}, },
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
},
"resolve": { "resolve": {
"version": "1.19.0", "version": "1.19.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
@@ -5996,6 +6069,11 @@
"source-map": "~0.6.1" "source-map": "~0.6.1"
} }
}, },
"whatwg-fetch": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz",
"integrity": "sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A=="
},
"whatwg-url": { "whatwg-url": {
"version": "7.1.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+1
View File
@@ -18,6 +18,7 @@
"postcss": "^8.2.1", "postcss": "^8.2.1",
"react": "17.0.1", "react": "17.0.1",
"react-dom": "17.0.1", "react-dom": "17.0.1",
"react-virtuoso": "^1.1.1",
"tailwindcss": "^2.0.2" "tailwindcss": "^2.0.2"
}, },
"devDependencies": { "devDependencies": {
+45 -7
View File
@@ -1,4 +1,8 @@
import { useCallback, useState } from 'react'; import { Virtuoso } from 'react-virtuoso';
import { faces } from '../data';
import Store from '../store';
import App from '../components/App'; import App from '../components/App';
import Backdrop from '../components/Backdrop'; import Backdrop from '../components/Backdrop';
@@ -6,20 +10,23 @@ import Menu from '../components/Menu';
import Modal from '../components/Modal'; import Modal from '../components/Modal';
import Nav from '../components/Nav'; import Nav from '../components/Nav';
import Home from '../components/pages/Home'; import Home from '../components/pages/Home';
import Profile from '../components/pages/Profile'; import Feed from '../components/pages/Feed';
import Settings from '../components/pages/Settings'; import Settings from '../components/pages/Settings';
import Tab from '../components/Tab'; import Tab from '../components/Tab';
import TabBar from '../components/TabBar'; import TabBar from '../components/TabBar';
import Store from '../store'; import List from '../components/List';
import ListItem from '../components/ListItem';
import { useState } from 'react';
import Button from '../components/Button';
const pages = [ const pages = [
{ id: 'home', title: 'Home', icon: 'home-outline', selectedIcon: 'home', component: Home }, { id: 'home', title: 'Home', icon: 'home-outline', selectedIcon: 'home', component: Home },
{ {
id: 'profile', id: 'feed',
title: 'Profile', title: 'Feed',
icon: 'person-outline', icon: 'flash-outline',
selectedIcon: 'person', selectedIcon: 'person',
component: Profile, component: Feed,
}, },
{ {
id: 'settings', id: 'settings',
@@ -64,10 +71,41 @@ const MenuContent = () => (
</> </>
); );
const FakeNotification = ({ i }) => (
<ListItem className="flex align-center">
<img
src={`/img/faces/image-${(i % 66) + 1}.png`}
alt="Notification"
className="block rounded-full w-8 h-8 mr-4"
/>
<div className="flex-1">
<span className="p-0 m-0 align-middle">You have a new friend request</span>
</div>
<div>
<Button className="background-transparent px-1 py-1 text-green-400 text-lg">
<ion-icon name="checkmark-outline" />
</Button>
<Button className="background-transparent px-1 py-1 text-red-400 text-lg">
<ion-icon name="close-outline" />
</Button>
</div>
</ListItem>
);
const NotificationsContent = () => ( const NotificationsContent = () => (
<div className="w-full h-full flex flex-col">
<div className="p-4"> <div className="p-4">
<h2 className="text-xl">Notifications</h2> <h2 className="text-xl">Notifications</h2>
</div> </div>
<List className="flex-1">
<Virtuoso
totalCount={1000}
overscan={200}
style={{ height: '100%', width: '100%' }}
itemContent={index => <FakeNotification i={index} />}
/>
</List>
</div>
); );
export default function Index() { export default function Index() {
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+4
View File
@@ -1,3 +1,7 @@
:root {
--safe-area-top: env(safe-area-inset-top, 0);
--safe-area-bottom: env(safe-area-inset-bottom, 0);
}
body { body {
overflow: hidden; overflow: hidden;
height: 100vh; height: 100vh;