Merge branch 'sidebar' into 'main'

Improve info sidebar

See merge request sc07/canvas!14
This commit is contained in:
Grant 2024-07-13 23:53:58 +00:00
commit 184492358c
11 changed files with 226 additions and 137 deletions

28
package-lock.json generated
View File

@ -2393,6 +2393,7 @@
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"peer": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
@ -2401,7 +2402,8 @@
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
"optional": true,
"peer": true
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
@ -3050,6 +3052,14 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw=="
},
"node_modules/@icons-pack/react-simple-icons": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/@icons-pack/react-simple-icons/-/react-simple-icons-9.6.0.tgz",
"integrity": "sha512-8lDLssg+2aJutepQV/P4zlGm0fgujSeIItCYaLKo+25NtwepozWxZJOnc5WGHSi3HjiLcGmxI6dA2eiD5w3i+w==",
"peerDependencies": {
"react": "^16.13 || ^17 || ^18"
}
},
"node_modules/@internationalized/date": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.5.2.tgz",
@ -9747,20 +9757,21 @@
}
},
"node_modules/framer-motion": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.5.tgz",
"integrity": "sha512-Lb0EYbQcSK/pgyQUJm+KzsQrKrJRX9sFRyzl9hSr9gFG4Mk8yP7BjhuxvRXzblOM/+JxycrJdCDVmOQBsjpYlw==",
"version": "11.3.2",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.3.2.tgz",
"integrity": "sha512-RgjSzrNFZmedWcvmW4MMc84A7UcoY37jocadE3Mbg3o+UMofodfyeNnYD/HR15UhP22/bb5KOebNhYOj4mYkpQ==",
"dependencies": {
"tslib": "^2.4.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
@ -16247,11 +16258,12 @@
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@icons-pack/react-simple-icons": "^9.6.0",
"@nextui-org/react": "^2.2.9",
"@sc07-canvas/lib": "^1.0.0",
"@typescript-eslint/parser": "^7.1.0",
"eventemitter3": "^5.0.1",
"framer-motion": "^11.0.5",
"framer-motion": "^11.3.2",
"lodash.throttle": "^4.1.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",

View File

@ -24,11 +24,12 @@
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@icons-pack/react-simple-icons": "^9.6.0",
"@nextui-org/react": "^2.2.9",
"@sc07-canvas/lib": "^1.0.0",
"@typescript-eslint/parser": "^7.1.0",
"eventemitter3": "^5.0.1",
"framer-motion": "^11.0.5",
"framer-motion": "^11.3.2",
"lodash.throttle": "^4.1.1",
"prop-types": "^15.8.1",
"react": "^18.2.0",

View File

@ -0,0 +1,49 @@
import { Button, Link } from "@nextui-org/react";
import { SiDiscord, SiLemmy, SiMastodon, SiMatrix } from "@icons-pack/react-simple-icons"
export const InfoButtons = () => {
return (
<div className="p-2 flex gap-2 flex-wrap">
<Button
as={Link}
size="sm"
href="https://matrix.to/#/#canvas-meta:aftermath.gg?via=matrix.org"
target="_blank"
variant="ghost"
>
<SiMatrix size={18} />
<p>Matrix</p>
</Button>
<Button
as={Link}
size="sm"
href="https://discord.gg/mEUqXZw8kR"
target="_blank"
variant="ghost"
>
<SiDiscord size={18} />
<p>Discord</p>
</Button>
<Button
as={Link}
size="sm"
href="https://toast.ooo/c/canvas"
target="_blank"
variant="ghost"
>
<SiLemmy size={18} />
<p>Lemmy</p>
</Button>
<Button
as={Link}
size="sm"
href="https://social.fediverse.events/@canvas"
target="_blank"
variant="ghost"
>
<SiMastodon size={18} />
<p>Mastodon</p>
</Button>
</div>
);
};

View File

@ -0,0 +1,29 @@
import { Button } from "@nextui-org/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
export type InfoHeaderProps = {
setInfoSidebar: (value: boolean) => void
}
export const InfoHeader = ({ setInfoSidebar }: InfoHeaderProps) => {
return (
<header className="flex p-2 justify-between items-center">
<div>
<div className="flex items-center gap-2">
<FontAwesomeIcon icon={faInfoCircle} size="lg" />
<div>
<h1 className="text-xl">Info</h1>
<p className="text-xs text-default-600">Information about the event</p>
</div>
</div>
</div>
<Button size="sm" isIconOnly onClick={() => setInfoSidebar(false)}>
<FontAwesomeIcon icon={faXmark} />
</Button>
</header>
);
};

View File

@ -0,0 +1,22 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faShieldHalved } from "@fortawesome/free-solid-svg-icons";
export const InfoPrivacy = () => {
return (
<div className="flex flex-col gap-2">
<header className="flex items-center gap-1">
<FontAwesomeIcon icon={faShieldHalved} size="2xs" className="pt-0.5" />
<h2 className="text">Privacy</h2>
</header>
<section>
<ul className="list-disc text-default-800 text-sm ml-10 flex flex-col gap-1">
<li>
Google Invisible Recaptcha is used to help prevent bots. Google's
privacy policy and terms are available below.
</li>
<li>Usernames should not be assumed to be private</li>
</ul>
</section>
</div>
);
};

