Skip to content

Commit

Permalink
Merge pull request #7 from frudolph77/simpleLanguageSwitch
Browse files Browse the repository at this point in the history
simple language switch
  • Loading branch information
alexander-zibert authored Dec 2, 2023
2 parents 2db2fc0 + 62f6191 commit e4d6c90
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 13 deletions.
18 changes: 18 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@reduxjs/toolkit": "^1.9.3",
"axios": "^1.5.0",
"react": "^18.2.0",
"react-circle-flags": "^0.0.20",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-scripts": "5.0.1",
Expand Down
190 changes: 190 additions & 0 deletions frontend/src/components/LanguageSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import * as React from 'react';
import { FC } from 'react';
import { Select as BaseSelect, SelectProps, SelectRootSlotProps, } from '@mui/base/Select';
import { Option as BaseOption, optionClasses } from '@mui/base/Option';
import { SelectOption } from '@mui/base/useOption';
import { styled } from '@mui/system';
import { Popper as BasePopper } from '@mui/base/Popper';
import KeyboardArrowDownRounded from '@mui/icons-material/KeyboardArrowDownRounded';
import { useTheme } from "@mui/material/styles";
import { CircleFlag } from "react-circle-flags";

type Props = {
disabled?: boolean;
prefixId?: string;
onChange?: (value: string) => void;
value?: string;
};

declare type Language = {
code: string;
language: string;
tm: string;
};

const availableCountries: Language[] = [
{code: 'pt', language: "Português", tm: 'BR'},
{code: 'cn', language: '简体中文', tm: 'CNS'},
{code: 'cn', language: '繁體中文', tm: 'CNT'},
{code: 'cz', language: 'Česky', tm: "CZ"},
{code: 'de', language: 'Deutsch', tm: "DE"},
{code: 'uk', language: 'English', tm: 'EN'},
{code: 'fr', language: 'Français', tm: 'FR'},
{code: 'gr', language: 'Ελληνικά', tm: 'GR'},
{code: 'hu', language: 'Magyar', tm: 'HU'},
{code: 'it', language: 'Italiano', tm: 'IT'},
{code: 'jp', language: '日本語', tm: 'JP'},
{code: 'kr', language: '한국어', tm: 'KR'},
{code: 'nl', language: 'Dutch', tm: 'NL'},
{code: 'pl', language: 'Polski', tm: 'PL'},
{code: 'ru', language: 'Русский', tm: 'RU'},
{code: 'es', language: 'Español', tm: "SP"},
{code: 'th', language: 'ไทย', tm: 'TH'},
{code: 'ua', language: 'Українська', tm: 'UA'},
];

const LanguageSelect: FC<Props> = (props) => {

function getCountry() {
return availableCountries.find(c => c.tm === props.value);
}

return (
<Select
id={`${props.prefixId}-select`}
disabled={props.disabled}
value={getCountry()}
renderValue={(selected: SelectOption<Language> | null) =>
<CircleFlag countryCode={selected?.value.code || "uk"} height={24}/>}
onChange={(_, value) => {
props.onChange && props.onChange((value && value.tm) || "EN");
}}
>
{availableCountries.map((country: Language) => (
<Option
key={`${country.code}-${country.tm}`}
value={country}
>
<CircleFlag countryCode={country?.code || "uk"} height={24}/>
{country.language}
</Option>
))}
</Select>
);
}

export default LanguageSelect;

const Select = React.forwardRef(function CustomSelect(
props: SelectProps<Language, false>,
ref: React.ForwardedRef<any>
) {
const slots: SelectProps<Language, false>['slots'] = {
root: Button,
listbox: Listbox,
popper: Popper,
...props.slots,
};

return <BaseSelect {...props} ref={ref} slots={slots}/>;
});

const Button = React.forwardRef(function Button<
TValue extends {},
Multiple extends boolean
>(
props: SelectRootSlotProps<TValue, Multiple>,
ref: React.ForwardedRef<HTMLButtonElement>
) {
const theme = useTheme();
const {ownerState, ...other} = props;
return (
<StyledButton type="button" {...other} ref={ref}>
{other.children}
<KeyboardArrowDownRounded fontSize="large" sx={{color: theme.palette.primary.light}}/>
</StyledButton>
);
});

const StyledButton = styled('button', {shouldForwardProp: () => true})(
({theme}) => `
box-sizing: border-box;
min-width: 80px;
padding: 8px;
text-align: left;
line-height: 1.5;
background: none;
border: none;
position: relative;
opacity: unset;
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 120ms;
-webkit-appearance: none;
&:hover {
cursor: pointer;
}
& img {
vertical-align: sub;
}
& > svg {
position: absolute;
top: 0;
}
`
);

const Listbox = styled('ul')(
({theme}) => `
font-family: "Plus Jakarta Sans";
font-size: 1rem;
box-sizing: border-box;
padding: 6px;
margin: 2px 0;
min-width: 160px;
max-height: 315px;
border-radius: 8px;
overflow: auto;
outline: 0px;
background: ${theme.palette.background.paper};
border: 1px solid ${theme.palette.mode === 'dark' ? theme.palette.languageSwitch[800] : theme.palette.languageSwitch[100]};
`
);

