├── packages ├── .gitkeep ├── frontend │ ├── CNAME │ ├── .env.development │ ├── .env.production │ ├── README.md │ ├── public │ │ ├── favicon.png │ │ ├── favicon.zip │ │ ├── favicon │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── site.webmanifest │ │ │ └── about.txt │ │ └── global.css │ ├── package.json │ ├── src │ │ ├── main.ts │ │ ├── challenge │ │ │ ├── api │ │ │ │ ├── getDailyChallenge.ts │ │ │ │ └── submitAnswer.ts │ │ │ ├── DisappearingButton.svelte │ │ │ ├── ChallengeHints.svelte │ │ │ └── Challenge.svelte │ │ ├── api │ │ │ └── index.ts │ │ └── App.svelte │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── vitest.config.ts │ ├── svelte.config.cjs │ ├── .eslintrc.js │ ├── index.html │ ├── tsconfig.json │ └── project.json ├── common │ ├── src │ │ ├── lib │ │ │ ├── common.ts │ │ │ └── common.spec.ts │ │ ├── routes.enum.ts │ │ ├── Answer.ts │ │ ├── index.ts │ │ ├── Challenge.ts │ │ ├── themes.ts │ │ ├── textComparison.ts │ │ ├── levenstein.ts │ │ └── challenges.ts │ ├── package.json │ ├── README.md │ ├── tsconfig.spec.json │ ├── tsconfig.lib.json │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── tsconfig.json │ └── project.json └── backend │ ├── src │ ├── environments │ │ ├── environment.ts │ │ └── environment.prod.ts │ └── server.ts │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tsconfig.app.json │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ └── project.json ├── tools ├── generators │ └── .gitkeep └── tsconfig.tools.json ├── .prettierrc ├── .vscode ├── settings.json └── extensions.json ├── concept-cheatsheet.pdf ├── .prettierignore ├── jest.preset.js ├── jest.config.ts ├── vitest.config.ts ├── .editorconfig ├── tsconfig.base.json ├── .gitignore ├── .eslintrc.json ├── nx.json ├── .github └── workflows │ └── publish-github-page.yml └── package.json /packages/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /packages/frontend/CNAME: -------------------------------------------------------------------------------- 1 | ijome.nans-dumortier.com 2 | -------------------------------------------------------------------------------- /packages/frontend/.env.development: -------------------------------------------------------------------------------- 1 | VITE_API_URL=http://localhost:3000 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "ijome" 4 | ] 5 | } -------------------------------------------------------------------------------- /packages/frontend/.env.production: -------------------------------------------------------------------------------- 1 | VITE_API_URL=https://ijome-backend.onrender.com -------------------------------------------------------------------------------- /packages/frontend/README.md: -------------------------------------------------------------------------------- 1 | # Frontend for ijome 2 | 3 | This is a svelte app. 4 | -------------------------------------------------------------------------------- /concept-cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/concept-cheatsheet.pdf -------------------------------------------------------------------------------- /packages/common/src/lib/common.ts: -------------------------------------------------------------------------------- 1 | export function common(): string { 2 | return 'common'; 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /packages/backend/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | }; 4 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /packages/backend/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /packages/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ijome/common", 3 | "version": "0.0.1", 4 | "type": "commonjs" 5 | } 6 | -------------------------------------------------------------------------------- /packages/frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon.png -------------------------------------------------------------------------------- /packages/frontend/public/favicon.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon.zip -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nrwl/jest'; 2 | 3 | export default { 4 | projects: getJestProjects(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/frontend/public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon/favicon.ico -------------------------------------------------------------------------------- /packages/common/src/routes.enum.ts: -------------------------------------------------------------------------------- 1 | export enum Routes { 2 | DAILY_CHALLENGE = 'daily/challenge', 3 | DAILY_ANSWER = 'daily/answer' 4 | } -------------------------------------------------------------------------------- /packages/frontend/public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /packages/frontend/public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /packages/frontend/public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /packages/common/src/Answer.ts: -------------------------------------------------------------------------------- 1 | 2 | export type Answer = { 3 | answer: string 4 | } 5 | 6 | export type AnswerResponse = { 7 | correct: boolean, 8 | } 9 | -------------------------------------------------------------------------------- /packages/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "emojis-list": "^3.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import App from './App.svelte'; 2 | 3 | const app = new App({ 4 | target: document.body, 5 | }); 6 | 7 | export default app; 8 | -------------------------------------------------------------------------------- /packages/frontend/public/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /packages/frontend/public/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NansD/ijome/main/packages/frontend/public/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /packages/common/src/lib/common.spec.ts: -------------------------------------------------------------------------------- 1 | import { common } from './common'; 2 | 3 | describe('common', () => { 4 | it('should work', () => { 5 | expect(common()).toEqual('common'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "esbenp.prettier-vscode", 5 | "firsttris.vscode-jest-runner", 6 | "dbaeumer.vscode-eslint" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | plugins: [], 5 | test: { 6 | globals: true, 7 | environment: 'jsdom', 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/common/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/common'; 2 | export * from './routes.enum'; 3 | export * from './Challenge'; 4 | export * from './Answer'; 5 | export * from './challenges'; 6 | export * from './textComparison' -------------------------------------------------------------------------------- /packages/frontend/src/challenge/api/getDailyChallenge.ts: -------------------------------------------------------------------------------- 1 | import { ChallengeDTO, getTodaysChallenge } from '@ijome/common'; 2 | export async function getDailyChallenge(): Promise { 3 | return getTodaysChallenge(); 4 | } 5 | -------------------------------------------------------------------------------- /packages/frontend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | 4 | "compilerOptions": { 5 | "outDir": "../../dist/out-tsc" 6 | }, 7 | 8 | "include": ["src/**/*"], 9 | "exclude": ["**/*.spec.ts", "**/*_spec.ts", "public/*"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/frontend/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["**/*.spec.ts", "**/*.spec.js", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/frontend/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vite'; 2 | import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 | import baseConfig from '../../vitest.config'; 4 | 5 | export default mergeConfig(baseConfig, { 6 | plugins: [svelte({ hot: !process.env.VITEST })], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- 1 | # common 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build common` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test common` to execute the unit tests via [Jest](https://jestjs.io). 12 | -------------------------------------------------------------------------------- /packages/common/src/Challenge.ts: -------------------------------------------------------------------------------- 1 | export interface Challenge { 2 | challenge: string, 3 | theme: string, 4 | subThemes?: { 5 | challenge: string, 6 | theme: string, 7 | }[], 8 | possibleSolutions: string[] 9 | } 10 | 11 | export type ChallengeDTO = Omit; -------------------------------------------------------------------------------- /packages/common/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/frontend/public/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /packages/backend/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/backend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"] 7 | }, 8 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"], 9 | "include": ["**/*.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/common/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["**/*.ts"], 9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/frontend/svelte.config.cjs: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require('svelte-preprocess'); 2 | 3 | module.exports = { 4 | // Consult https://github.com/sveltejs/svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: sveltePreprocess(), 7 | base: '/ijome', 8 | paths: { 9 | base: '/ijome', 10 | assets: '/assets' 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/frontend/src/challenge/api/submitAnswer.ts: -------------------------------------------------------------------------------- 1 | import { Answer, AnswerResponse, compare, getTodaysChallenge } from "@ijome/common"; 2 | 3 | export async function submitAnswer({ answer }: Answer): Promise { 4 | const challenge = getTodaysChallenge(); 5 | if (challenge.possibleSolutions.some(p => compare(p, answer))) return { correct: true }; 6 | return { correct: false }; 7 | } 8 | -------------------------------------------------------------------------------- /packages/backend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/common/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/common/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'common', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | transform: { 11 | '^.+\\.[tj]s$': 'ts-jest', 12 | }, 13 | moduleFileExtensions: ['ts', 'js', 'html'], 14 | coverageDirectory: '../../coverage/packages/common', 15 | }; 16 | -------------------------------------------------------------------------------- /packages/frontend/public/favicon/about.txt: -------------------------------------------------------------------------------- 1 | This favicon was generated using the following graphics from Twitter Twemoji: 2 | 3 | - Graphics Title: 1f389.svg 4 | - Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji) 5 | - Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/1f389.svg 6 | - Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/) 7 | -------------------------------------------------------------------------------- /packages/backend/README.md: -------------------------------------------------------------------------------- 1 | # Local development 2 | 3 | First of all, install every dependency : 4 | 5 | ```shell 6 | yarn 7 | ``` 8 | 9 | Then, start the backend server : 10 | 11 | ```shell 12 | nx serve backend 13 | ``` 14 | 15 | Or, if `nx` is not installed globally on your machine : 16 | 17 | ```shell 18 | npx nx serve backend 19 | ``` 20 | 21 | Don't forget to run linter before pushing : 22 | 23 | ```shell 24 | nx lint 25 | ``` -------------------------------------------------------------------------------- /packages/backend/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'backend', 4 | preset: '../../jest.preset.js', 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | }, 9 | }, 10 | testEnvironment: 'node', 11 | transform: { 12 | '^.+\\.[tj]s$': 'ts-jest', 13 | }, 14 | moduleFileExtensions: ['ts', 'js', 'html'], 15 | coverageDirectory: '../../coverage/packages/backend', 16 | }; 17 | -------------------------------------------------------------------------------- /packages/frontend/src/challenge/DisappearingButton.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | {#if showText} 8 |