View File

@ -0,0 +1,37 @@
import { faGavel } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export const InfoRules = () => {
return (
<div className="flex flex-col gap-2">
<header className="flex items-center gap-1">
<FontAwesomeIcon icon={faGavel} size="2xs" className="pt-0.5" />
<h2 className="text">Rules</h2>
</header>
<section>
<ol className="list-decimal text-default-800 text-sm ml-10 flex flex-col gap-1">
<li>
<p>No alternate accounts</p>
<p className="text-xs text-default-600">We want to keep it fair and not require people to create more
accounts to defend their art</p>
</li>
<li>
<p>No bots/automated placements</p>
<p className="text-xs text-default-600">We're land of the humans, not bots</p>
</li>
<li>
<p>No hate speech or adjacent</p>
</li>
<li>
<p>No gore or nudity (NSFW/NSFL)</p>
</li>
</ol>
<p className="text-default-600 text-xs ml-3 mt-1">
This canvas is built upon good faith rules, therefore moderators have
complete discretion on the rules. If you have any questions, ask in
the Matrix space or the Discord
</p>
</section>
</div>
)
};

View File

@ -1,10 +1,9 @@
import { Button, Link } from "@nextui-org/react";
import { Divider } from "@nextui-org/react";
import { useAppContext } from "../../contexts/AppContext";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { faDiscord } from "@fortawesome/free-brands-svg-icons";
import { Rules } from "./Rules";
import { Privacy } from "./Privacy";
import { InfoHeader } from "./InfoHeader";
import { InfoText } from "./InfoText";
import { InfoButtons } from "./InfoButtons";
import { motion } from "framer-motion"
/**
* Information sidebar
@ -17,58 +16,39 @@ export const InfoSidebar = () => {
const { infoSidebar, setInfoSidebar } = useAppContext();
return (
<div
className="sidebar sidebar-left md:max-w-[30vw]"
style={{ ...(infoSidebar ? {} : { display: "none" }) }}
>
<header>
<h1>Information</h1>
<div className="flex-grow" />
<Button size="sm" isIconOnly onClick={() => setInfoSidebar(false)}>
<FontAwesomeIcon icon={faXmark} />
</Button>
</header>
<section>
<div className="flex gap-1 *:flex-grow">
<Button
as={Link}
href="https://matrix.to/#/#canvas-meta:aftermath.gg?via=matrix.org"
target="_blank"
>
Matrix Space
</Button>
<Button
as={Link}
href="https://discord.gg/mEUqXZw8kR"
target="_blank"
>
{/* i do not know why faDiscord doesn't match the types, but it does render */}
<FontAwesomeIcon icon={faDiscord as any} />
Discord
</Button>
</div>
<Button as={Link} href="https://toast.ooo/c/canvas" target="_blank">
<div className="flex flex-col text-center">
<span>Lemmy</span>
<span className="text-xs">!canvas@toast.ooo</span>
</div>
</Button>
<Button
as={Link}
href="https://social.fediverse.events/@canvas"
target="_blank"
>
<div className="flex flex-col text-center">
<span>Mastodon</span>
<span className="text-xs">@canvas@fediverse.events</span>
</div>
</Button>
<b>Build {__COMMIT_HASH__}</b>
<div id="grecaptcha-badge"></div>
</section>
<div>
<motion.div
className="absolute w-screen h-screen z-50 left-0 top-0 bg-black"
initial={{ opacity: 0, visibility: 'hidden' }}
animate={{ opacity: infoSidebar ? 0.25 : 0, visibility: infoSidebar ? 'visible' : 'hidden' }}
transition={{ type: 'spring', stiffness: 50 }}
/>
<motion.div
className="min-w-[20rem] max-w-[75vw] md:max-w-[30vw] bg-white text-black flex flex-col justify-between fixed left-0 h-full shadow-xl overflow-y-auto z-50 top-0"
initial={{ x: '-150%' }}
animate={{ x: infoSidebar ? '-50%' : '-150%' }}
transition={{ type: 'spring', stiffness: 50 }}
/>
<motion.div
className="min-w-[20rem] max-w-[75vw] md:max-w-[30vw] bg-white text-black flex flex-col justify-between fixed left-0 h-full shadow-xl overflow-y-auto z-50 top-0"
initial={{ x: '-100%' }}
animate={{ x: infoSidebar ? 0 : '-100%' }}
transition={{ type: 'spring', stiffness: 50 }}
>
<div>
<InfoHeader setInfoSidebar={setInfoSidebar} />
<Rules />
<Privacy />
<Divider />
<InfoButtons />
<InfoText />
</div>
<div className="p-2">
<p className="text-xs text-default-600">Build {__COMMIT_HASH__}</p>
<div id="grecaptcha-badge"></div>
</div>
</motion.div>
</div>
);
};

