diff --git a/components/arcade/showcase/cohort-card.js b/components/arcade/showcase/cohort-card.js index c72df2d1..2fa5437d 100644 --- a/components/arcade/showcase/cohort-card.js +++ b/components/arcade/showcase/cohort-card.js @@ -54,7 +54,6 @@ const CohortCard = ({ } const firstImage = imageLink || randomNotFoundImg(id) - console.log({imageLink}) function red() { window.location.href = '/arcade/showcase/project/' + id + '/edit' @@ -125,7 +124,7 @@ const CohortCard = ({ } }} > - {' '} + {' '} )} @@ -170,7 +169,7 @@ const CohortCard = ({ }} onClick={e => { setIsVisible(false) - document.getElementById('add-project').close() + document.getElementById('delete-project').close() handleDelete() }} > @@ -186,7 +185,7 @@ const CohortCard = ({ color: '#09AFB4' }} onClick={e => { - document.getElementById('add-project').close() + document.getElementById('delete-project').close() }} /> diff --git a/components/arcade/showcase/project-edit.js b/components/arcade/showcase/project-edit.js index 3224fae1..fc697f50 100644 --- a/components/arcade/showcase/project-edit.js +++ b/components/arcade/showcase/project-edit.js @@ -1,26 +1,14 @@ -import { Input, Label, Text, Flex, Box, Grid } from 'theme-ui' +import { Input, Label, Text, Box, Grid } from 'theme-ui' import ProjectView from './project-view' import useForm from '../../../lib/use-form' import Submit from '../../submit' -import { useState } from 'react' import Icon from '@hackclub/icons' -// import FileInput from '../../../pages/api/arcade/showcase/projects/[projectID]/file-input' /** @jsxImportSource theme-ui */ const ProjectEditForm = ({ project }) => { - // const [previewProject, setPreviewProject] = useState(project) - const [screenshot, setScreenshot] = useState(project.screenshot) - const [newScreenshot, setNewScreenshot] = useState('') - - const [video, setVideo] = useState(project.video) - const [newVideo, setNewVideo] = useState('') - - function publishedChanges(e) { - console.log('published changes', e) - } const { status, formProps, useField, data } = useForm( `/api/arcade/showcase/projects/${project.id}/edit/`, - publishedChanges, + null, { method: 'PATCH', initData: { ...project, recordId: project.id }, @@ -29,38 +17,6 @@ const ProjectEditForm = ({ project }) => { } ) - const updateScreenshot = newMedia => { - if (screenshot.some(item => item === newMedia)) { - alert('This media already exists and cannot be added.') - return - } - setScreenshot(screenshot => [...screenshot, newMedia]) - } - - const deleteScreenshot = deletedMedia => { - setScreenshot(screenshot.filter(item => !item.includes(deletedMedia))) - } - - const updateNewScreenshot = e => { - setNewScreenshot(e.target.value) - } - - const updateVideo = newMedia => { - if (video.some(item => item === newMedia)) { - alert('This media already exists and cannot be added.') - return - } - setVideo(video => [...video, newMedia]) - } - - const deleteVideo = deletedMedia => { - setVideo(video.filter(item => !item.includes(deletedMedia))) - } - - const updateNewVideo = e => { - setNewVideo(e.target.value) - } - const previewProject = { ...data } @@ -134,6 +90,17 @@ const ProjectEditForm = ({ project }) => { sx={{ border: '1px dashed', borderColor: '#09AFB4', mb: 2 }} /> + + Short description + + This shows up on the showcase page. Keep it short and sweet! + + + ReadMe Link { - Screenshot link + Screenshot link (required) - Demo your work! No hosted link? Try{' '} - #cdn{' '} - or tmpfiles + Demo your work! Post an image in{' '} + #cdn{' '} + on Slack and paste the link here. { /> - Video link + Video demo (optional) - Add a link to your demo video! Need a host? Try{' '} - #cdn{' '} - or tmpfiles + Short video demoing your project. YouTube link. Suggested for hardware projects. { { }} /> + + #scrapbook Slack Link + + This is just to show you worked on this for arcade! + + + + + Hours (estimated) + + This isn't shown on the site and won't affect your chances, but it'll help us guage how accurate arcade was. Please be honestโ this is just feedback for us for future events we run! + + + + { { const [darkColor, setDarkColor] = useState('#000000') @@ -66,25 +68,24 @@ const ProjectView = ({ setInvertedColor(invertColor(textColor)) }, [color]) - function convertToRawUrl(githubUrl) { - if (!githubUrl.includes('github.com')) { - // throw new Error('Invalid GitHub URL') - return '' - } + // function convertToRawUrl(githubUrl) { + // if (!githubUrl.includes('github.com')) { + // // throw new Error('Invalid GitHub URL') + // return '' + // } - return githubUrl - .replace('github.com', 'raw.githubusercontent.com') - .replace('/blob/', '/') - } + // return githubUrl + // .replace('github.com', 'raw.githubusercontent.com') + // .replace('/blob/', '/') + // } const [markdown, setMarkdown] = useState('') useEffect(() => { const fetchMarkdown = async () => { - const rawReadMeLink = convertToRawUrl(readMeLink) - if (rawReadMeLink) { + if (readMeLink) { try { - const res = await fetch(rawReadMeLink) + const res = await fetch(readMeLink) const text = await res.text() setMarkdown(text) } catch (error) { @@ -101,7 +102,13 @@ const ProjectView = ({ {title} + {description} By {user} - - View all my ships - + {playLink && ( + + Play Now + + )} + + + {codeHost} + + + {preview ? ( + <>> + ) : ( + + View all my ships + + )} - { image != '' && ( + {image != '' && ( - + )} - { video != '' && ( + + {/* { video != '' && ( - )} + )} */} - - - {playLink && ( - - Play Now - - )} - - - {codeHost} - - ) } diff --git a/components/arcade/showcase/readme-renderer.js b/components/arcade/showcase/readme-renderer.js index d314373e..03a1ccfe 100644 --- a/components/arcade/showcase/readme-renderer.js +++ b/components/arcade/showcase/readme-renderer.js @@ -1,14 +1,19 @@ -import ReactMarkdown from "react-markdown" -import remarkGfm from "remark-gfm" -import style from "./readme-renderer.module.css" +import ReactMarkdown from 'react-markdown' +import remarkGfm from 'remark-gfm' +import rehypeRaw from 'rehype-raw' +import rehypeSanitize from 'rehype-sanitize' +import style from './readme-renderer.module.css' const ReadmeRenderer = ({ markdown }) => { return ( + rehypePlugins={[rehypeRaw, rehypeSanitize]} + linkTarget={'_blank'} + > + {markdown} + ) } export default ReadmeRenderer \ No newline at end of file diff --git a/components/arcade/showcase/readme-renderer.module.css b/components/arcade/showcase/readme-renderer.module.css index d4d04d75..f61234e8 100644 --- a/components/arcade/showcase/readme-renderer.module.css +++ b/components/arcade/showcase/readme-renderer.module.css @@ -1,3 +1,396 @@ +.reactMarkDown { + text-align: left; +} .reactMarkDown img { max-width: 100%; -} \ No newline at end of file +} + +/* +Copyright (c) 2017 Chris Patuzzo +https://twitter.com/chrispatuzzo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +.reactMarkDown a { + color: #4183C4; + text-decoration: none; +} + +.reactMarkDown a.absent { + color: #cc0000; +} + +.reactMarkDown a.anchor { + display: block; + padding-left: 30px; + margin-left: -30px; + cursor: pointer; + position: absolute; + top: 0; + left: 0; + bottom: 0; +} + +.reactMarkDown h1, .reactMarkDown h2, .reactMarkDown h3, .reactMarkDown h4, .reactMarkDown h5, .reactMarkDown h6 { + margin: 20px 0 10px; + padding: 0; + font-weight: bold; + -webkit-font-smoothing: antialiased; + cursor: text; + position: relative; +} + +.reactMarkDown h2:first-child, .reactMarkDown h1:first-child, .reactMarkDown h1:first-child + h2, .reactMarkDown h3:first-child, .reactMarkDown h4:first-child, .reactMarkDown h5:first-child, .reactMarkDown h6:first-child { + margin-top: 0; + padding-top: 0; +} + +.reactMarkDown h1:hover a.anchor, .reactMarkDown h2:hover a.anchor, .reactMarkDown h3:hover a.anchor, .reactMarkDown h4:hover a.anchor, .reactMarkDown h5:hover a.anchor, .reactMarkDown h6:hover a.anchor { + text-decoration: none; +} + +.reactMarkDown h1 tt, .reactMarkDown h1 code { + font-size: inherit; +} + +.reactMarkDown h2 tt, .reactMarkDown h2 code { + font-size: inherit; +} + +.reactMarkDown h3 tt, .reactMarkDown h3 code { + font-size: inherit; +} + +.reactMarkDown h4 tt, .reactMarkDown h4 code { + font-size: inherit; +} + +.reactMarkDown h5 tt, .reactMarkDown h5 code { + font-size: inherit; +} + +.reactMarkDown h6 tt, .reactMarkDown h6 code { + font-size: inherit; +} + +.reactMarkDown h1 { + font-size: 28px; + /* color: black; */ +} + +.reactMarkDown h2 { + font-size: 24px; + border-bottom: 1px solid #cccccc; + /* color: black; */ +} + +.reactMarkDown h3 { + font-size: 18px; +} + +.reactMarkDown h4 { + font-size: 16px; +} + +.reactMarkDown h5 { + font-size: 14px; +} + +.reactMarkDown h6 { + font-size: 14px; +} + +.reactMarkDown p, .reactMarkDown blockquote, .reactMarkDown ul, .reactMarkDown ol, .reactMarkDown dl, .reactMarkDown li, .reactMarkDown table, .reactMarkDown pre { + margin: 15px 0; +} + +.reactMarkDown hr { + border: 0 none; + color: #cccccc; + height: 4px; + padding: 0; +} + +.reactMarkDown .reactMarkDown > h2:first-child { + margin-top: 0; + padding-top: 0; +} + +.reactMarkDown .reactMarkDown > h1:first-child { + margin-top: 0; + padding-top: 0; +} + +.reactMarkDown .reactMarkDown > h1:first-child + h2 { + margin-top: 0; + padding-top: 0; +} + +.reactMarkDown .reactMarkDown > h3:first-child, .reactMarkDown .reactMarkDown > h4:first-child, .reactMarkDown .reactMarkDown > h5:first-child, .reactMarkDown .reactMarkDown > h6:first-child { + margin-top: 0; + padding-top: 0; +} + +.reactMarkDown a:first-child h1, .reactMarkDown a:first-child h2, .reactMarkDown a:first-child h3, .reactMarkDown a:first-child h4, .reactMarkDown a:first-child h5, .reactMarkDown a:first-child h6 { + margin-top: 0; + padding-top: 0; +} + +.reactMarkDown h1 p, .reactMarkDown h2 p, .reactMarkDown h3 p, .reactMarkDown h4 p, .reactMarkDown h5 p, .reactMarkDown h6 p { + margin-top: 0; +} + +.reactMarkDown li p.first { + display: inline-block; +} + +.reactMarkDown ul, .reactMarkDown ol { + padding-left: 30px; +} + +.reactMarkDown ul :first-child, .reactMarkDown ol :first-child { + margin-top: 0; +} + +.reactMarkDown ul :last-child, .reactMarkDown ol :last-child { + margin-bottom: 0; +} + +.reactMarkDown dl { + padding: 0; +} + +.reactMarkDown dl dt { + font-size: 14px; + font-weight: bold; + font-style: italic; + padding: 0; + margin: 15px 0 5px; +} + +.reactMarkDown dl dt:first-child { + padding: 0; +} + +.reactMarkDown dl dt > :first-child { + margin-top: 0; +} + +.reactMarkDown dl dt > :last-child { + margin-bottom: 0; +} + +.reactMarkDown dl dd { + margin: 0 0 15px; + padding: 0 15px; +} + +.reactMarkDown dl dd > :first-child { + margin-top: 0; +} + +.reactMarkDown dl dd > :last-child { + margin-bottom: 0; +} + +.reactMarkDown blockquote { + border-left: 4px solid #dddddd; + padding: 0 15px; + color: #777777; +} + +.reactMarkDown blockquote > :first-child { + margin-top: 0; +} + +.reactMarkDown blockquote > :last-child { + margin-bottom: 0; +} + +.reactMarkDown table { + padding: 0; +} + +.reactMarkDown table tr { + border-top: 1px solid #cccccc; + background-color: white; + margin: 0; + padding: 0; +} + +.reactMarkDown table tr:nth-child(2n) { + background-color: #f8f8f8; +} + +.reactMarkDown table tr th { + font-weight: bold; + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; +} + +.reactMarkDown table tr td { + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; +} + +.reactMarkDown table tr th :first-child, .reactMarkDown table tr td :first-child { + margin-top: 0; +} + +.reactMarkDown table tr th :last-child, .reactMarkDown table tr td :last-child { + margin-bottom: 0; +} + +.reactMarkDown img { + max-width: 100%; +} + +.reactMarkDown span.frame { + display: block; + overflow: hidden; +} + +.reactMarkDown span.frame > span { + border: 1px solid #dddddd; + display: block; + float: left; + overflow: hidden; + margin: 13px 0 0; + padding: 7px; + width: auto; +} + +.reactMarkDown span.frame span img { + display: block; + float: left; +} + +.reactMarkDown span.frame span span { + clear: both; + color: #333333; + display: block; + padding: 5px 0 0; +} + +.reactMarkDown span.align-center { + display: block; + overflow: hidden; + clear: both; +} + +.reactMarkDown span.align-center > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: center; +} + +.reactMarkDown span.align-center span img { + margin: 0 auto; + text-align: center; +} + +.reactMarkDown span.align-right { + display: block; + overflow: hidden; + clear: both; +} + +.reactMarkDown span.align-right > span { + display: block; + overflow: hidden; + margin: 13px 0 0; + text-align: right; +} + +.reactMarkDown span.align-right span img { + margin: 0; + text-align: right; +} + +.reactMarkDown span.float-left { + display: block; + margin-right: 13px; + overflow: hidden; + float: left; +} + +.reactMarkDown span.float-left span { + margin: 13px 0 0; +} + +.reactMarkDown span.float-right { + display: block; + margin-left: 13px; + overflow: hidden; + float: right; +} + +.reactMarkDown span.float-right > span { + display: block; + overflow: hidden; + margin: 13px auto 0; + text-align: right; +} + +.reactMarkDown code, .reactMarkDown tt { + margin: 0 2px; + padding: 0 5px; + white-space: nowrap; + border: 1px solid #eaeaea; + background-color: #f8f8f8; + border-radius: 3px; +} + +.reactMarkDown pre code { + margin: 0; + padding: 0; + white-space: pre; + border: none; + background: transparent; +} + +.reactMarkDown .highlight pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; +} + +.reactMarkDown pre { + background-color: #f8f8f8; + border: 1px solid #cccccc; + font-size: 13px; + line-height: 19px; + overflow: auto; + padding: 6px 10px; + border-radius: 3px; +} + +.reactMarkDown code, .reactMarkDown pre tt { + background-color: transparent; + border: none; +} diff --git a/components/arcade/showcase/small-view-card.js b/components/arcade/showcase/small-view-card.js new file mode 100644 index 00000000..24876e32 --- /dev/null +++ b/components/arcade/showcase/small-view-card.js @@ -0,0 +1,33 @@ +import { useRef } from 'react' +import { Text, Close } from 'theme-ui' +import styles from './cohort-card.module.css' +import { useState } from 'react' +import { Button } from 'theme-ui' +import Icon from '@hackclub/icons' +import randomNotFoundImg from './random-not-found-img' +/** @jsxImportSource theme-ui */ + +const SmallView = ({ + id, + title = 'Title Not Found', + desc = 'Description Not Found' +}) => { + return ( + + {title} + + {desc} + + ) +} + +export default SmallView diff --git a/components/arcade/showcase/youtube-renderer.js b/components/arcade/showcase/youtube-renderer.js new file mode 100644 index 00000000..6b070e2b --- /dev/null +++ b/components/arcade/showcase/youtube-renderer.js @@ -0,0 +1,18 @@ +import LiteYouTubeEmbed from 'react-lite-youtube-embed'; +import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css' + +const YoutubeRenderer = ({ youtubeLink }) => { + if (!youtubeLink) return null + const youtubeID = youtubeLink.split('v=')[1] + if (!youtubeID) return Invalid YouTube link: "{youtubeLink}" + + return ( + + ) +} + +export default YoutubeRenderer \ No newline at end of file diff --git a/package.json b/package.json index eb5ae56e..cf6f0425 100644 --- a/package.json +++ b/package.json @@ -62,12 +62,14 @@ "pcb-stackup": "^4.2.8", "rc-dialog": "^9.5.2", "react": "^17.0.2", + "react-beautiful-dnd": "^13.1.1", "react-before-after-slider-component": "^1.1.8", "react-countdown": "^2.3.6", "react-datepicker": "^4.24.0", "react-dom": "^17.0.2", "react-horizontal-scrolling-menu": "^6.0.2", "react-konami-code": "^2.3.0", + "react-lite-youtube-embed": "^2.4.0", "react-markdown": "^8", "react-marquee-slider": "^1.1.5", "react-masonry-css": "^1.0.16", @@ -84,6 +86,8 @@ "react-use-websocket": "^4.8.1", "react-wrap-balancer": "^1.1.0", "recharts": "2.12.2", + "rehype-raw": "^7.0.0", + "rehype-sanitize": "^6.0.0", "remark": "^15.0.1", "remark-gfm": "^3.0.1", "remark-html": "^16.0.1", diff --git a/pages/api/arcade/gallery.js b/pages/api/arcade/gallery.js deleted file mode 100644 index 356539ed..00000000 --- a/pages/api/arcade/gallery.js +++ /dev/null @@ -1,33 +0,0 @@ -import AirtablePlus from "airtable-plus" - -const fetchPosts = async () => { - const airtable = new AirtablePlus({ - apiKey: process.env.AIRTABLE_API_KEY, - baseID: 'app4kCWulfB02bV8Q', - tableName: 'Projects', - }) - - const records = await airtable.read({ - filterByFormula: '{Status} = "Shipped"' - }) - - return records.map(record => ({ - id: record.id, - name: record.fields["Name"], - desc: record.fields["Description"], - slack: record.fields["Slack Handle"], - codeLink: record.fields["Github Link"], - playLink: record.fields["Playable Link"], - images: record.fields["Screenshot / Video"], - })) -} - -export default async function handler(req, res) { - try { - const data = await fetchPosts(); - res.status(200).json(data); - } catch (error) { - console.error(error) - res.status(500).json({ error: 'Failed to fetch posts' }); - } -} \ No newline at end of file diff --git a/pages/api/arcade/showcase/projects/[projectID]/edit.js b/pages/api/arcade/showcase/projects/[projectID]/edit.js index 46bb73d2..de322882 100644 --- a/pages/api/arcade/showcase/projects/[projectID]/edit.js +++ b/pages/api/arcade/showcase/projects/[projectID]/edit.js @@ -14,11 +14,13 @@ export default async function handler(req, res) { const updatedFields = {} updatedFields['Name'] = body.title - updatedFields['Description'] = body.desc + updatedFields['Estimated Hours'] = body.hours + updatedFields['Description'] = body.description updatedFields['Slack Link'] = body.slackLink updatedFields['Code Link'] = body.codeLink updatedFields['Play Link'] = body.playLink updatedFields['Screenshot'] = [body.screenshot].map(i => ({ url: i })) + // updatedFields['Video'] = [body.video].map(i => ({ url: i })) updatedFields['color'] = body.color updatedFields['textColor'] = body.textColor updatedFields['ScreenshotLink'] = body.screenshot @@ -38,7 +40,8 @@ export default async function handler(req, res) { const results = { id: project.id, title: project.fields['Name'] || '', - desc: project.fields['Description'] || '', + hours: project.fields['Estimated Hours'] || '', + description: project.fields['Description'] || '', slackLink: project.fields['Slack Link'] || '', codeLink: project.fields['Code Link'] || '', slackLink: project.fields['Slack Link'] || '', diff --git a/pages/api/arcade/showcase/projects/[projectID]/index.js b/pages/api/arcade/showcase/projects/[projectID]/index.js index b2e31a19..00e512e2 100644 --- a/pages/api/arcade/showcase/projects/[projectID]/index.js +++ b/pages/api/arcade/showcase/projects/[projectID]/index.js @@ -42,7 +42,8 @@ export default async function handler(req, res) { const results = { id: p.id, title: p.fields['Name'] || '', - desc: p.fields['Description'] || '', + description: p.fields['Description'] || '', + hours: p.fields['Estimated Hours'], slackLink: p.fields['Slack Link'] || '', codeLink: p.fields['Code Link'] || '', slackLink: p.fields['Slack Link'] || '', @@ -53,7 +54,7 @@ export default async function handler(req, res) { color: p.fields['color'] || '', textColor: p.fields['textColor'] || '', screenshot: p.fields['ScreenshotLink'] || '', - video: p.fields['VideoLink'] || '', + video: p.fields['Video']?.[0]?.url || p.fields['VideoLink'] || '', readMeLink: p.fields['ReadMeLink'] || '' } return res.status(200).json({ project: results }) diff --git a/pages/api/arcade/showcase/vote.js b/pages/api/arcade/showcase/vote.js new file mode 100644 index 00000000..c7e2747b --- /dev/null +++ b/pages/api/arcade/showcase/vote.js @@ -0,0 +1,95 @@ +import AirtablePlus from 'airtable-plus'; + +const usersTable = new AirtablePlus({ + baseID: 'app4kCWulfB02bV8Q', + apiKey: process.env.AIRTABLE_API_KEY, + tableName: 'Users', +}); + +const votesTable = new AirtablePlus({ + baseID: 'app4kCWulfB02bV8Q', + apiKey: process.env.AIRTABLE_API_KEY, + tableName: 'Vote', +}); + +const showcaseTable = new AirtablePlus({ + baseID: 'app4kCWulfB02bV8Q', + apiKey: process.env.AIRTABLE_API_KEY, + tableName: 'Showcase', +}); + +export default async function handler(req, res) { + if (req.method !== 'POST') { + return res.status(405).json({ error: 'Method not allowed' }); + } + + try { + + const { authorization} = req.headers; + const { rank1, rank2, rank3 } = req.body; + return res.status(500).json({ error: req.body }); + + const pointsDistribution = [5, 4, 3, 2, 1]; + + for (let i = 0; i < rank1.length; i++) { + const project = rank1[i]; + const points = pointsDistribution[i]; + + addVote(project, points, authorization); + } + + for (let i = 0; i < rank2.length; i++) { + const project = rank2[i]; + const points = pointsDistribution[i]; + + addVote(project, points, authorization); + } + + for (let i = 0; i < rank3.length; i++) { + const project = rank3[i]; + const points = pointsDistribution[i]; + + addVote(project, points, authorization); + } + + { success: true, vote } + + res.status(200).json(); + } catch (error) { + console.error('Error creating vote:', error); + res.status(500).json({ error: 'Internal Server Error' }); + } +} + +const addVote = async (projectId, points, authorization) => { + if (!authorization || !points || !projectId) { + return res.status(400).json({ error: 'Missing required headers' }); + } + + const users = await usersTable.read({ + filterByFormula: `{Auth Token} = '${authorization}'` + }); + + if (users.length === 0) { + return res.status(404).json({ error: 'User not found' }); + } + + const user = users[0]; + console.log(user); + + const vote = await votesTable.create({ + Points: parseInt(points, 10), + Voter: [user.id] + }); + + const project = await showcaseTable.find(projectId); + + const updatedVotes = project.fields.Votes + ? [...project.fields.Votes, vote.id] + : [vote.id]; + + await showcaseTable.update(projectId, { + Votes: updatedVotes + }); + +} \ No newline at end of file diff --git a/pages/api/games.js b/pages/api/games.js index a7f067dc..7f0211f9 100644 --- a/pages/api/games.js +++ b/pages/api/games.js @@ -1,9 +1,15 @@ export async function getGames() { + try { + let games = await fetch( 'https://sprig.hackclub.com/api/gallery?new' ).then(res => res.json()) return games + } catch(e) { + console.error(e) + return [] + } } export default async function Games(req, res) { diff --git a/pages/api/github.js b/pages/api/github.js index 21d3e926..95aff5ef 100644 --- a/pages/api/github.js +++ b/pages/api/github.js @@ -32,6 +32,8 @@ const getUrl = (type, payload, repo) => { } export async function fetchGitHub() { + try { + const initialGitHubData = await fetch( 'https://api.github.com/orgs/hackclub/events' ).then(r => r.json()) @@ -48,6 +50,10 @@ export async function fetchGitHub() { })) return gitHubData + } catch (error) { + console.error(error) + return [] + } } export default async function github(req, res) { diff --git a/pages/api/sprig-console.js b/pages/api/sprig-console.js index 87da975b..1e404587 100644 --- a/pages/api/sprig-console.js +++ b/pages/api/sprig-console.js @@ -15,6 +15,11 @@ export async function getConsoles() { } export default async function SprigConsoles(req, res) { - const consoleCount = await getConsoles() + let consoleCount = 100 + try { + consoleCount = await getConsoles() + } catch (error) { + console.error(error) + } res.json(consoleCount) } diff --git a/pages/arcade/gallery.js b/pages/arcade/gallery.js deleted file mode 100644 index ac500282..00000000 --- a/pages/arcade/gallery.js +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react' -import Nav from '../../components/Nav' -import Footer from '../../components/arcade/Footer' -import BGImg from '../../components/background-image' -import background from '../../public/home/assemble.jpg' -import { Badge, Box, Button, Card, Container, Grid, Heading, Link, Text } from 'theme-ui' -import SlideDown from '../../components/slide-down' -import Post from '../../components/arcade/showcase/post' -import styles from '../../components/arcade/showcase/post.module.css' -import CohortCard from '../../components/arcade/showcase/cohort-card' - -export async function getStaticProps() { - const host = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : 'https://hackclub.com'; - const res = await fetch(`${host}/api/arcade/gallery`); - const posts = await res.json(); - - const filteredPosts = posts; - - return { - props: { posts: filteredPosts, - }, - }; - } - - -const gallery = ({ posts }) => { - console.log(posts); - return ( - - - - - - - - - Arcade Gallery - - - - Add a Project - - - - - - - {posts.map(post => { - return ( - ) - - })} - - - - - ) -} - -export default gallery \ No newline at end of file diff --git a/pages/arcade/showcase/index.js b/pages/arcade/showcase/index.js deleted file mode 100644 index d84ca506..00000000 --- a/pages/arcade/showcase/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' - -const index = () => { - return ( - index - ) -} - -export default index \ No newline at end of file diff --git a/pages/arcade/showcase/my.js b/pages/arcade/showcase/my.js index e038cc12..40b6c1b4 100644 --- a/pages/arcade/showcase/my.js +++ b/pages/arcade/showcase/my.js @@ -1,17 +1,10 @@ import { useEffect, useState, useRef } from 'react' import CohortCard from '../../../components/arcade/showcase/cohort-card' -import ProjectView from '../../../components/arcade/showcase/project-view' -import Nav from '../../../components/Nav' -import Footer from '../../../components/arcade/Footer' -import BGImg from '../../../components/background-image' -import background from '../../../public/arcade/homeBG.svg' import { Button, Heading, Text, Box, Close } from 'theme-ui' import SlideDown from '../../../components/slide-down' import styles from '../../../components/arcade/showcase/my.module.css' import Countdown from 'react-countdown' -import { StyleSheetContext } from 'styled-components' import Icon from '@hackclub/icons' -import Flag from '../../../components/flag' import ProjectAddView from '../../../components/arcade/showcase/project-add' /** @jsxImportSource theme-ui */ @@ -149,7 +142,7 @@ const My = () => { const [status, setStatus] = useState('loading') const [errorMsg, setError] = useState(null) - const launchDate = new Date(2024, 7, 19, 0, 0, 0, 0) + const launchDate = new Date(2025, 7, 25, 8, 0, 0, 0) const renderer = ({ hours, minutes, seconds, completed }) => { if (completed) { @@ -180,8 +173,9 @@ const My = () => { // Render a countdown return ( - First voting round in {hours > 0 ? `${hours} hours` : ''}{' '} - {minutes > 0 ? `${minutes} minutes` : ''} {seconds} seconds + First voting round in a week + {/* {hours > 0 ? `${hours} hours` : ''}{' '} + {minutes > 0 ? `${minutes} minutes` : ''} {seconds} seconds */} ) } diff --git a/pages/arcade/showcase/project/[projectID]/index.js b/pages/arcade/showcase/project/[projectID]/index.js index 5a076aec..fa242153 100644 --- a/pages/arcade/showcase/project/[projectID]/index.js +++ b/pages/arcade/showcase/project/[projectID]/index.js @@ -1,11 +1,6 @@ -import { useEffect, useState, useRef } from 'react' +import { useEffect, useState } from 'react' import ProjectView from '../../../../../components/arcade/showcase/project-view' -import Nav from '../../../../../components/Nav' -import Footer from '../../../../../components/arcade/Footer' -import BGImg from '../../../../../components/background-image' import styles from '../../../../../components/arcade/showcase/project-view.module.css' -import { Box, Text } from 'theme-ui' -import Icon from '@hackclub/icons' /** @jsxImportSource theme-ui */ const styled = ` @@ -26,7 +21,6 @@ body, html { body { background-color: #FAEFD6; - min-height: 100vh; } a { diff --git a/pages/arcade/showcase/test.js b/pages/arcade/showcase/test.js new file mode 100644 index 00000000..26e1097d --- /dev/null +++ b/pages/arcade/showcase/test.js @@ -0,0 +1,46 @@ +import React, { useEffect } from 'react'; + +const Test = () => { + + + const submitVote = async (rank1, rank2, rank3) => { + const authToken = window.localStorage.getItem('arcade.authToken'); + + try { + const response = await fetch('/api/arcade/showcase/vote', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': authToken, + }, + body: JSON.stringify({ + rank1, + rank2, + rank3, + }), + }) + + + const data = await response.json(); + return data; + } catch (error) { + console.error('Error submitting vote:', error); + throw error; + } + }; + + useEffect(() => { + + const rank1 = ["recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo"]; + const rank2 = ["recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo"]; + const rank3 = ["recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo", "recnSpjM91mCKJjlo"]; + + submitVote(rank1, rank2, rank3); + }, []); + + return ( + test + ); +}; + +export default Test; diff --git a/pages/arcade/showcase/vote.js b/pages/arcade/showcase/vote.js new file mode 100644 index 00000000..df6e0415 --- /dev/null +++ b/pages/arcade/showcase/vote.js @@ -0,0 +1,770 @@ +import { useEffect, useState, useRef } from 'react' +import CohortCard from '../../../components/arcade/showcase/cohort-card' +import { Button, Heading, Text, Box, Close, Flex } from 'theme-ui' +import SlideDown from '../../../components/slide-down' +import styles from '../../../components/arcade/showcase/my.module.css' +import Countdown from 'react-countdown' +import Icon from '@hackclub/icons' +import ProjectView from '../../../components/arcade/showcase/project-view' +import SmallView from '../../../components/arcade/showcase/small-view-card' +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' +import { over } from 'lodash' + +/** @jsxImportSource theme-ui */ + +const styled = ` +@import url('https://fonts.googleapis.com/css2?family=Slackey&family=Emblema+One&family=Gaegu&display=swap'); +body, html { + overflow-x: hidden; + } +.slackey { + font-family: "Slackey", sans-serif; + } + .emblema { + font-family: "Emblema One", system-ui; + } + + .gaegu { + font-family: "Gaegu", sans-serif; + } + + body { + background-color: #FAEFD6; + } + +@keyframes float { + + from, + to { + transform: translate(0%, -37%) rotate(-2deg); + } + + 25% { + transform: translate(-2%, -40%) rotate(2deg); + } + + 50% { + transform: translate(0%, -43%) rotate(-1deg); + } + + 75% { + transform: translate(-1%, -40%) rotate(-1deg); + } +} + +a { + color: inherit; +} +` + +const Loading = () => ( + + Loading... + +) + +const ErrorMessage = () => ( + + There was an error loading your project. + +) + +const My = () => { + // let originalProjects = { + // cohort: { + // id: 'rectAjJ2Lv4dDhUGR' + // }, + // showcases: [ + // { + // id: 'rec4cl4TSvfwwnU6H', + // createdTime: '2024-08-14T13:47:49.000Z', + // fields: { + // Name: 'Blast-off', + // 'Code Link': 'https://github.com/Ranger-NF/BlastOff', + // 'Play Link': 'https://ranger-nf.itch.io/blastoff', + // Description: 'This is a description', + // color: '#14f0cb', + // textColor: '#ffffff', + // ScreenshotLink: + // 'https://cloud-c6ul4axwx-hack-club-bot.vercel.app/0instagram_profile_downloader.jpg', + // ReadMeLink: + // 'https://raw.githubusercontent.com/remarkjs/react-markdown/main/readme.md', + // 'View link': + // 'https://hackclub.com/arcade/showcase/project/rec4cl4TSvfwwnU6H' + // } + // }, + // { + // id: 'recLyu8vD4mmUqYrA', + // createdTime: '2024-08-19T17:12:16.000Z', + // fields: { + // Name: 'Turtle T1 (A rabbit R1 spinoff)', + // 'Code Link': 'https://github.com/briyandyju09/Turtle-T1', + // Description: 'A web based spin off to the not so liked rabbit R1', + // color: '#FAEFD6', + // ScreenshotLink: + // 'https://cloud-k7p388c60-hack-club-bot.vercel.app/0image-19.png', + // ReadMeLink: + // 'https://raw.githubusercontent.com/briyandyju09/Turtle-T1/main/README.md', + // 'View link': + // 'https://hackclub.com/arcade/showcase/project/recLyu8vD4mmUqYrA' + // } + // }, + // { + // id: 'recYZd9J9MS4fDuJC', + // createdTime: '2024-08-16T22:28:10.000Z', + // fields: { + // Name: 'peace-and-tranquility', + // 'Code Link': 'https://github.com/maxwofford/peace-and-tranquility', + // 'Play Link': 'https://dinosaurbbq.org/', + // Description: 'No one is around to help', + // color: '#293438', + // textColor: '#ffffff', + // ScreenshotLink: + // 'https://cloud-c6ul4axwx-hack-club-bot.vercel.app/0instagram_profile_downloader.jpg', + // ReadMeLink: + // 'https://raw.githubusercontent.com/remarkjs/react-markdown/main/readme.md', + // 'View link': + // 'https://hackclub.com/arcade/showcase/project/recYZd9J9MS4fDuJC' + // } + // }, + // { + // id: 'reclIN8evh60EH90v', + // createdTime: '2024-08-17T05:57:05.000Z', + // fields: { + // Name: 'site2eeeEEE534', + // 'Code Link': 'https://github.com/hackclub/site', + // 'Play Link': 'https://hackclub.com', + // Description: + // '๐ The new, new Hack Club website (uses Next.js & Theme UI).', + // color: '#68d0f8', + // textColor: '#fafafa', + // ScreenshotLink: + // 'https://cloud-c6ul4axwx-hack-club-bot.vercel.app/0instagram_profile_downloader.jpg', + // ReadMeLink: + // 'https://raw.githubusercontent.com/remarkjs/react-markdown/main/readme.md', + // 'View link': + // 'https://hackclub.com/arcade/showcase/project/reclIN8evh60EH90v' + // } + // }, + // { + // id: 'reclIN8evh60EH2220v', + // createdTime: '2024-08-17T05:57:05.000Z', + // fields: { + // Name: 'site2eeeEEE53344', + // 'Code Link': 'https://github.com/hackclub/site', + // 'Play Link': 'https://hackclub.com', + // Description: + // '๐ The new, new Hack Club website (uses Next.js & Theme UI).', + // color: '#68d0f8', + // textColor: '#fafafa', + // ScreenshotLink: + // 'https://cloud-c6ul4axwx-hack-club-bot.vercel.app/0instagram_profile_downloader.jpg', + // ReadMeLink: + // 'https://raw.githubusercontent.com/remarkjs/react-markdown/main/readme.md', + // 'View link': + // 'https://hackclub.com/arcade/showcase/project/reclIN8evh60EH90v' + // } + // } + // ] + // } + + // originalProjects = originalProjects.showcases + const [projects, setProjects] = useState([]) + const [originalProjects, setOriginalProjects] = useState([]) + const [name, setName] = useState('') + const [loadStatus, setLoadStatus] = useState('loading') + const [status, setStatus] = useState('loading') + const [errorMsg, setError] = useState(null) + const [votes, setVotes] = useState({}) + const [openProjectId, setOpenProjectId] = useState('') + const [openProject, setOpenProject] = useState([]) + const [showUIElements, setShowUIElements] = useState(false) + const [activeDroppableId, setActiveDroppableId] = useState(null) + const [activeDroppable, setActiveDroppable] = useState(true) + + const [submitStatus, setSubmitStatus] = useState('loading') + const [creative, setCreative] = useState([]) + const [technical, setTechnical] = useState([]) + const [overall, setOverall] = useState([]) + + const [showCreative, setShowCreative] = useState(true) + const [showTechnical, setShowTechnical] = useState(false) + const [showOverall, setShowOverall] = useState(false) + const [endPage, setEndPage] = useState(false) + const [isButtonActive, setIsButtonActive] = useState(false) + + const loadProjects = async () => { + const token = window.localStorage.getItem('arcade.authToken') + const response = await fetch('/api/arcade/showcase/cohort/active', { + method: 'GET', + headers: { + Authorization: `Bearer ${token}` + } + }).catch(e => { + console.error(e) + setLoadStatus('error') + setError(e) + }) + const data = await response.json() + if (data.error) { + setLoadStatus('error') + return + } else { + setProjects(data.showcases) + setOriginalProjects(data.showcases) + setLoadStatus('success') + } + } + + useEffect(async () => { + loadProjects() + }, []) + + const getProjectDetails = async () => { + const token = window.localStorage.getItem('arcade.authToken') + setStatus('loading') + + try { + const response = await fetch( + `/api/arcade/showcase/projects/${openProjectId}`, + { + method: 'GET', + headers: { + Authorization: `Bearer ${token}` + } + } + ) + + const data = await response.json() + + if (data.error) { + setStatus('error') + setError(data.error) + } else { + setOpenProject(data.project) + setStatus('success') + } + } catch (e) { + console.error(e) + setStatus('error') + setError(e.message) + } + } + + useEffect(() => { + getProjectDetails() + }, [openProjectId]) + + useEffect(() => { + setShowUIElements(true) + }, []) + + useEffect(() => { + console.log(Object.keys(votes).length) + if (Object.keys(votes).length == 5) { + setIsButtonActive(true) + } else { + setIsButtonActive(false) + } + }, [votes]) + + const extractVotes = votes => { + const sortedKeys = Object.keys(votes).sort((a, b) => { + const numA = parseInt(a.split('-')[1], 10) + const numB = parseInt(b.split('-')[1], 10) + return numA - numB + }) + + return sortedKeys.map(key => votes[key]) + } + + const onDragUpdate = update => { + setActiveDroppable(true) + const { destination } = update + if (destination) { + setActiveDroppableId(destination.droppableId) + } + } + + const onDragEnd = result => { + const { source, destination } = result + + if (!destination) return + + if ( + source.droppableId === 'projects' && + destination.droppableId.startsWith('votes-') + ) { + const linkId = result.draggableId + const voteId = destination.droppableId + + setVotes(prevVotes => { + const updatedVotes = { + ...prevVotes, + [voteId]: linkId + } + + const votedProjectIds = Object.values(updatedVotes) + + const updatedProjects = originalProjects.filter( + project => !votedProjectIds.includes(project.id) + ) + + setProjects(updatedProjects) + + return updatedVotes + }) + } + setActiveDroppable(false) + } + + const deleteVote = voteId => { + setVotes(prevVotes => { + const updatedVotes = { ...prevVotes } + + delete updatedVotes[voteId] + + const votedProjectIds = Object.values(updatedVotes) + + const updatedProjects = originalProjects.filter( + project => !votedProjectIds.includes(project.id) + ) + + setProjects(updatedProjects) + + return updatedVotes + }) + } + + const renderVoteBox = voteId => { + const linkId = votes[voteId] + const project = originalProjects.find(link => link.id === linkId) + + if (project) { + return ( + + { + deleteVote(voteId) + }} + /> + + + {voteId.replace('votes-', '')} + + + + + {project.fields.Name} + + + {project.fields.Description} + + + + ) + } + + return ( + + + + {voteId.replace('votes-', '')} + + + + Drop here + + + ) + } + + const voteCreative = () => { + let ids = extractVotes(votes) + setCreative(ids) + setShowCreative(false) + setVotes({}) + setProjects(originalProjects) + setShowTechnical(true) + } + + const voteTechnical = () => { + let ids = extractVotes(votes) + setTechnical(ids) + setShowTechnical(false) + setVotes({}) + setProjects(originalProjects) + setShowOverall(true) + } + + const voteOverall = () => { + let ids = extractVotes(votes) + setOverall(ids) + setShowTechnical(false) + setVotes({}) + setProjects(originalProjects) + setEndPage(true) + } + + const submitVote = async (creative, technical, overall) => { + const authToken = window.localStorage.getItem('arcade.authToken') + + try { + const response = await fetch('/api/arcade/showcase/vote', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: authToken + }, + body: JSON.stringify({ + creative, + technical, + overall + }) + }) + + const data = await response.json() + setSubmitStatus('success') + return data + } catch (error) { + console.error('Error submitting vote:', error) + setSubmitStatus('error') + throw error + } + } + + useEffect(() => { + console.log('the votes') + console.log(creative) + console.log(technical) + console.log(overall) + + submitVote(creative, technical, overall) + }, [endPage]) + + return endPage == true ? ( + + {submitStatus == 'loading' + ? 'Loading' + : submitStatus == 'success' + ? 'Thanks for voting!' + : 'Ran into an error sending your votes'} + + ) : ( + showUIElements && ( + + + + + + + Ships + + + Here are the 18 projects for this round of voting :) Please + carefully look at each of them. + + + {provided => ( + + {projects.map((project, index) => ( + + {provided => ( + { + document + .getElementById('show-project') + .showModal() + + setOpenProjectId(project.id) + }} + sx={{ + cursor: 'drag' + }} + > + + + )} + + ))} + {provided.placeholder} + + )} + + + + + + Choose top 5 for{' '} + + + {showCreative + ? 'Most creative ships' + : showTechnical + ? 'Most technical ships' + : 'Best overall ships'} + + {['votes-1', 'votes-2', 'votes-3', 'votes-4', 'votes-5'].map( + voteId => ( + + {provided => ( + + {renderVoteBox(voteId)} + {provided.placeholder} + + )} + + ) + )} + {isButtonActive ? ( + { + showCreative + ? voteCreative() + : showTechnical + ? voteTechnical() + : showOverall + ? voteOverall() + : null + }} + sx={{ + backgroundColor: '#09AFB4', + color: '#FAEFD6', + borderRadius: '5px', + border: 'none', + px: '20px', + transitionDuration: '0.3s', + '&:hover': { + transform: 'scale(1.05)' + }, + width: 'fit-content' + }} + > + Place votes + + ) : ( + + Place votes + + )} + + + + + + + {status == 'loading' && } + + {status == 'error' && } + + {status == 'success' && ( + + )} + { + document.getElementById('show-project').close() + }} + /> + + + + + + ) + ) +} + +export default My diff --git a/pages/arcade/showcase/vote/project/[ID]/index.js b/pages/arcade/showcase/vote/project/[ID]/index.js deleted file mode 100644 index b8aac7d4..00000000 --- a/pages/arcade/showcase/vote/project/[ID]/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' - -const Page = () => { - return ( - Project - ) -} - -export default Page \ No newline at end of file diff --git a/pages/bin/gallery.js b/pages/bin/gallery.js deleted file mode 100644 index f6995a1c..00000000 --- a/pages/bin/gallery.js +++ /dev/null @@ -1,131 +0,0 @@ -import React from 'react' -import BinPost from '../../components/bin/GalleryPosts' -import styles from '../../public/bin/style/gallery.module.css' -import Script from 'next/script' -import Nav from '../../components/bin/nav' -import Footer from '../../components/footer' -import PartTag from '../../components/bin/PartTag'; -import { useEffect, useRef, useState } from 'react'; -import { resolve } from 'styled-jsx/css'; -import { set } from 'lodash'; - -export async function getStaticProps() { - const host = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : 'https://hackclub.com'; - const res = await fetch(`${host}/api/bin/gallery/posts/`); - const posts = await res.json(); - - const filteredPosts = posts.filter(post => post.status === 'Accepted' && post.parts && !post.hide); - - //Tags - - const resTag = await fetch(`${host}/api/bin/gallery/tags/`); - const tags = await resTag.json(); - - const filteredTags = tags.filter(tag => !tag.hide); - return { - props: { posts: filteredPosts, - tags: filteredTags - }, - }; -} - - - -function Gallery({ posts = [], tags = [] }) { - - const [allPosts, setAllPosts] = useState([]); - const [filterPosts, setFilterPosts] = useState([]); - const [filterParts, setFilterParts] = useState([]); - - useEffect(() => { - setAllPosts(posts); - setFilterParts([]); - - }, []); - - useEffect(() => { - setFilterPosts( - allPosts.filter(post => - post.parts && filterParts.every(part => post.parts.includes(part)) - ) - ); - }, [filterParts]); - - - const addFilter = (partID) => { - setFilterParts((prevParts) => { - if (!prevParts.includes(partID)) { - console.log("add", partID) - return [...prevParts, partID]; - } - return prevParts; - }); - - }; - - const removeFilter = (partID) => { - setFilterParts((prevParts) => { - return prevParts.filter(id => id !== partID); - }); - }; - - return ( - - - - - - - - - - Bin Gallery - A display of all of bin's projects - - Want to add to the gallery? window.location.href = '/bin'}>Create a bin project in wokwi and your project will be added to the gallery! - - Search By Tag: - - - {tags.map(tag => { - return ( - ) - - })} - - - - - - - - {filterPosts.map(post => { - return ( - ) - - })} - - - - - ) -} - - - -export default Gallery diff --git a/pages/index.js b/pages/index.js index b1674a8a..cd34cdcd 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1275,9 +1275,14 @@ export async function getStaticProps() { } hackathonsData.sort((a, b) => new Date(a.start) - new Date(b.start)) - let events = await fetch( - 'https://events.hackclub.com/api/events/upcoming/' - ).then(res => res.json()) + let events = [] + try { + await fetch( + 'https://events.hackclub.com/api/events/upcoming/' + ).then(res => res.json()) + } catch (error) { + console.error('Error fetching events:', error) + } return { props: { diff --git a/yarn.lock b/yarn.lock index 3620f3e1..3fc37530 100644 --- a/yarn.lock +++ b/yarn.lock @@ -992,7 +992,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== @@ -2130,6 +2130,14 @@ dependencies: "@types/unist" "*" +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.5" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" + integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -2208,11 +2216,29 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g== -"@types/prop-types@^15.0.0": +"@types/prop-types@*", "@types/prop-types@^15.0.0": version "15.7.12" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== +"@types/react-redux@^7.1.20": + version "7.1.33" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.33.tgz#53c5564f03f1ded90904e3c90f77e4bd4dc20b15" + integrity sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + +"@types/react@*": + version "18.3.4" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.4.tgz#dfdd534a1d081307144c00e325c06e00312c93a3" + integrity sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/styled-system@^5.1.13": version "5.1.22" resolved "https://registry.yarnpkg.com/@types/styled-system/-/styled-system-5.1.22.tgz#508499f4c68bb86dde3454693e92f5771edf177f" @@ -3303,6 +3329,13 @@ crypto-browserify@3.12.0, crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-box-model@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" @@ -4961,7 +4994,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6040,6 +6073,11 @@ mdurl@^1.0.0: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -7363,6 +7401,11 @@ quick-lru@^1.0.0: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha512-tRS7sTgyxMXtLum8L65daJnHUhfDUgboRdcWW2bR9vBfrj2+O5HSMbQOJfJJjIVSPFqbBCF37FpwWXGitDc5tA== +raf-schd@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -7416,6 +7459,19 @@ rc-util@^5.21.0, rc-util@^5.24.4, rc-util@^5.43.0: "@babel/runtime" "^7.18.3" react-is "^18.2.0" +react-beautiful-dnd@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2" + integrity sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ== + dependencies: + "@babel/runtime" "^7.9.2" + css-box-model "^1.2.0" + memoize-one "^5.1.1" + raf-schd "^4.0.2" + react-redux "^7.2.0" + redux "^4.0.4" + use-memo-one "^1.1.1" + react-before-after-slider-component@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/react-before-after-slider-component/-/react-before-after-slider-component-1.1.8.tgz#3df14381703aaa43428cdac05f271b8b492d25ca" @@ -7466,6 +7522,11 @@ react-is@16.13.1, react-is@^16.10.2, react-is@^16.13.1, react-is@^16.7.0, react- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + react-is@^18.0.0, react-is@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" @@ -7478,6 +7539,11 @@ react-konami-code@^2.3.0: dependencies: prop-types "^15.8.1" +react-lite-youtube-embed@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/react-lite-youtube-embed/-/react-lite-youtube-embed-2.4.0.tgz#1f56a12be1061d50431444d52d836bd09a1283a2" + integrity sha512-Xo6cM1zPlROvvM97JkqQIoXstlQDaC4+DawmM7BB7Hh1cXrkBHEGq1iJlQxBTUWAUklmpcC7ph7qg7CztXtABQ== + react-markdown@^8: version "8.0.7" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.7.tgz#c8dbd1b9ba5f1c5e7e5f2a44de465a3caafdf89b" @@ -7529,6 +7595,18 @@ react-popper@^2.3.0: react-fast-compare "^3.0.1" warning "^4.0.2" +react-redux@^7.2.0: + version "7.2.9" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d" + integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^17.0.2" + react-refresh@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" @@ -7701,6 +7779,13 @@ recharts@2.12.2: tiny-invariant "^1.3.1" victory-vendor "^36.6.8" +redux@^4.0.0, redux@^4.0.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + reflect.getprototypeof@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" @@ -7803,6 +7888,15 @@ rehype-raw@^5.0.0: dependencies: hast-util-raw "^6.1.0" +rehype-raw@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-7.0.0.tgz#59d7348fd5dbef3807bbaa1d443efd2dd85ecee4" + integrity sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww== + dependencies: + "@types/hast" "^3.0.0" + hast-util-raw "^9.0.0" + vfile "^6.0.0" + rehype-sanitize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/rehype-sanitize/-/rehype-sanitize-4.0.0.tgz#b5241cf66bcedc49cd4e924a5f7a252f00a151ad" @@ -7810,6 +7904,14 @@ rehype-sanitize@^4.0.0: dependencies: hast-util-sanitize "^3.0.0" +rehype-sanitize@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz#16e95f4a67a69cbf0f79e113c8e0df48203db73c" + integrity sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg== + dependencies: + "@types/hast" "^3.0.0" + hast-util-sanitize "^5.0.0" + rehype-stringify@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-8.0.0.tgz#9b6afb599bcf3165f10f93fc8548f9a03d2ec2ba" @@ -8372,16 +8474,7 @@ string-hash@1.1.3: resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -8492,7 +8585,7 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8506,13 +8599,6 @@ strip-ansi@6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -8692,7 +8778,7 @@ timers-browserify@2.0.12, timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tiny-invariant@^1.3.1: +tiny-invariant@^1.0.6, tiny-invariant@^1.3.1: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== @@ -9192,6 +9278,11 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.12.3" +use-memo-one@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" + integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ== + use-subscription@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"
{desc}
Invalid YouTube link: "{youtubeLink}"
A display of all of bin's projects