const Option = styled(BaseOption)(
({theme}) => `
list-style: none;
padding: 4px;
border-radius: 4px;
cursor: default;
&.${optionClasses.selected},
&.${optionClasses.highlighted}.${optionClasses.selected} {
background-color: ${theme.palette.mode === 'dark' ? theme.palette.languageSwitch[900] : theme.palette.languageSwitch[100]};
color: ${theme.palette.mode === 'dark' ? theme.palette.languageSwitch[100] : theme.palette.languageSwitch[900]};
}
&:hover,
&.${optionClasses.highlighted} {
background-color: ${theme.palette.mode === 'dark' ? theme.palette.languageSwitch[800] : theme.palette.languageSwitch[100]};
color: ${theme.palette.mode === 'dark' ? theme.palette.languageSwitch[300] : theme.palette.languageSwitch[900]};
}
&:hover {
cursor: pointer;
}
& img {
margin-right: 10px;
vertical-align: middle;
}
`
);

const Popper = styled(BasePopper)`
z-index: 10;
`;
11 changes: 5 additions & 6 deletions frontend/src/hooks/useCriteriaCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,13 @@ export const criteriaCardPool: CriteriaCard[] = [
{ id: 48, criteriaSlots: 9, irrelevantCriteria: [] },
];

const getCardUrl = (card?: CriteriaCard) =>
card
? `https://turingmachine.info/images/criteriacards/EN/TM_GameCards_EN-${(
"0" + card.id
).slice(-2)}.png`
const getCardUrl = (card?: CriteriaCard, language?: string) =>
(card && language)
? `https://turingmachine.info/images/criteriacards/${language}/TM_GameCards_${language}-${( "0" + card.id ).slice(-2)}.png`
: "";

export const useCriteriaCard = (verifier: Verifier, index: number) => {
const language = useAppSelector((state) => state.settings.language);
const comments = useAppSelector((state) => state.comments);
const comment = comments.find((comment) => comment.verifier === verifier);

Expand Down Expand Up @@ -111,7 +110,7 @@ export const useCriteriaCard = (verifier: Verifier, index: number) => {
}
};

const cardImage = useMemo(() => getCardUrl(card), [card]);
const cardImage = useMemo(() => getCardUrl(card, language), [card, language]);

useUpdateEffect(() => {
dispatch(commentsActions.updateCard({ verifier, index, card }));
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/hooks/usePaletteMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import { settingsActions } from "../store/slices/settingsSlice";
import { useAppDispatch } from "./useAppDispatch";
import { useAppSelector } from "./useAppSelector";

declare module '@mui/material/styles' {
interface Palette {
languageSwitch: Palette['primary'];
}

interface PaletteOptions {
languageSwitch?: PaletteOptions['primary'];
}
}

export const usePaletteMode = () => {
const dispatch = useAppDispatch();
const settings = useAppSelector((state) => state.settings);
Expand Down Expand Up @@ -31,6 +41,12 @@ export const usePaletteMode = () => {
secondary: {
main: "#ff1744",
},
languageSwitch: {
100: '#E5EAF2',
300: '#C7D0DD',
800: '#303740',
900: '#1C2025',
},
mode: settings.paletteMode,
},
typography: {
Expand Down
16 changes: 10 additions & 6 deletions frontend/src/store/slices/commentsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ export const commentsSlice = createSlice({
const { fake, ind, m } = action.payload;
const nightmare = m === 2;

const addAdditionalCardAttributes = (card: number) => {
return {
...criteriaCardPool.find((cc) => cc.id === card)!,
nightmare
}
}

for (let i = 0; i < ind.length; i++) {
if (fake) {
const cards = [ind[i], fake[i]];
Expand All @@ -65,8 +72,8 @@ export const commentsSlice = createSlice({
verifier: verifiers[i],
nightmare,
criteriaCards: [
criteriaCardPool.find((cc) => cc.id === shuffledCards[0])!,
criteriaCardPool.find((cc) => cc.id === shuffledCards[1])!,
addAdditionalCardAttributes(shuffledCards[0]),
addAdditionalCardAttributes(shuffledCards[1]),
],
letters: createLetters(ind.length, verifiers[i], nightmare),
});
Expand All @@ -77,10 +84,7 @@ export const commentsSlice = createSlice({
verifier: verifiers[i],
nightmare,
criteriaCards: [
{
...criteriaCardPool.find((cc) => cc.id === card)!,
nightmare,
},
addAdditionalCardAttributes(card),
],
letters: createLetters(ind.length, verifiers[i], nightmare),
});
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/store/slices/settingsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { createSlice } from "@reduxjs/toolkit";
export type SettingsState = {
paletteMode: PaletteMode;
storeVersion: number;
language: string;
};

const initialState: SettingsState = {
paletteMode: "light",
storeVersion: parseInt(process.env.REACT_APP_STORE_VERSION),
language: "EN",
};

export const settingsSlice = createSlice({
Expand All @@ -17,6 +19,9 @@ export const settingsSlice = createSlice({
togglePaletteMode: (state) => {
state.paletteMode = state.paletteMode === "light" ? "dark" : "light";
},
updateLanguage: (state, action) => {
state.language = action.payload
}
},
});

Expand Down
Loading

0 comments on commit e4d6c90

Please sign in to comment.