Skip to content

Commit

Permalink
share words and view current word count
Browse files Browse the repository at this point in the history
  • Loading branch information
joshfeinsilber committed May 15, 2024
1 parent fe60b42 commit cfe44dd
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 16 deletions.
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"copy-to-clipboard": "^3.3.3",
"framer-motion": "^11.1.9",
"jotai": "^2.8.0",
"jsurl": "^0.1.5",
"lodash": "^4.17.21",
"rand-seed": "^1.0.2",
"react": "^18.2.0",
Expand All @@ -24,6 +25,7 @@
"styled-components": "^6.1.11"
},
"devDependencies": {
"@types/jsurl": "^0.1.2",
"@types/lodash": "^4.17.1",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
Expand Down
3 changes: 3 additions & 0 deletions src/screens/game/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useEffect, useState } from 'react'
import { lettersForToday } from '../../util/lottery/letters'
import { handleSubmit } from '../../util/game/handleSubmit'
import { motion } from 'framer-motion'
import { WordCount } from './WordCount'

export const Game = () => {
const [word, setWord] = useAtom(currentWord)
Expand Down Expand Up @@ -54,6 +55,8 @@ export const Game = () => {
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
<WordCount />

<div className="flex w-full flex-1 items-center justify-center">
<Word />
</div>
Expand Down
7 changes: 7 additions & 0 deletions src/screens/game/WordCount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useAtomValue } from 'jotai'
import { words } from '../../store/game'

export const WordCount = () => {
const wordCount = useAtomValue(words).length
return <div className="absolute top-[24px] z-20 text-sm">Word #{wordCount + 1}</div>
}
21 changes: 20 additions & 1 deletion src/screens/results/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import { useAtomValue } from 'jotai'
import { Top } from './Top'
import { Words } from './Words'
import { motion } from 'framer-motion'
import { words } from '../../store/game'
import { lettersForToday } from '../../util/lottery/letters'
import { useMemo } from 'react'
import { decodeResults } from '../../util/results/encodedInfo'

export const Results = () => {
const wordList = useAtomValue(words)

const otherResults = useMemo(() => {
const urlParams = new URLSearchParams(window.location.search)
const results = urlParams.get('results')
if (!results) {
return null
}
return decodeResults(results)
}, [])

return (
<motion.div
initial={{ scale: 0, opacity: 0 }}
Expand All @@ -11,7 +27,10 @@ export const Results = () => {
className="w-full max-w-xl"
>
<Top />
<Words />
{otherResults ? (
<Words title="Their Words" words={otherResults.words} letters={otherResults.letters} />
) : null}
<Words title="Your Words" words={wordList} letters={lettersForToday()} canShare={true} />
</motion.div>
)
}
9 changes: 7 additions & 2 deletions src/screens/results/Top.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { GAME_OVER_MESSAGES } from '../../const/messages'
import { getRandomItemFromArray } from '../../util/lottery/seed'
import { motion } from 'framer-motion'
import { words } from '../../store/game'
import { shareResult } from '../../util/results/share'
import { resultText, shareResult } from '../../util/results/share'

export const Top = () => {
const wordsUsed = useAtomValue(words)
Expand All @@ -28,7 +28,12 @@ export const Top = () => {
<p className="text-lg opacity-90">
You completed today's puzzle in {wordsUsed.length} words.
</p>
<button className="btn btn-primary btn-lg btn-block mt-4" onClick={shareResult}>
<button
className="btn btn-primary btn-lg btn-block mt-4"
onClick={() => {
shareResult(resultText())
}}
>
Share
</button>
</div>
Expand Down
68 changes: 59 additions & 9 deletions src/screens/results/Words.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,66 @@
import { useAtomValue } from 'jotai'
import { words } from '../../store/game'
import { useMemo } from 'react'
import classNames from 'classnames'
import { resultLinkText, shareResult } from '../../util/results/share'

export const Words = () => {
const wordsUsed: string[] = useAtomValue(words)
interface Props {
title: string
words: string[]
letters: string[]

canShare?: boolean
}

export const Words = (props: Props) => {
// Since we might get the same word multiple times as we re-use this list, we make a random key for React
const randomKey = useMemo(() => {
return Math.random().toString()
}, [])

const shareResults = () => {
shareResult(
resultLinkText({
words: props.words,
letters: props.letters
})
)
}

let letterIndex = 0

return (
<div className="card mt-4 w-full select-text bg-base-100 text-center shadow-xl">
<div className="center card mt-4 w-full select-text bg-base-100 shadow-xl">
<div className="card-body flex flex-col items-center">
<ul className="text-base">
{wordsUsed.map((word, index) => (
<li key={word + index}>{word}</li>
))}
<h3 className="text-xl font-bold">{props.title}</h3>
{props.canShare ? (
<button className="btn btn-secondary btn-xs" onClick={shareResults}>
Share Words
</button>
) : null}
<ul className="mt-3 flex flex-col gap-3 text-base">
{props.words.map((word) => {
return (
<div className="flex flex-wrap gap-2 text-lg">
{word.split('').map((letter, idx) => {
let point = false
if (props.letters[letterIndex] === letter) {
point = true
letterIndex++
}

return (
<span
key={letter + idx + randomKey + word}
className={classNames({
'text-green-700 underline': point
})}
>
{letter.toUpperCase()}
</span>
)
})}
</div>
)
})}
</ul>
</div>
</div>
Expand Down
32 changes: 32 additions & 0 deletions src/util/results/encodedInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import JSURL from 'jsurl'

export const encodeResults = (data: { letters: string[]; words: string[] }) => {
const encodedWords = data.words.map((word) => {
return word.split('').map((letter) => {
return data.letters.indexOf(letter)
})
})

// Encode JSON into url friendly
return JSURL.stringify({
w: encodedWords,
l: data.letters
})
}

export const decodeResults = (encoded: string) => {
const decoded = JSURL.parse<{ w: number[][]; l: string[] }>(decodeURIComponent(encoded))

const words = decoded.w.map((word: number[]) => {
return word
.map((index) => {
return decoded.l[index]
})
.join('')
})

return {
letters: decoded.l,
words
}
}
13 changes: 9 additions & 4 deletions src/util/results/share.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { PUZZLE_NUMBER } from '../../const/puzzleNumber'
import { words } from '../../store/game'
import { store } from '../../store/store'
import { toast } from 'sonner'
import { encodeResults } from './encodedInfo'

const colors = ['🟦', '🟧', 'πŸŸͺ', '🟨', '🟩', '🟫', '⬜']

const resultText = () => {
export const resultText = () => {
const wordsUsed = store.get(words)

let text = `🎰 Charlottery No. ${PUZZLE_NUMBER}
Expand Down Expand Up @@ -36,14 +37,18 @@ const resultText = () => {
return text
}

export const shareResult = () => {
export const resultLinkText = (data: { words: string[]; letters: string[] }) => {
return `πŸ”— View my Charlottery No. ${PUZZLE_NUMBER} words: ${window.location.origin}?results=${encodeResults(data)}`
}

export const shareResult = (text: string) => {
if (!navigator.share) {
toast.success('Copied to clipboard!')
copy(resultText())
copy(text)
} else {
navigator.share({
title: `Charlottery No. ${PUZZLE_NUMBER}`,
text: resultText()
text: text
})
}
}

0 comments on commit cfe44dd

Please sign in to comment.