{textToShow}

9 | {:else} 10 | 11 | {/if} -------------------------------------------------------------------------------- /packages/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/frontend/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export const API_URL = import.meta.env.VITE_API_URL; 2 | 3 | export async function queryAndReturnBody(url: string) { 4 | const fetchResult = await fetch(url); 5 | const result = await fetchResult.json(); 6 | return result; 7 | } 8 | 9 | export async function postData(url = '', data = {}) { 10 | const response = await fetch(url, { 11 | method: 'POST', 12 | headers: { 13 | 'Content-Type': 'application/json' 14 | }, 15 | redirect: 'follow', 16 | body: JSON.stringify(data) 17 | }); 18 | return response.json(); 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2017", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@ijome/common": ["packages/common/src/index.ts"] 19 | } 20 | }, 21 | "exclude": ["node_modules", "tmp"] 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /packages/frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: ['svelte3', '@typescript-eslint'], 4 | extends: ['../../.eslintrc.json'], 5 | ignorePatterns: ['!**/*', 'vitest.config.ts'], 6 | overrides: [ 7 | { 8 | files: ['*.ts', '*.js', '*.svelte'], 9 | parserOptions: { 10 | project: ['packages/frontend/tsconfig.*?.json'], 11 | }, 12 | rules: {}, 13 | }, 14 | { 15 | files: ['*.ts', '*.tsx'], 16 | rules: {}, 17 | }, 18 | { 19 | files: ['*.js', '*.jsx'], 20 | rules: {}, 21 | }, 22 | { 23 | files: ['*.svelte'], 24 | processor: 'svelte3/svelte3', 25 | }, 26 | ], 27 | settings: { 28 | 'svelte3/typescript': require('typescript'), 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/common/src/themes.ts: -------------------------------------------------------------------------------- 1 | // ouais c'est un peu moche de tout avoir en doublon, 2 | // mais si on fait enum truc { 'ma clé' }, la valeur JS de truc['ma clé'] c'est 0 et non une chaine de caractères 3 | // on trouvera sûrement un truc plus joli à faire en tout cas 4 | 5 | 6 | 7 | // this enum is based off concept-cheatsheet.pdf 8 | export enum Themes { 9 | 'Object, Paquet, Carton' = 'Object, Paquet, Carton', 10 | 'Télévision, Émission, Série' = 'Télévision, Émission, Série', 11 | 'Littérature, Écriture, Livre' = 'Littérature, Écriture, Livre', 12 | 'Expression, Langue, Dialogue - Bande Dessinée' = 'Expression, Langue, Dialogue - Bande Dessinée', 13 | 'Rébus' = 'Rébus', 14 | 'Lieu, Pays, Drapeau' = 'Lieu, Pays, Drapeau', 15 | 'Date, Événement, Jour' = 'Date, Événement, Jour', 16 | 'Cinéma, Film, Caméra' = 'Cinéma, Film, Caméra' 17 | } -------------------------------------------------------------------------------- /packages/frontend/public/global.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | position: relative; 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | body { 9 | color: #333; 10 | margin: 0; 11 | box-sizing: border-box; 12 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 13 | Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; 14 | } 15 | 16 | a { 17 | color: rgb(0, 100, 200); 18 | text-decoration: none; 19 | } 20 | 21 | a:hover { 22 | text-decoration: underline; 23 | } 24 | 25 | a:visited { 26 | color: rgb(0, 80, 160); 27 | } 28 | 29 | label { 30 | display: block; 31 | } 32 | 33 | input, 34 | button, 35 | select, 36 | textarea { 37 | font-family: inherit; 38 | font-size: inherit; 39 | -webkit-padding: 0.4em 0; 40 | padding: 0.4em; 41 | margin: 0 0 0.5em 0; 42 | box-sizing: border-box; 43 | border: 1px solid #ccc; 44 | border-radius: 2px; 45 | } 46 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "rules": { 6 | "semi": "error" 7 | }, 8 | "overrides": [ 9 | { 10 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 11 | "rules": { 12 | "@nrwl/nx/enforce-module-boundaries": [ 13 | "error", 14 | { 15 | "enforceBuildableLibDependency": true, 16 | "allow": [], 17 | "depConstraints": [ 18 | { 19 | "sourceTag": "*", 20 | "onlyDependOnLibsWithTags": ["*"] 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | }, 27 | { 28 | "files": ["*.ts", "*.tsx"], 29 | "extends": ["plugin:@nrwl/nx/typescript"], 30 | "rules": {} 31 | }, 32 | { 33 | "files": ["*.js", "*.jsx"], 34 | "extends": ["plugin:@nrwl/nx/javascript"], 35 | "rules": {} 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /packages/common/src/textComparison.ts: -------------------------------------------------------------------------------- 1 | import { levenstein } from './levenstein' 2 | 3 | function clean(text: string) { 4 | return text 5 | // Remove special characters 6 | .replace(/[^a-zA-Z0-9 ]/g, '') 7 | // Replaces multiple successive white spaces by one white space 8 | .replace(/\s+/g, ' ') 9 | .trim() 10 | .toLowerCase(); 11 | } 12 | 13 | function compare(text1: string, text2: string) { 14 | const cleanedText1 = clean(text1); 15 | const cleanedText2 = clean(text2); 16 | const distance = levenstein(cleanedText1,cleanedText2); 17 | /* 18 | { 19 | // In these options, 0 means we are totally allowing it, 1 means we are very strict about it 20 | insertion_cost: 0.2, // We allow a lot of additions, to prevent being too harsh with someone adding parasite words like "the", "of" etc 21 | deletion_cost: 1, 22 | substitution_cost: 0.8 // Allows replacing a couple of letters by others, e.g. keyboard fail 23 | } 24 | */ 25 | if (distance <= 2) return true; 26 | return false; 27 | } 28 | 29 | export { compare }; -------------------------------------------------------------------------------- /packages/common/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "common", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/common/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nrwl/js:tsc", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "dist/packages/common", 12 | "main": "packages/common/src/index.ts", 13 | "tsConfig": "packages/common/tsconfig.lib.json", 14 | "assets": ["packages/common/*.md"] 15 | } 16 | }, 17 | "lint": { 18 | "executor": "@nrwl/linter:eslint", 19 | "outputs": ["{options.outputFile}"], 20 | "options": { 21 | "lintFilePatterns": ["packages/common/**/*.ts"] 22 | } 23 | }, 24 | "test": { 25 | "executor": "@nrwl/jest:jest", 26 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 27 | "options": { 28 | "jestConfig": "packages/common/jest.config.ts", 29 | "passWithNoTests": true 30 | } 31 | } 32 | }, 33 | "tags": [] 34 | } 35 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 3 | "npmScope": "ijome", 4 | "tasksRunnerOptions": { 5 | "default": { 6 | "runner": "nx/tasks-runners/default", 7 | "options": { 8 | "cacheableOperations": ["build", "lint", "test", "e2e"] 9 | } 10 | } 11 | }, 12 | "targetDefaults": { 13 | "build": { 14 | "dependsOn": ["^build"], 15 | "inputs": ["production", "^production"] 16 | }, 17 | "test": { 18 | "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"] 19 | }, 20 | "lint": { 21 | "inputs": ["default", "{workspaceRoot}/.eslintrc.json"] 22 | } 23 | }, 24 | "namedInputs": { 25 | "default": ["{projectRoot}/**/*", "sharedGlobals"], 26 | "production": [ 27 | "default", 28 | "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", 29 | "!{projectRoot}/tsconfig.spec.json", 30 | "!{projectRoot}/jest.config.[jt]s", 31 | "!{projectRoot}/.eslintrc.json" 32 | ], 33 | "sharedGlobals": [] 34 | }, 35 | "workspaceLayout": { 36 | "appsDir": "packages", 37 | "libsDir": "packages" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 19 | 20 | 21 | Ijome 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | 4 | "compilerOptions": { 5 | "moduleResolution": "node", 6 | "target": "es2017", 7 | /** 8 | Svelte Preprocess cannot figure out whether you have a value or a type, so tell TypeScript 9 | to enforce using `import type` instead of `import` for Types. 10 | */ 11 | "importsNotUsedAsValues": "error", 12 | "isolatedModules": true, 13 | /** 14 | To have warnings/errors of the Svelte compiler at the correct position, 15 | enable source maps by default. 16 | */ 17 | "sourceMap": true, 18 | /** Requests the runtime types from the svelte modules by default. Needed for TS files or else you get errors. */ 19 | "types": ["svelte", "vite/client"], 20 | 21 | "strict": false, 22 | "esModuleInterop": true, 23 | "skipLibCheck": true, 24 | "forceConsistentCasingInFileNames": true, 25 | /** Needed for the vite-tsconfig-paths vite plugin. */ 26 | "checkJs": true 27 | }, 28 | "files": [], 29 | "include": [], 30 | "references": [ 31 | { 32 | "path": "./tsconfig.app.json" 33 | }, 34 | { 35 | "path": "./tsconfig.spec.json" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /packages/backend/src/server.ts: -------------------------------------------------------------------------------- 1 | import fastify from 'fastify'; 2 | import cors from '@fastify/cors'; 3 | import { Answer, AnswerResponse, ChallengeDTO, getTodaysChallenge } from '@ijome/common'; 4 | import { compare } from '@ijome/common'; 5 | 6 | const server = fastify({ logger: true }); 7 | 8 | server.register(cors, { 9 | origin: '*' 10 | }); 11 | 12 | server.get('/daily/challenge', (): ChallengeDTO => { 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | const { possibleSolutions, ...challenge } = getTodaysChallenge(); 15 | return challenge; 16 | }); 17 | 18 | const answerSchema = { 19 | body: { 20 | type: 'object', 21 | required: ['answer'], 22 | properties: { 23 | answer: { type: 'string' } 24 | } 25 | } 26 | }; 27 | 28 | server.post<{ Body: Answer }>('/daily/answer', { 29 | schema: answerSchema, 30 | }, 31 | (request): AnswerResponse => { 32 | const challenge = getTodaysChallenge(); 33 | if (challenge.possibleSolutions.find(p => compare(p, request.body.answer))) return { correct: true }; 34 | return { correct: false }; 35 | } 36 | ); 37 | 38 | const start = async () => { 39 | try { 40 | await server.listen({ port: process.env.PORT ? Number(process.env.PORT) : 3000, host: '0.0.0.0' }); 41 | } catch (err) { 42 | server.log.error(err); 43 | process.exit(1); 44 | } 45 | }; 46 | start(); 47 | -------------------------------------------------------------------------------- /packages/frontend/src/challenge/ChallengeHints.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 |
19 | Indice(s) : 20 |
21 | {#each hints as hint, index} 22 |
26 | #{index + 1}   27 | {#if hint.show} 28 | {hint.theme} 29 | {:else} 30 | (hint.show = true)} 32 | showText={hint.show} 33 | textToShow={hint.theme} 34 | /> 35 | {/if} 36 |
37 | {/each} 38 |
39 |
40 | 41 | 48 | -------------------------------------------------------------------------------- /.github/workflows/publish-github-page.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | node-version: [16.x] 18 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | cache: 'yarn' 27 | - run: yarn 28 | - run: yarn nx build frontend --configuration=production && cp ./packages/frontend/CNAME dist/packages/frontend 29 | - name: Push 30 | uses: s0/git-publish-subdir-action@develop 31 | env: 32 | REPO: self 33 | BRANCH: build # The branch name where you want to push the assets 34 | FOLDER: dist/packages/frontend # The directory where your assets are generated 35 | GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} # GitHub will automatically add this - you don't need to bother getting a token 36 | MESSAGE: "Build: ({sha}) {msg}" # The commit message 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ijome", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "clean": "rm -rf node_modules && rm -rf dist && yarn" 7 | }, 8 | "engines": { 9 | "node": ">=16 <17" 10 | }, 11 | "private": true, 12 | "homepage": "https://nansd.github.io/ijome/", 13 | "devDependencies": { 14 | "@nrwl/cli": "15.0.4", 15 | "@nrwl/cypress": "15.0.4", 16 | "@nrwl/eslint-plugin-nx": "14.8.6", 17 | "@nrwl/jest": "15.0.4", 18 | "@nrwl/js": "15.0.4", 19 | "@nrwl/linter": "15.0.4", 20 | "@nrwl/node": "15.0.4", 21 | "@nrwl/workspace": "15.0.4", 22 | "@nxext/svelte": "^14.0.2", 23 | "@sveltejs/vite-plugin-svelte": "^1.0.1", 24 | "@testing-library/svelte": "^3.1.3", 25 | "@tsconfig/svelte": "^3.0.0", 26 | "@types/jest": "28.1.1", 27 | "@types/natural": "^5.1.1", 28 | "@types/node": "18.7.1", 29 | "@typescript-eslint/eslint-plugin": "^5.36.1", 30 | "@typescript-eslint/parser": "^5.36.1", 31 | "@vitest/ui": "^0.9.3", 32 | "c8": "^7.12.0", 33 | "cypress": "^10.7.0", 34 | "eslint": "~8.15.0", 35 | "eslint-config-prettier": "8.1.0", 36 | "eslint-plugin-cypress": "^2.10.3", 37 | "eslint-plugin-svelte3": "^4.0.0", 38 | "jest": "28.1.1", 39 | "jest-environment-jsdom": "28.1.1", 40 | "nx": "15.0.4", 41 | "prettier": "^2.6.2", 42 | "svelte": "^3.49.0", 43 | "svelte-check": "^2.8.0", 44 | "svelte-jester": "^2.3.2", 45 | "svelte-preprocess": "^4.10.7", 46 | "ts-jest": "28.0.5", 47 | "ts-node": "10.9.1", 48 | "typescript": "~4.8.2", 49 | "vitest": "^0.19.1" 50 | }, 51 | "dependencies": { 52 | "@fastify/cors": "^8.1.1", 53 | "@sveltestack/svelte-query": "^1.6.0", 54 | "fastify": "^4.9.2", 55 | "natural": "^5.2.3", 56 | "svelte-confetti": "^1.2.0", 57 | "tslib": "^2.3.0" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/backend/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/backend/src", 5 | "projectType": "application", 6 | "targets": { 7 | "build": { 8 | "executor": "@nrwl/webpack:webpack", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "target": "node", 12 | "compiler": "tsc", 13 | "outputPath": "dist/packages/backend", 14 | "main": "packages/backend/src/server.ts", 15 | "tsConfig": "packages/backend/tsconfig.app.json" 16 | }, 17 | "configurations": { 18 | "production": { 19 | "optimization": true, 20 | "extractLicenses": true, 21 | "inspect": false, 22 | "fileReplacements": [ 23 | { 24 | "replace": "packages/backend/src/environments/environment.ts", 25 | "with": "packages/backend/src/environments/environment.prod.ts" 26 | } 27 | ] 28 | } 29 | } 30 | }, 31 | "serve": { 32 | "executor": "@nrwl/js:node", 33 | "options": { 34 | "buildTarget": "backend:build" 35 | }, 36 | "configurations": { 37 | "production": { 38 | "buildTarget": "backend:build:production" 39 | } 40 | } 41 | }, 42 | "lint": { 43 | "executor": "@nrwl/linter:eslint", 44 | "outputs": ["{options.outputFile}"], 45 | "options": { 46 | "lintFilePatterns": ["packages/backend/**/*.ts"] 47 | } 48 | }, 49 | "test": { 50 | "executor": "@nrwl/jest:jest", 51 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 52 | "options": { 53 | "jestConfig": "packages/backend/jest.config.ts", 54 | "passWithNoTests": true 55 | } 56 | } 57 | }, 58 | "tags": [] 59 | } 60 | -------------------------------------------------------------------------------- /packages/frontend/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/frontend/src", 5 | "projectType": "application", 6 | "tags": [], 7 | "targets": { 8 | "build": { 9 | "executor": "@nxext/vite:build", 10 | "outputs": ["{options.outputPath}"], 11 | "options": { 12 | "frameworkConfigFile": "@nxext/svelte/plugins/vite", 13 | "outputPath": "dist/packages/frontend", 14 | "assets": [ 15 | { 16 | "glob": "/*", 17 | "input": "./public/**", 18 | "output": "./" 19 | } 20 | ], 21 | "tsConfig": "packages/frontend/tsconfig.app.json" 22 | }, 23 | "configurations": { 24 | "production": {} 25 | } 26 | }, 27 | "serve": { 28 | "executor": "@nxext/vite:dev", 29 | "options": { 30 | "frameworkConfigFile": "@nxext/svelte/plugins/vite", 31 | "outputPath": "dist/packages/frontend", 32 | "assets": [ 33 | { 34 | "glob": "/*", 35 | "input": "./public/**", 36 | "output": "./" 37 | } 38 | ], 39 | "tsConfig": "packages/frontend/tsconfig.app.json" 40 | } 41 | }, 42 | "lint": { 43 | "executor": "@nrwl/linter:eslint", 44 | "outputs": ["{options.outputFile}"], 45 | "options": { 46 | "lintFilePatterns": ["packages/frontend/**/*.{ts,svelte,spec.ts}"] 47 | } 48 | }, 49 | "check": { 50 | "executor": "@nrwl/workspace:run-commands", 51 | "options": { 52 | "command": "svelte-check", 53 | "cwd": "packages/frontend" 54 | } 55 | }, 56 | "test": { 57 | "executor": "@nxext/vitest:vitest", 58 | "options": { 59 | "vitestConfig": "packages/frontend/vitest.config.ts" 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/common/src/levenstein.ts: -------------------------------------------------------------------------------- 1 | // copied from stackoverflow 🤷‍♂️ 2 | export function levenstein(s: string, t: string) { 3 | if (s === t) { 4 | return 0; 5 | } 6 | const n = s.length, m = t.length; 7 | if (n === 0 || m === 0) { 8 | return n + m; 9 | } 10 | let x = 0, y, a, b, c, d, g, h = 0; 11 | const p = new Uint16Array(n); 12 | const u = new Uint32Array(n); 13 | for (y = 0; y < n;) { 14 | u[y] = s.charCodeAt(y); 15 | p[y] = ++y; 16 | } 17 | 18 | for (; (x + 3) < m; x += 4) { 19 | const e1 = t.charCodeAt(x); 20 | const e2 = t.charCodeAt(x + 1); 21 | const e3 = t.charCodeAt(x + 2); 22 | const e4 = t.charCodeAt(x + 3); 23 | c = x; 24 | b = x + 1; 25 | d = x + 2; 26 | g = x + 3; 27 | h = x + 4; 28 | for (y = 0; y < n; y++) { 29 | a = p[y]; 30 | if (a < c || b < c) { 31 | c = (a > b ? b + 1 : a + 1); 32 | } 33 | else { 34 | if (e1 !== u[y]) { 35 | c++; 36 | } 37 | } 38 | 39 | if (c < b || d < b) { 40 | b = (c > d ? d + 1 : c + 1); 41 | } 42 | else { 43 | if (e2 !== u[y]) { 44 | b++; 45 | } 46 | } 47 | 48 | if (b < d || g < d) { 49 | d = (b > g ? g + 1 : b + 1); 50 | } 51 | else { 52 | if (e3 !== u[y]) { 53 | d++; 54 | } 55 | } 56 | 57 | if (d < g || h < g) { 58 | g = (d > h ? h + 1 : d + 1); 59 | } 60 | else { 61 | if (e4 !== u[y]) { 62 | g++; 63 | } 64 | } 65 | p[y] = h = g; 66 | g = d; 67 | d = b; 68 | b = c; 69 | c = a; 70 | } 71 | } 72 | 73 | for (; x < m;) { 74 | const e = t.charCodeAt(x); 75 | c = x; 76 | d = ++x; 77 | for (y = 0; y < n; y++) { 78 | a = p[y]; 79 | if (a < c || d < c) { 80 | d = (a > d ? d + 1 : a + 1); 81 | } 82 | else { 83 | if (e !== u[y]) { 84 | d = c + 1; 85 | } 86 | else { 87 | d = c; 88 | } 89 | } 90 | p[y] = d; 91 | c = a; 92 | } 93 | h = d; 94 | } 95 | 96 | return h; 97 | } -------------------------------------------------------------------------------- /packages/frontend/src/App.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 12 | 13 |
14 |

Ijome {emoji}

15 |

Devinez des concepts à partir d'émojis!

16 |
17 | 18 |
19 | 20 |
21 | 22 | 176 | -------------------------------------------------------------------------------- /packages/frontend/src/challenge/Challenge.svelte: -------------------------------------------------------------------------------- 1 | 40 | 41 |
45 |
46 | {#if $queryResult.isLoading} 47 |
48 |
49 |
50 |
51 |
52 |
53 | {:else} 54 |

Challenge du jour

55 | {$queryResult.data?.challenge} 56 | 57 | {/if} 58 |
59 |
60 | 61 | 71 | 72 | {#if isCorrect} 73 |
74 | 75 | 81 | 88 | 95 |

96 | Félicitations 🥳 ! On se retrouve demain pour la prochaine partie ! 97 |

98 |
99 | {/if} 100 |
101 |
102 | 103 |
106 | {#each tries as tentative, index} 107 |
110 | 111 | #{index + 1} 112 | 113 | 114 | {tentative.answer} 115 | 116 | {#if tentative.success} 117 |

Succès ✅

118 | {:else} 119 |

Loupé ❌

120 | {/if} 121 |
122 | {/each} 123 |
124 | 125 | 166 | -------------------------------------------------------------------------------- /packages/common/src/challenges.ts: -------------------------------------------------------------------------------- 1 | import { Challenge } from './Challenge' 2 | import { Themes } from "./themes"; 3 | 4 | /** 5 | * Write the least possible words necessary for the solution to be correct, 6 | * avoid parasite words like "the", "my" etc unless they are VERY important 7 | * for the solution to be accepted 8 | */ 9 | export const challenges: Challenge[] = [ 10 | { 11 | challenge: '🐀👨‍🍳', 12 | theme: Themes['Télévision, Émission, Série'], 13 | possibleSolutions: ['ratatouille'] 14 | }, 15 | { 16 | challenge: '🐺🦷⬜', 17 | theme: Themes['Littérature, Écriture, Livre'], 18 | possibleSolutions: ['croc blanc'] 19 | }, 20 | { 21 | challenge: '🦶🦶🍽️', 22 | theme: Themes['Expression, Langue, Dialogue - Bande Dessinée'], 23 | possibleSolutions: ['mettre les pieds dans le plat'] 24 | }, 25 | { 26 | challenge: '🥚🐄', 27 | theme: Themes['Expression, Langue, Dialogue - Bande Dessinée'], 28 | possibleSolutions: ['qui vole un oeuf vole un boeuf'] 29 | }, 30 | { 31 | challenge: '🎲🥘🏊‍♂️🤥', 32 | theme: Themes['Rébus'], 33 | possibleSolutions: ['déménagement'] 34 | }, 35 | { 36 | challenge: '⬆️🤥🗣', 37 | theme: Themes['Rébus'], 38 | subThemes: [{ 39 | theme: Themes['Lieu, Pays, Drapeau'], 40 | challenge: '🟦⬜🟥' 41 | }], 42 | possibleSolutions: ['normandie'] 43 | }, 44 | { 45 | challenge: '🎲🪑👑', 46 | theme: Themes['Télévision, Émission, Série'], 47 | possibleSolutions: ['game throne', 'trone fer', 'throne fer'] 48 | }, 49 | { 50 | challenge: '🗓🌦🧥🪡 ', 51 | theme: Themes['Expression, Langue, Dialogue - Bande Dessinée'], 52 | possibleSolutions: ['en avril ne te découvre pas d\'un fil', 'avril découvre fil'] 53 | }, 54 | { 55 | challenge: '🌽🥀🪺', 56 | theme: Themes['Rébus'], 57 | subThemes: [{ 58 | theme: Themes['Date, Événement, Jour'], 59 | challenge: '1' 60 | }], 61 | possibleSolutions: ['epiphanie', 'epifanie'] 62 | }, 63 | { 64 | challenge: '✝️ 🪺🥤', 65 | theme: Themes['Rébus'], 66 | subThemes: [{ 67 | theme: Themes['Date, Événement, Jour'], 68 | challenge: '🎅' 69 | }], 70 | possibleSolutions: ['st nicolas', 'saint nicolas'] 71 | }, 72 | { 73 | challenge: '🔌🏛⚔️🎆', 74 | theme: Themes['Rébus'], 75 | subThemes: [{ 76 | theme: Themes['Date, Événement, Jour'], 77 | challenge: '14' 78 | }], 79 | possibleSolutions: ['prise bastille', 'prise de la bastille'] 80 | }, 81 | { 82 | challenge: '🦃🇺🇸🙏', 83 | theme: Themes['Date, Événement, Jour'], 84 | possibleSolutions: ['thanksgiving'] 85 | }, 86 | { 87 | challenge: '🍻 🍀 🌈 ✝️', 88 | theme: Themes['Date, Événement, Jour'], 89 | possibleSolutions: ['st patrick', 'saint patrick'] 90 | }, 91 | { 92 | challenge: '🪑👨🗳️🍫', 93 | theme: Themes['Cinéma, Film, Caméra'], 94 | possibleSolutions: ['forest gump', 'forrest gump'] 95 | }, 96 | { 97 | "challenge": "🦁👑", 98 | "theme": Themes["Cinéma, Film, Caméra"], 99 | "possibleSolutions": ["le roi lion", "lion king"] 100 | }, 101 | { 102 | "challenge": "🦇👨‍🌆", 103 | "theme": Themes["Cinéma, Film, Caméra"], 104 | "possibleSolutions": ["batman"] 105 | }, 106 | { 107 | "challenge": "🔎🧔📜", 108 | "theme": Themes["Littérature, Écriture, Livre"], 109 | "possibleSolutions": ["sherlock holmes"] 110 | }, 111 | { 112 | "challenge": "👸❄️", 113 | "theme": Themes["Cinéma, Film, Caméra"], 114 | "possibleSolutions": ["la reine des neiges", "frozen"] 115 | }, 116 | { 117 | "challenge": "🧙‍♂️💍", 118 | "theme": Themes["Cinéma, Film, Caméra"], 119 | "possibleSolutions": ["le seigneur des anneaux", "lord of the rings"] 120 | }, 121 | { 122 | "challenge": "👠🛳️🧊", 123 | "theme": Themes["Cinéma, Film, Caméra"], 124 | "possibleSolutions": ["titanic"] 125 | }, 126 | { 127 | "challenge": "🍎🐍👫", 128 | "theme": Themes["Littérature, Écriture, Livre"], 129 | "possibleSolutions": ["adam et ève", "adam and eve"] 130 | }, 131 | { 132 | "challenge": "🧙‍♂️🪄👓⚡🎩", 133 | "theme": Themes["Littérature, Écriture, Livre"], 134 | "possibleSolutions": ["harry potter"] 135 | }, 136 | { 137 | "challenge": "🚢🧔‍♂️🏝️📖", 138 | "theme": Themes["Littérature, Écriture, Livre"], 139 | "possibleSolutions": ["robinson crusoe", "vendredi", "vendredi ou la vie sauvage"] 140 | }, 141 | { 142 | "challenge": "🧚🧒 🏴‍☠️🪝", 143 | "theme": Themes["Littérature, Écriture, Livre"], 144 | "possibleSolutions": ["peter pan"] 145 | }, 146 | { 147 | "challenge": "🐉🧙‍♂️", 148 | "theme": Themes["Cinéma, Film, Caméra"], 149 | "possibleSolutions": ["le hobbit", "the hobbit"] 150 | }, 151 | { 152 | "challenge": "👑💂‍♂️🫖", 153 | "theme": Themes["Lieu, Pays, Drapeau"], 154 | "possibleSolutions": ["royaume-uni", "united kingdom"] 155 | } 156 | ]; 157 | 158 | export function getTodaysChallenge() { 159 | const today = new Date().getDate(); 160 | const challenge = challenges[today]; 161 | if (!challenge) return challenges[today - challenges.length]; 162 | return challenge; 163 | } 164 | --------------------------------------------------------------------------------