diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
new file mode 100644
index 0000000..8116248
--- /dev/null
+++ b/.github/workflows/playwright.yml
@@ -0,0 +1,27 @@
+name: Playwright Tests
+on:
+ push:
+ branches: [ main, master ]
+ pull_request:
+ branches: [ main, master ]
+jobs:
+ test:
+ timeout-minutes: 60
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: lts/*
+ - name: Install dependencies
+ run: npm install -g pnpm && pnpm install
+ - name: Install Playwright Browsers
+ run: pnpm exec playwright install --with-deps
+ - name: Run Playwright tests
+ run: pnpm exec playwright test
+ - uses: actions/upload-artifact@v4
+ if: ${{ !cancelled() }}
+ with:
+ name: playwright-report
+ path: playwright-report/
+ retention-days: 30
diff --git a/.gitignore b/.gitignore
index a547bf3..6e8d72c 100755
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
+.env
+
node_modules
dist
dist-ssr
@@ -22,3 +24,10 @@ dist-ssr
*.njsproj
*.sln
*.sw?
+
+# Playwright
+/test-results/
+/playwright-report/
+/blob-report/
+/playwright/.cache/
+/playwright/.auth/
\ No newline at end of file
diff --git a/package.json b/package.json
index 513af9b..af8144e 100755
--- a/package.json
+++ b/package.json
@@ -11,12 +11,15 @@
"dependencies": {
"@floating-ui/react": "^0.26.9",
"@reduxjs/toolkit": "^1.9.5",
+ "@tanstack/react-query": "^5.90.21",
"axios": "^1.5.0",
"class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.1",
"emojibase": "^15.0.0",
"interweave": "^13.1.0",
"interweave-autolink": "^5.1.0",
"interweave-emoji": "^7.0.0",
+ "lucide-react": "^0.510.0",
"preact": "^10.16.0",
"react-redux": "^8.1.2",
"react-router-dom": "^6.16.0",
@@ -24,10 +27,13 @@
"react-textarea-autosize": "^8.5.3",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.4.2",
+ "tailwind-merge": "^3.5.0",
"yet-another-react-lightbox": "^3.12.2"
},
"devDependencies": {
+ "@playwright/test": "^1.58.2",
"@preact/preset-vite": "^2.5.0",
+ "@types/node": "^25.5.0",
"@types/react-redux": "^7.1.34",
"autoprefixer": "^10.4.15",
"postcss": "^8.4.28",
diff --git a/playwright.config.ts b/playwright.config.ts
new file mode 100644
index 0000000..be773d3
--- /dev/null
+++ b/playwright.config.ts
@@ -0,0 +1,80 @@
+///
+
+import { defineConfig, devices } from '@playwright/test';
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// import dotenv from 'dotenv';
+// import path from 'path';
+// dotenv.config({ path: path.resolve(__dirname, '.env') });
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ testDir: './tests',
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('')`. */
+ // baseURL: 'http://localhost:3000',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+
+ {
+ name: 'firefox',
+ use: { ...devices['Desktop Firefox'] },
+ },
+
+ {
+ name: 'webkit',
+ use: { ...devices['Desktop Safari'] },
+ },
+
+ /* Test against mobile viewports. */
+ // {
+ // name: 'Mobile Chrome',
+ // use: { ...devices['Pixel 5'] },
+ // },
+ // {
+ // name: 'Mobile Safari',
+ // use: { ...devices['iPhone 12'] },
+ // },
+
+ /* Test against branded browsers. */
+ // {
+ // name: 'Microsoft Edge',
+ // use: { ...devices['Desktop Edge'], channel: 'msedge' },
+ // },
+ // {
+ // name: 'Google Chrome',
+ // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
+ // },
+ ],
+
+ /* Run your local dev server before starting the tests */
+ // webServer: {
+ // command: 'npm run start',
+ // url: 'http://localhost:3000',
+ // reuseExistingServer: !process.env.CI,
+ // },
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5ebd9fd..b2af1e7 100755
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,12 +14,18 @@ importers:
'@reduxjs/toolkit':
specifier: ^1.9.5
version: 1.9.7(react-redux@8.1.3(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1))(react@18.2.0)
+ '@tanstack/react-query':
+ specifier: ^5.90.21
+ version: 5.90.21(react@18.2.0)
axios:
specifier: ^1.5.0
version: 1.6.7
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
emojibase:
specifier: ^15.0.0
version: 15.3.0
@@ -32,6 +38,9 @@ importers:
interweave-emoji:
specifier: ^7.0.0
version: 7.0.0(interweave@13.1.0(react@18.2.0))(react@18.2.0)
+ lucide-react:
+ specifier: ^0.510.0
+ version: 0.510.0(react@18.2.0)
preact:
specifier: ^10.16.0
version: 10.19.3
@@ -53,13 +62,22 @@ importers:
redux-thunk:
specifier: ^2.4.2
version: 2.4.2(redux@4.2.1)
+ tailwind-merge:
+ specifier: ^3.5.0
+ version: 3.5.0
yet-another-react-lightbox:
specifier: ^3.12.2
version: 3.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
devDependencies:
+ '@playwright/test':
+ specifier: ^1.58.2
+ version: 1.58.2
'@preact/preset-vite':
specifier: ^2.5.0
- version: 2.8.1(@babel/core@7.23.9)(preact@10.19.3)(vite@4.5.2)
+ version: 2.8.1(@babel/core@7.23.9)(preact@10.19.3)(vite@4.5.2(@types/node@25.5.0))
+ '@types/node':
+ specifier: ^25.5.0
+ version: 25.5.0
'@types/react-redux':
specifier: ^7.1.34
version: 7.1.34
@@ -77,7 +95,7 @@ importers:
version: 5.3.3
vite:
specifier: ^4.4.5
- version: 4.5.2
+ version: 4.5.2(@types/node@25.5.0)
packages:
@@ -441,6 +459,11 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
+ '@playwright/test@1.58.2':
+ resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
'@preact/preset-vite@2.8.1':
resolution: {integrity: sha512-a9KV4opdj17X2gOFuGup0aE+sXYABX/tJi/QDptOrleX4FlnoZgDWvz45tHOdVfrZX+3uvVsIYPHxRsTerkDNA==}
peerDependencies:
@@ -483,9 +506,20 @@ packages:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'}
+ '@tanstack/query-core@5.90.20':
+ resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==}
+
+ '@tanstack/react-query@5.90.21':
+ resolution: {integrity: sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==}
+ peerDependencies:
+ react: ^18 || ^19
+
'@types/hoist-non-react-statics@3.3.5':
resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==}
+ '@types/node@25.5.0':
+ resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==}
+
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -589,8 +623,8 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- caniuse-lite@1.0.30001580:
- resolution: {integrity: sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==}
+ caniuse-lite@1.0.30001754:
+ resolution: {integrity: sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==}
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
@@ -607,6 +641,10 @@ packages:
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
engines: {node: '>=6'}
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@@ -777,6 +815,11 @@ packages:
fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -923,6 +966,11 @@ packages:
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lucide-react@0.510.0:
+ resolution: {integrity: sha512-p8SQRAMVh7NhsAIETokSqDrc5CHnDLbV29mMnzaXx+Vc/hnqQzwI2r0FMWCcoTXnbw2KEjy48xwpGdEL+ck06Q==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
magic-string@0.30.5:
resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==}
engines: {node: '>=12'}
@@ -1028,6 +1076,16 @@ packages:
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
engines: {node: '>= 6'}
+ playwright-core@1.58.2:
+ resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.58.2:
+ resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==}
+ engines: {node: '>=18'}
+ hasBin: true
+
postcss-import@15.1.0:
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'}
@@ -1198,8 +1256,8 @@ packages:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
- scheduler@0.23.0:
- resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
+ scheduler@0.23.2:
+ resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
@@ -1260,6 +1318,9 @@ packages:
tabbable@6.2.0:
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
+ tailwind-merge@3.5.0:
+ resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==}
+
tailwindcss@3.4.1:
resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
engines: {node: '>=14.0.0'}
@@ -1288,6 +1349,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ undici-types@7.18.2:
+ resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
+
update-browserslist-db@1.0.13:
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
hasBin: true
@@ -1744,12 +1808,16 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
- '@preact/preset-vite@2.8.1(@babel/core@7.23.9)(preact@10.19.3)(vite@4.5.2)':
+ '@playwright/test@1.58.2':
+ dependencies:
+ playwright: 1.58.2
+
+ '@preact/preset-vite@2.8.1(@babel/core@7.23.9)(preact@10.19.3)(vite@4.5.2(@types/node@25.5.0))':
dependencies:
'@babel/core': 7.23.9
'@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.23.9)
'@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.23.9)
- '@prefresh/vite': 2.4.5(preact@10.19.3)(vite@4.5.2)
+ '@prefresh/vite': 2.4.5(preact@10.19.3)(vite@4.5.2(@types/node@25.5.0))
'@rollup/pluginutils': 4.2.1
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.23.9)
debug: 4.3.4
@@ -1757,7 +1825,7 @@ snapshots:
magic-string: 0.30.5
node-html-parser: 6.1.12
resolve: 1.22.8
- vite: 4.5.2
+ vite: 4.5.2(@types/node@25.5.0)
transitivePeerDependencies:
- preact
- supports-color
@@ -1770,7 +1838,7 @@ snapshots:
'@prefresh/utils@1.2.0': {}
- '@prefresh/vite@2.4.5(preact@10.19.3)(vite@4.5.2)':
+ '@prefresh/vite@2.4.5(preact@10.19.3)(vite@4.5.2(@types/node@25.5.0))':
dependencies:
'@babel/core': 7.23.9
'@prefresh/babel-plugin': 0.5.1
@@ -1778,7 +1846,7 @@ snapshots:
'@prefresh/utils': 1.2.0
'@rollup/pluginutils': 4.2.1
preact: 10.19.3
- vite: 4.5.2
+ vite: 4.5.2(@types/node@25.5.0)
transitivePeerDependencies:
- supports-color
@@ -1799,11 +1867,22 @@ snapshots:
estree-walker: 2.0.2
picomatch: 2.3.1
+ '@tanstack/query-core@5.90.20': {}
+
+ '@tanstack/react-query@5.90.21(react@18.2.0)':
+ dependencies:
+ '@tanstack/query-core': 5.90.20
+ react: 18.2.0
+
'@types/hoist-non-react-statics@3.3.5':
dependencies:
'@types/react': 18.2.48
hoist-non-react-statics: 3.3.2
+ '@types/node@25.5.0':
+ dependencies:
+ undici-types: 7.18.2
+
'@types/parse-json@4.0.2': {}
'@types/prop-types@15.7.11': {}
@@ -1857,7 +1936,7 @@ snapshots:
autoprefixer@10.4.17(postcss@8.4.33):
dependencies:
browserslist: 4.22.2
- caniuse-lite: 1.0.30001580
+ caniuse-lite: 1.0.30001754
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.0
@@ -1898,7 +1977,7 @@ snapshots:
browserslist@4.22.2:
dependencies:
- caniuse-lite: 1.0.30001580
+ caniuse-lite: 1.0.30001754
electron-to-chromium: 1.4.646
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.22.2)
@@ -1907,7 +1986,7 @@ snapshots:
camelcase-css@2.0.1: {}
- caniuse-lite@1.0.30001580: {}
+ caniuse-lite@1.0.30001754: {}
chalk@2.4.2:
dependencies:
@@ -1933,6 +2012,8 @@ snapshots:
clsx@2.0.0: {}
+ clsx@2.1.1: {}
+
color-convert@1.9.3:
dependencies:
color-name: 1.1.3
@@ -2104,6 +2185,9 @@ snapshots:
fraction.js@4.3.7: {}
+ fsevents@2.3.2:
+ optional: true
+
fsevents@2.3.3:
optional: true
@@ -2221,6 +2305,10 @@ snapshots:
dependencies:
yallist: 3.1.1
+ lucide-react@0.510.0(react@18.2.0):
+ dependencies:
+ react: 18.2.0
+
magic-string@0.30.5:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
@@ -2305,6 +2393,14 @@ snapshots:
pirates@4.0.6: {}
+ playwright-core@1.58.2: {}
+
+ playwright@1.58.2:
+ dependencies:
+ playwright-core: 1.58.2
+ optionalDependencies:
+ fsevents: 2.3.2
+
postcss-import@15.1.0(postcss@8.4.33):
dependencies:
postcss: 8.4.33
@@ -2358,7 +2454,7 @@ snapshots:
dependencies:
loose-envify: 1.4.0
react: 18.2.0
- scheduler: 0.23.0
+ scheduler: 0.23.2
react-is@16.13.1: {}
@@ -2472,7 +2568,7 @@ snapshots:
dependencies:
queue-microtask: 1.2.3
- scheduler@0.23.0:
+ scheduler@0.23.2:
dependencies:
loose-envify: 1.4.0
@@ -2530,6 +2626,8 @@ snapshots:
tabbable@6.2.0: {}
+ tailwind-merge@3.5.0: {}
+
tailwindcss@3.4.1:
dependencies:
'@alloc/quick-lru': 5.2.0
@@ -2575,6 +2673,8 @@ snapshots:
typescript@5.3.3: {}
+ undici-types@7.18.2: {}
+
update-browserslist-db@1.0.13(browserslist@4.22.2):
dependencies:
browserslist: 4.22.2
@@ -2604,12 +2704,13 @@ snapshots:
util-deprecate@1.0.2: {}
- vite@4.5.2:
+ vite@4.5.2(@types/node@25.5.0):
dependencies:
esbuild: 0.18.20
postcss: 8.4.33
rollup: 3.29.4
optionalDependencies:
+ '@types/node': 25.5.0
fsevents: 2.3.3
which@2.0.2:
diff --git a/src/components/Card/LocationCard/index.tsx b/src/components/Card/LocationCard/index.tsx
index 79a87e3..97b984a 100755
--- a/src/components/Card/LocationCard/index.tsx
+++ b/src/components/Card/LocationCard/index.tsx
@@ -1,5 +1,6 @@
import { JSXInternal } from "node_modules/preact/src/jsx";
import { LocationInfo } from "../../../domains";
+import { cn } from "../../../utils/common";
interface ComponentProps {
onCardClick: (id: number) => void,
@@ -8,40 +9,70 @@ interface ComponentProps {
containerStyle?: JSXInternal.CSSProperties
}
-const LocationCard = (props: ComponentProps) => (
-
-
props.onCardClick(props.data.id)}>
-
-

+const LocationCard = (props: ComponentProps) => {
+ const getScoreClasses = (score: number, count: number) => {
+ if (count === 0) return {
+ text: 'text-white',
+ bg: 'bg-white'
+ };
+
+ if (score <= 40) return {
+ text: 'text-rating-red',
+ bg: 'bg-rating-red'
+ };
+ if (score <= 69) return {
+ text: 'text-rating-yellow',
+ bg: 'bg-rating-yellow'
+ };
+ return {
+ text: 'text-brand-green',
+ bg: 'bg-brand-green'
+ };
+ };
+
+ const criticClasses = getScoreClasses(props.data.critic_score, props.data.critic_count);
+ const userClasses = getScoreClasses(props.data.user_score, props.data.user_count);
+
+ return (
+
+
props.onCardClick(props.data.id)}>
+
+

{
+ e.currentTarget.src = 'https://pub-6b637ea51b64436dbf0514bc956972d1.r2.dev/public/upload/misty-forest-black-white.webp';
+ e.currentTarget.onerror = null;
+ }}
+ />
+
+
+
+
{props.data.name}
+
{props.data.regency_name}, {props.data.province_name}
-
-
-
{props.data.name}
-
{props.data.regency_name}, {props.data.province_name}
-
- {props.data.critic_count !== 0 &&
-
{props.data.critic_score}
-
-
+
{props.data.critic_count !== 0 ? props.data.critic_score : 'NR'}
+
-
critic score ({props.data.critic_count})
+
Critic score ({props.data.critic_count})
- }
- {props.data.user_score !== 0 &&
-
{props.data.user_score}
-
-
+
{props.data.user_count !== 0 ? props.data.user_score : 'NR'}
+
-
user score ({props.data.user_count})
+
User score ({props.data.user_count})
- }
-
-)
+
+ );
+}
export default LocationCard;
\ No newline at end of file
diff --git a/tailwind.config.js b/tailwind.config.js
index 0445e23..c3bdcf0 100755
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -2,53 +2,30 @@
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
- colors: {
- transparent: 'transparent',
- current: 'currentColor',
- primary: '#202225',
- secondary: '#2f3136',
- tertiary: '#a8adb3',
- quartenary: '#4D4E51',
- green: '#85CE73',
- error: '#ff5454',
- gray: '#797979',
- yellow: '#e5c453'
+ extend: {
+ colors: {
+ primary: '#202225',
+ secondary: '#2f3136',
+ tertiary: '#a8adb3',
+ quartenary: '#4D4E51',
+ 'brand-green': '#85CE73',
+ error: '#ff5454',
+ 'brand-yellow': '#e5c453',
+ 'rating-red': '#CE7385',
+ 'rating-green': '#85CE73',
+ 'rating-yellow': '#DECA21'
+ },
+ borderColor: {
+ primary: '#38444d',
+ secondary: '#202225'
+ },
+ fontFamily: {
+ lato: ['Lato', 'sans-serif']
+ },
+ fontSize: {
+ xxs: ['0.65rem', { lineHeight: '.85rem' }],
+ },
},
- borderColor: {
- primary: '#38444d',
- secondary: '#202225'
- },
- fontFamily: {
- lato: ['Lato', 'sans-serif']
- },
- fontSize: {
- xxs: ['0.65rem', { lineHeight: '.85rem' }],
- xs: ['0.75rem', { lineHeight: '1rem' }],
- sm: ['0.875rem', { lineHeight: '1.25rem' }],
- base: ['1rem', { lineHeight: '1.5rem' }],
- lg: ['1.125rem', { lineHeight: '1.75rem' }],
- xl: ['1.25rem', { lineHeight: '1.75rem' }],
- '2xl': ['1.5rem', { lineHeight: '2rem' }],
- '3xl': ['1.875rem', { lineHeight: '2.25rem' }],
- '4xl': ['2.25rem', { lineHeight: '2.5rem' }],
- '5xl': ['3rem', { lineHeight: '1' }],
- '6xl': ['3.75rem', { lineHeight: '1' }],
- '7xl': ['4.5rem', { lineHeight: '1' }],
- '8xl': ['6rem', { lineHeight: '1' }],
- '9xl': ['8rem', { lineHeight: '1' }],
- },
- fontWeight: {
- thin: '100',
- extralight: '200',
- light: '300',
- normal: '400',
- medium: '500',
- semibold: '600',
- bold: '700',
- extrabold: '800',
- black: '900',
- },
- extend: {},
},
plugins: [],
}
diff --git a/tsconfig.json b/tsconfig.json
index 5aa8f53..9294d6d 100755
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -10,7 +10,7 @@
"react": ["./node_modules/preact/compat/"],
"react-dom": ["./node_modules/preact/compat/"]
},
-
+ "types": ["node"],
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,