View File

@ -0,0 +1,14 @@
import { InfoPrivacy } from "./InfoPrivacy";
import { InfoRules } from "./InfoRules";
import { InfoWelcome } from "./InfoWelcome";
export const InfoText = () => {
return (
<div className="flex flex-col p-5 py-1 gap-2">
<InfoWelcome />
<InfoRules />
<InfoPrivacy />
</div>
)
};

View File

@ -0,0 +1,16 @@
import { faFire } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export const InfoWelcome = () => {
return (
<div className="flex flex-col gap-2">
<header className="flex items-center gap-1">
<FontAwesomeIcon icon={faFire} size="2xs" className="pt-0.5" />
<h2 className="text">Welcome</h2>
</header>
<section>
<p className="text-default-600 text-xs ml-3">Welcome to canvas! This is an event that lasts for 72 hours where users can place pixels every so often on a shared canvas. Everyone has access to the same canvas and pixels can be placed in any location to create things on the canvas.</p>
</section>
</div>
)
};

View File

@ -1,25 +0,0 @@
/**
* Privacy policy listed in InfoSidebar
*
* TODO: Customize this w/o editing the source #46
*
* @returns
*/
export const Privacy = () => {
return (
<>
<header>
<h2>Privacy</h2>
</header>
<section>
<ul className="list-disc ml-5">
<li>
Google Invisible Recaptcha is used to help prevent bots. Google's
privacy policy and terms are available above.
</li>
<li>Usernames should not be assumed to be private</li>
</ul>
</section>
</>
);
};

View File

@ -1,46 +0,0 @@
/**
* Rules listed inside InfoSidebar
*
* TODO: Customize this w/o editing the source #46
*
* @returns
*/
export const Rules = () => {
return (
<>
<header>
<h2>Rules</h2>
</header>
<section>
<p>Welcome to Canvas!</p>
<p>
We just have a couple rules, to use the canvas you must agree to them
</p>
<ol className="list-decimal ml-5">
<li>
<b>No alternative accounts</b>
<br />
We want to keep it fair and not require people to create more
accounts to defend their art
</li>
<li>
<b>No bots/automated placements</b>
<br />
We're land of the humans, not bots
</li>
<li>
<b>No hate speech or adjacent</b>
</li>
<li>
<b>No gore or nudity (NSFW/NSFL)</b>
</li>
</ol>
<i>
This canvas is built upon good faith rules, therefore moderators have
complete discretion on the rules. If you have any questions, ask in
the Matrix space or the Discord
</i>
</section>
</>
);
};