From 25779bbc077b9ef6fe20a017d4c62720de6fcac7 Mon Sep 17 00:00:00 2001 From: ldeluigi <44567586+ldeluigi@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:46:40 +0100 Subject: [PATCH 1/5] feat!: dark mode --- src/assets/globals.scss | 6 +++--- .../MultiSearchInput/MultiSearchInput.tsx | 2 +- .../multiSearchInput.module.scss | 4 ++++ .../RadioSearchInput/RadioSearchInput.tsx | 2 +- .../SearchSnippet/searchSnippet.module.scss | 2 +- .../layout/StyledSelect/StyledSelect.tsx | 4 ++-- .../StyledSelect/styledSelect.module.scss | 4 ++++ .../search/ComboResults/ComboResults.tsx | 12 +++++------ .../ComboResults/comboResults.module.scss | 14 ++++++++++++- src/pages/combo/[id]/combo.module.scss | 2 +- src/pages/search.tsx | 3 --- tailwind.config.js | 21 ++++++++----------- 12 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/assets/globals.scss b/src/assets/globals.scss index 678e70b9e4..e8b25bdba1 100644 --- a/src/assets/globals.scss +++ b/src/assets/globals.scss @@ -3,7 +3,7 @@ @tailwind utilities; html { - @apply bg-white font-body; + @apply bg-white font-body dark:bg-black dark:text-white; } body, @@ -57,7 +57,7 @@ a { } .heading-title { - @apply font-title text-center text-4xl text-dark uppercase; + @apply font-title text-center text-4xl text-dark uppercase dark:text-light; } .heading-subtitle { @@ -65,7 +65,7 @@ a { } .button { - @apply m-4 inline-block py-2 px-3 bg-transparent text-link border-2 border-primary rounded-sm no-underline; + @apply m-4 inline-block py-2 px-3 bg-transparent text-link border-2 border-primary rounded-sm no-underline dark:text-primary; } .button.tight { diff --git a/src/components/advancedSearch/MultiSearchInput/MultiSearchInput.tsx b/src/components/advancedSearch/MultiSearchInput/MultiSearchInput.tsx index 091ead7b47..ea5b28e5e6 100644 --- a/src/components/advancedSearch/MultiSearchInput/MultiSearchInput.tsx +++ b/src/components/advancedSearch/MultiSearchInput/MultiSearchInput.tsx @@ -129,7 +129,7 @@ const MultiSearchInput: React.FC = ({ value={input.value} onChange={(value) => handleInputChange(index, value)} label={inputLabel} - inputClassName="border-dark" + inputClassName={styles.autocompleteInput} autocompleteOptions={autocompleteOptions} cardAutocomplete={cardAutocomplete} resultAutocomplete={resultAutocomplete} diff --git a/src/components/advancedSearch/MultiSearchInput/multiSearchInput.module.scss b/src/components/advancedSearch/MultiSearchInput/multiSearchInput.module.scss index 97c9f8c148..111c39a6ce 100644 --- a/src/components/advancedSearch/MultiSearchInput/multiSearchInput.module.scss +++ b/src/components/advancedSearch/MultiSearchInput/multiSearchInput.module.scss @@ -5,3 +5,7 @@ .inputButton { @apply px-2 text-white flex flex-row items-center text-3xl border flex-grow justify-center; } + +.autocompleteInput { + @apply border-dark bg-white dark:bg-dark dark:text-light; +} diff --git a/src/components/advancedSearch/RadioSearchInput/RadioSearchInput.tsx b/src/components/advancedSearch/RadioSearchInput/RadioSearchInput.tsx index 692c85831a..80e1d228eb 100644 --- a/src/components/advancedSearch/RadioSearchInput/RadioSearchInput.tsx +++ b/src/components/advancedSearch/RadioSearchInput/RadioSearchInput.tsx @@ -42,7 +42,7 @@ const RadioSearchInput: React.FC = ({ checkedValue, options, formName, la value={option.value} onChange={() => handleChange(option.value)} /> - {option.label} + {option.label} ))} diff --git a/src/components/layout/SearchGuide/SearchSnippet/searchSnippet.module.scss b/src/components/layout/SearchGuide/SearchSnippet/searchSnippet.module.scss index 6c4afbef63..fcb0a9d89e 100644 --- a/src/components/layout/SearchGuide/SearchSnippet/searchSnippet.module.scss +++ b/src/components/layout/SearchGuide/SearchSnippet/searchSnippet.module.scss @@ -1,5 +1,5 @@ .link { - @apply text-dark no-underline; + @apply text-dark no-underline dark:text-light; .searchSnippet { @apply border-2 border-dark pb-2 mb-4 rounded-sm; } diff --git a/src/components/layout/StyledSelect/StyledSelect.tsx b/src/components/layout/StyledSelect/StyledSelect.tsx index 19f2322940..d37535d00f 100644 --- a/src/components/layout/StyledSelect/StyledSelect.tsx +++ b/src/components/layout/StyledSelect/StyledSelect.tsx @@ -20,7 +20,7 @@ const StyledSelect: React.FC = ({ value, options, selectBackgroundClassName = 'border border-dark', - selectTextClassName = 'text-dark', + selectTextClassName = styles.selectOption, onChange, disabled, }) => { @@ -48,7 +48,7 @@ const StyledSelect: React.FC = ({ className={`${styles.operatorSelector} ${selectTextClassName} focus:shadow-outline`} > {options.map((option, index) => ( - ))} diff --git a/src/components/layout/StyledSelect/styledSelect.module.scss b/src/components/layout/StyledSelect/styledSelect.module.scss index 7f76563952..55751bf8b4 100644 --- a/src/components/layout/StyledSelect/styledSelect.module.scss +++ b/src/components/layout/StyledSelect/styledSelect.module.scss @@ -1,3 +1,7 @@ .operatorSelector { @apply w-full h-10 pl-3 pr-6 appearance-none bg-transparent; } + +.selectOption { + @apply text-dark bg-white dark:text-light dark:bg-dark; +} diff --git a/src/components/search/ComboResults/ComboResults.tsx b/src/components/search/ComboResults/ComboResults.tsx index 5e1855a524..c8ca6446f7 100644 --- a/src/components/search/ComboResults/ComboResults.tsx +++ b/src/components/search/ComboResults/ComboResults.tsx @@ -83,7 +83,7 @@ export const ComboResult: React.FC = ({ > -
+
Cards in combo: {combo.uses.map(({ card, quantity }) => ( @@ -105,16 +105,16 @@ export const ComboResult: React.FC = ({ ))} {combo.requires.length > 0 && ( -
- +
+ +{combo.requires.reduce((q, r) => q + r.quantity, 0)} other card {combo.requires.reduce((q, r) => q + r.quantity, 0) > 1 ? 's' : ''}
)} {prereqCount > 0 && ( -
- +
+ +{prereqCount} other prerequisite{prereqCount > 1 ? 's' : ''}
@@ -133,7 +133,7 @@ export const ComboResult: React.FC = ({
{!hideVariants && combo.variantCount > 1 && ( -
+
+ {combo.variantCount - 1} variant{combo.variantCount > 2 ? 's' : ''} diff --git a/src/components/search/ComboResults/comboResults.module.scss b/src/components/search/ComboResults/comboResults.module.scss index 6f99ffb065..4731d62081 100644 --- a/src/components/search/ComboResults/comboResults.module.scss +++ b/src/components/search/ComboResults/comboResults.module.scss @@ -2,13 +2,25 @@ @apply flex flex-wrap justify-center; a { - @apply no-underline text-dark; + @apply no-underline text-dark dark:text-light; } .comboResult { @apply max-w-lg mx-0 my-2 rounded border-2 border-dark flex-grow flex flex-col content-center; } + .comboResultSection { + @apply border-b-2 border-light dark:border-dark; + } + + .prerequisites span { + @apply text-gray-500 dark:text-gray-400; + } + + .variantBanner { + @apply w-full bg-pink-300 text-right dark:bg-link; + } + @media (min-width: 768px) { .comboResult { @apply m-2; diff --git a/src/pages/combo/[id]/combo.module.scss b/src/pages/combo/[id]/combo.module.scss index 29aa26bee3..dab898912b 100644 --- a/src/pages/combo/[id]/combo.module.scss +++ b/src/pages/combo/[id]/combo.module.scss @@ -22,7 +22,7 @@ } thead { - @apply text-dark border-b-4; + @apply text-dark border-b-4 dark:text-light; } tbody { diff --git a/src/pages/search.tsx b/src/pages/search.tsx index ec8e6c5b14..66348e6f6e 100644 --- a/src/pages/search.tsx +++ b/src/pages/search.tsx @@ -157,7 +157,6 @@ const Search: React.FC = ({ combos, count, page, bannedCombos, error, fea id="sort-combos-select" onChange={handleSortChange} selectBackgroundClassName="border-dark border-2 my-2 sm:mr-2" - selectTextClassName="text-dark" label="Change how combos are sorted" options={SORT_OPTIONS} /> @@ -169,7 +168,6 @@ const Search: React.FC = ({ combos, count, page, bannedCombos, error, fea value={order} onChange={handleOrderChange} selectBackgroundClassName="border-dark border-2 sm:m-2" - selectTextClassName="text-dark" label="Change sort direction, ascending or descending" options={ORDER_OPTIONS} /> @@ -181,7 +179,6 @@ const Search: React.FC = ({ combos, count, page, bannedCombos, error, fea value={groupBy ? 'true' : 'false'} onChange={handleGroupByComboChange} selectBackgroundClassName="border-dark border-2 my-2 sm:mr-2" - selectTextClassName="text-dark" label="Group variants by combo" options={[ { value: 'true', label: 'Yes' }, diff --git a/tailwind.config.js b/tailwind.config.js index cf9ea021b6..e65c84f89a 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,23 +1,20 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: [ - "./src/pages/**/*.{js,ts,jsx,tsx}", - "./src/components/**/*.{js,ts,jsx,tsx}", - ], + content: ['./src/pages/**/*.{js,ts,jsx,tsx}', './src/components/**/*.{js,ts,jsx,tsx}'], theme: { extend: { colors: { - primary: "#C18AFF", - secondary: "#FF9595", - link: "#5b2499", - dark: "#222222", - light: "#DFDFDF", - danger: "#C54329", - warning: "#FFC580", + primary: '#C18AFF', + secondary: '#FF9595', + link: '#5b2499', + dark: '#222222', + light: '#DFDFDF', + danger: '#C54329', + warning: '#FFC580', }, fontFamily: { title: "'Josefin Sans', sans-serif", - body: "Roboto, sans-serif", + body: 'Roboto, sans-serif', }, }, }, From d38d3de3960c36cb585ab9ee9a96ef83cb2de388 Mon Sep 17 00:00:00 2001 From: ldeluigi <44567586+ldeluigi@users.noreply.github.com> Date: Fri, 15 Nov 2024 13:47:13 +0100 Subject: [PATCH 2/5] style: fix more dark mode issues --- src/assets/globals.scss | 2 +- .../AutocompleteInput/AutocompleteInput.tsx | 34 +++++++++++-------- src/components/layout/Footer/Footer.tsx | 2 +- .../CardSubmission/CardSubmission.tsx | 2 -- .../Feature Submission/FeatureSubmission.tsx | 1 - src/pages/advanced-search.module.scss | 8 +++++ src/pages/advanced-search.tsx | 12 ++----- src/pages/index.tsx | 2 +- src/pages/privacy-policy.module.scss | 2 +- src/pages/report-error.module.scss | 2 +- src/pages/style-guide.module.scss | 2 +- src/pages/syntax-guide.module.scss | 4 +-- 12 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/assets/globals.scss b/src/assets/globals.scss index e8b25bdba1..8f7c08cb44 100644 --- a/src/assets/globals.scss +++ b/src/assets/globals.scss @@ -18,7 +18,7 @@ html, } a { - @apply underline text-link; + @apply underline text-link dark:text-primary; } #main:focus { diff --git a/src/components/advancedSearch/AutocompleteInput/AutocompleteInput.tsx b/src/components/advancedSearch/AutocompleteInput/AutocompleteInput.tsx index ae41e5d253..5854fe5946 100644 --- a/src/components/advancedSearch/AutocompleteInput/AutocompleteInput.tsx +++ b/src/components/advancedSearch/AutocompleteInput/AutocompleteInput.tsx @@ -13,7 +13,13 @@ const MAX_NUMBER_OF_MATCHING_RESULTS = 20; const AUTOCOMPLETE_DELAY = 150; const BLUR_CLOSE_DELAY = 900; -export type AutoCompleteOption = { value: string; label: string; alias?: RegExp; normalizedValue?: string }; +export type AutoCompleteOption = { + value: string; + label: string; + alias?: RegExp; + normalizedValue?: string; + normalizedLabel?: string; +}; type Props = { value: string; @@ -25,7 +31,6 @@ type Props = { inputId: string; placeholder?: string; label?: string; - matchAgainstOptionLabel?: boolean; hasError?: boolean; useValueForInput?: boolean; onChange?: (_value: string) => void; @@ -41,7 +46,6 @@ const AutocompleteInput: React.FC = ({ templateAutocomplete, inputId, label, - matchAgainstOptionLabel, useValueForInput, placeholder, hasError, @@ -66,10 +70,6 @@ const AutocompleteInput: React.FC = ({ templateAutocomplete; const inMemory = !active || (!cardAutocomplete && !resultAutocomplete && !templateAutocomplete); - autocompleteOptions?.forEach( - (option) => (option.normalizedValue = option.normalizedValue ?? normalizeStringInput(option.value)), - ); - const total = matchingAutoCompleteOptions.length; const option = matchingAutoCompleteOptions[arrowCounter]; let screenReaderSelectionText = ''; @@ -226,6 +226,12 @@ const AutocompleteInput: React.FC = ({ setLoading(false); } } + options + .filter((o) => o.normalizedValue === undefined) + .forEach((o) => (o.normalizedValue = o.normalizedValue ?? normalizeStringInput(o.value))); + options + .filter((o) => o.normalizedLabel === undefined) + .forEach((o) => (o.normalizedLabel = o.normalizedLabel ?? normalizeStringInput(o.label))); return options.filter((option) => { const mainMatch = option.normalizedValue?.includes(normalizedValue); @@ -233,18 +239,15 @@ const AutocompleteInput: React.FC = ({ return true; } - if (matchAgainstOptionLabel) { - const labelMatch = normalizeStringInput(option.label).includes(normalizedValue); + const labelMatch = option.normalizedLabel?.includes(normalizedValue); - if (labelMatch) { - return true; - } + if (labelMatch) { + return true; } if (option.alias) { return normalizedValue.match(option.alias); } - return false; }); }; @@ -291,7 +294,8 @@ const AutocompleteInput: React.FC = ({ } setMatchingAutoCompleteOptions([]); const totalOptions = await findAllMatches(value); - setMatchingAutoCompleteOptions(findBestMatches(totalOptions, value)); + const matchingOptions = findBestMatches(totalOptions, value); + setMatchingAutoCompleteOptions(matchingOptions); }; const handleKeydown = (e: React.KeyboardEvent) => { @@ -358,7 +362,7 @@ const AutocompleteInput: React.FC = ({ {matchingAutoCompleteOptions.map((item, index) => (
  • handleClick(item)} onMouseOver={() => handleAutocompleteItemHover(index)} > diff --git a/src/components/layout/Footer/Footer.tsx b/src/components/layout/Footer/Footer.tsx index 8886f7eaf4..5636d6ec94 100644 --- a/src/components/layout/Footer/Footer.tsx +++ b/src/components/layout/Footer/Footer.tsx @@ -54,7 +54,7 @@ const Footer: React.FC = ({ className, noMargin }) => {

    Commander Spellbook utilizes icons provided by  - Font Awesome  according to the  + Font Awesome according to the  Font Awesome License.

  • diff --git a/src/components/submission/CardSubmission/CardSubmission.tsx b/src/components/submission/CardSubmission/CardSubmission.tsx index 33190a9692..600ba60232 100644 --- a/src/components/submission/CardSubmission/CardSubmission.tsx +++ b/src/components/submission/CardSubmission/CardSubmission.tsx @@ -72,7 +72,6 @@ const CardSubmission = ({ card, template, onChange, index, onDelete }: Props) => placeholder="Search for a template (ex: 'Creature with haste') or type in a new one..." // hasError={!!input.error} useValueForInput - matchAgainstOptionLabel maxLength={256} /> @@ -91,7 +90,6 @@ const CardSubmission = ({ card, template, onChange, index, onDelete }: Props) => placeholder="Search for a card..." // hasError={!!input.error} useValueForInput - matchAgainstOptionLabel maxLength={256} /> diff --git a/src/components/submission/Feature Submission/FeatureSubmission.tsx b/src/components/submission/Feature Submission/FeatureSubmission.tsx index af3bba5c76..10606e661b 100644 --- a/src/components/submission/Feature Submission/FeatureSubmission.tsx +++ b/src/components/submission/Feature Submission/FeatureSubmission.tsx @@ -30,7 +30,6 @@ const FeatureSubmission: React.FC = ({ feature, onChange, onDelete, index placeholder="Search for a feature (ex: 'Infinite mana')..." // hasError={!!input.error} useValueForInput - matchAgainstOptionLabel maxLength={256} /> - diff --git a/src/pages/submit-a-combo.tsx b/src/pages/submit-a-combo.tsx index 9e39172af2..52f325f7c6 100644 --- a/src/pages/submit-a-combo.tsx +++ b/src/pages/submit-a-combo.tsx @@ -297,7 +297,7 @@ const SubmitACombo: React.FC = () => { value={manaCost} onChange={(e) => setManaCost(e.target.value)} /> -
    +
    Preview:
    From 6186e86c5adac8c8cc51660125cbac4a05afe1aa Mon Sep 17 00:00:00 2001 From: ldeluigi <44567586+ldeluigi@users.noreply.github.com> Date: Sat, 16 Nov 2024 10:53:35 +0100 Subject: [PATCH 4/5] chore: remove hardcoded references to scryfall SVGs --- src/pages/api/combo/[id]/generate-image.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/pages/api/combo/[id]/generate-image.ts b/src/pages/api/combo/[id]/generate-image.ts index 6fc5db4f17..bb267fd82d 100644 --- a/src/pages/api/combo/[id]/generate-image.ts +++ b/src/pages/api/combo/[id]/generate-image.ts @@ -2,17 +2,9 @@ import { Canvas, CanvasRenderingContext2D, createCanvas, loadImage } from 'canva import { VariantsApi } from '@spacecowmedia/spellbook-client'; import { apiConfiguration } from 'services/api.service'; import { NextApiRequest, NextApiResponse } from 'next'; +import scryfall from 'scryfall-client'; import serverPath from 'lib/serverPath'; -const manaSymbols: { [key: string]: string } = { - W: 'https://svgs.scryfall.io/card-symbols/W.svg', - U: 'https://svgs.scryfall.io/card-symbols/U.svg', - B: 'https://svgs.scryfall.io/card-symbols/B.svg', - R: 'https://svgs.scryfall.io/card-symbols/R.svg', - G: 'https://svgs.scryfall.io/card-symbols/G.svg', - C: 'https://svgs.scryfall.io/card-symbols/C.svg', -}; - const width = 1080; const manaOffset = width / 25; const iWidth = (width * 32) / 500; @@ -34,7 +26,7 @@ async function headerCanvas(identityArray: any[]) { let startManaPos = width / 2 - ((identityArray.length - 1) * (iWidth + manaOffset) + iWidth) / 2; for (let [index, letter] of identityArray.entries()) { let position = index * (iWidth + manaOffset) + startManaPos; - let img = await loadImage(manaSymbols[letter]); + let img = await loadImage(scryfall.getSymbolUrl(letter)); ctx.drawImage(img, position, manaOffset / 2, iWidth, iWidth); } return canvas1; From 44ecce264ef171a1900e3e446f5de0b1fab5af9c Mon Sep 17 00:00:00 2001 From: ldeluigi <44567586+ldeluigi@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:15:02 +0100 Subject: [PATCH 5/5] feat: dark mode switch --- src/components/SearchBar/SearchBar.tsx | 8 ++- .../SearchBar/searchBar.module.scss | 3 +- src/components/layout/Icon/Icon.tsx | 6 ++ src/components/ui/DarkMode/DarkMode.tsx | 58 +++++++++++++++++++ tailwind.config.js | 1 + 5 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/components/ui/DarkMode/DarkMode.tsx diff --git a/src/components/SearchBar/SearchBar.tsx b/src/components/SearchBar/SearchBar.tsx index 540d0aaa39..66115e4a75 100644 --- a/src/components/SearchBar/SearchBar.tsx +++ b/src/components/SearchBar/SearchBar.tsx @@ -3,9 +3,10 @@ import Link from 'next/link'; import styles from './searchBar.module.scss'; import { NextRouter, useRouter } from 'next/router'; import UserDropdown from '../layout/UserDropdown/UserDropdown'; -import { useCookies } from 'react-cookie'; import { apiConfiguration } from 'services/api.service'; import { VariantsApi } from '@spacecowmedia/spellbook-client'; +import DarkMode from 'components/ui/DarkMode/DarkMode'; +import { useCookies } from 'react-cookie'; type Props = { onHomepage?: boolean; @@ -119,7 +120,7 @@ const SearchBar: React.FC = ({ onHomepage, className }) => {
    {!onHomepage && ( -
    +
    + + +