Compare commits

..

126 Commits

Author SHA1 Message Date
6861c0f0fa chore(release): 3.4.3 2022-05-01 08:03:37 +02:00
9a18e74b90 revert(react): downgrade back to 17.0.2 due to lack of support 2022-05-01 08:03:22 +02:00
4dd1b70079 remove linux/arm64 builds, failing temporarily 2022-04-30 13:39:23 +02:00
f9580fe716 chore(release): 3.4.2 2022-04-30 13:19:34 +02:00
3545f7939f remove linux/arm64 for server, as playwright does not support it 2022-04-30 13:19:08 +02:00
9caad3bc0b chore(release): 3.4.1 2022-04-30 13:01:59 +02:00
5bdb92b1cf fix(typeorm): update typeorm to latest 0.2.x for secpatch 2022-04-30 13:01:45 +02:00
87d381fe8e feat(all): upgrade to v3.4.0 2022-04-30 12:58:17 +02:00
ccfb4d3cb0 Merge pull request #867 from Tomiiwa/Table-of-Contents
[DOC] Added Table of Contents to ReadMe
2022-04-30 09:11:08 +02:00
763074a86c Added Table of Contents to ReadMe 2022-04-29 16:41:52 +01:00
0f46895711 Merge pull request #861 from AmruthPillai/dependabot/github_actions/actions/checkout-3.0.2
chore(deps): bump actions/checkout from 3.0.1 to 3.0.2
2022-04-25 09:34:20 +02:00
aa736af0f5 Merge pull request #858 from AmruthPillai/dependabot/gradle/app/org.jetbrains.kotlin.android-1.6.21
chore(deps): bump org.jetbrains.kotlin.android from 1.6.20 to 1.6.21 in /app
2022-04-25 09:33:53 +02:00
1d9056f935 chore(deps): bump actions/checkout from 3.0.1 to 3.0.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.0.1...v3.0.2)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-25 03:11:03 +00:00
9cadd603f3 chore(deps): bump org.jetbrains.kotlin.android in /app
Bumps org.jetbrains.kotlin.android from 1.6.20 to 1.6.21.

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-25 03:08:55 +00:00
b7b62d7bd0 Merge pull request #853 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-24 08:06:24 +02:00
820e6c90d3 New translations modals.json (Greek) 2022-04-22 15:06:52 +02:00
ea642d1b60 New translations landing.json (Greek) 2022-04-22 15:06:51 +02:00
ec006779a8 New translations common.json (Greek) 2022-04-22 15:06:47 +02:00
515be23c44 New translations dashboard.json (Greek) 2022-04-22 15:06:46 +02:00
c11aec8b44 Merge pull request #851 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-22 07:14:41 +02:00
3c2147e72c New translations landing.json (Swedish) 2022-04-21 21:01:56 +02:00
15a35e6243 New translations modals.json (Swedish) 2022-04-21 21:01:53 +02:00
d53a5a492c New translations landing.json (Swedish) 2022-04-21 20:00:31 +02:00
0810e5ae6a Merge pull request #842 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-20 09:21:40 +02:00
881b183db5 Merge pull request #844 from AmruthPillai/dependabot/github_actions/actions/checkout-3.0.1
chore(deps): bump actions/checkout from 3.0.0 to 3.0.1
2022-04-20 09:21:32 +02:00
15cea02872 Delete close-stale.yml 2022-04-19 06:45:45 +02:00
c195561df0 Merge pull request #843 from augustocardoso07/fix/page-counter
Fix page counter in the center section
2022-04-18 18:15:24 +02:00
fc725cfc0c chore(deps): bump actions/checkout from 3.0.0 to 3.0.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-18 02:30:45 +00:00
9f54516e8c Fix page counter in the center section 2022-04-17 21:09:55 -03:00
68a4cd9635 New translations builder.json (Swedish) 2022-04-17 19:42:51 +02:00
ff01802f2f New translations common.json (Swedish) 2022-04-17 19:42:49 +02:00
bb900bc2e1 New translations dashboard.json (Swedish) 2022-04-17 19:42:48 +02:00
459f82b66b Merge pull request #828 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-11 07:48:37 +02:00
4b382243e4 New translations modals.json (Odia) 2022-04-10 12:17:28 +02:00
af074085d1 New translations landing.json (Odia) 2022-04-10 12:17:25 +02:00
0c8c872668 New translations dashboard.json (Odia) 2022-04-10 12:17:25 +02:00
ddb29bb40d New translations common.json (Odia) 2022-04-10 12:17:23 +02:00
aecb627ab7 New translations builder.json (Odia) 2022-04-10 12:17:22 +02:00
b8cd53cb59 chore(release): 3.3.4 2022-04-09 22:02:26 +02:00
e61f6153c3 Merge pull request #823 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-09 22:01:54 +02:00
386e8ab902 Merge pull request #827 from AmruthPillai/compose-envs
Remove YAML anchors and prefer Docker Compose Environment Arrays
2022-04-09 22:01:41 +02:00
5e8f02e3ca add local build context comment in docker-compose 2022-04-09 21:47:41 +02:00
f219562e72 style(eslint): client/next: add specific rule for no-html-link-for-pages 2022-04-09 21:25:19 +02:00
29d94dfc14 ci(docker): remove yaml anchors in favor of environment array in docker-compose
fix #825, fix #824, fix #820
2022-04-09 21:21:45 +02:00
622f5fc28c ci(github-actions): update key tags for GitHub action to build docker image 2022-04-09 09:33:44 +02:00
647f01e25c Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-04-09 09:32:20 +02:00
5a79c0e5c2 chore(release): 3.3.3 2022-04-09 09:32:04 +02:00
2a4c298572 Merge pull request #819 from martadinata666/combine-tags
combine-tags
2022-04-09 09:30:46 +02:00
1e59f73f79 feat(profile): add XING profile icon
fix #821
2022-04-09 09:29:51 +02:00
feb911aea0 feat(s3): implement non-ephemeral storage through S3/DO Spaces 2022-04-09 09:28:08 +02:00
d0863d68c6 chore(release): 3.3.3 2022-04-09 09:26:34 +02:00
447d9b3ca1 New translations builder.json (Greek) 2022-04-08 19:35:17 +02:00
86e66eb6a0 combine-tags 2022-04-08 19:08:01 +07:00
b2c9515a63 Create SECURITY.md 2022-04-08 10:37:24 +02:00
db04c5caee update CHANGELOG.md 2022-04-08 10:34:27 +02:00
33526d5d13 chore(release): 3.3.2 2022-04-08 10:33:44 +02:00
fc77b548d8 fix(types/react): downgrade to <18 2022-04-08 10:33:06 +02:00
bf7a168f2e chore(release): 3.3.1 2022-04-08 09:50:34 +02:00
17b1551bab ci(buildx): buildx docker, remove arm/v7 for non-support 2022-04-08 09:50:23 +02:00
8864243558 update 2022-04-08 09:41:50 +02:00
37aab7a16f chore(release): 3.3.1 2022-04-08 09:40:46 +02:00
86e1bdf7ea chore(typescript): downgrade to "<4.6.0" 2022-04-08 09:40:34 +02:00
4547fd213d chore(release): 3.3.0 2022-04-08 09:39:01 +02:00
5aacec40cc chore(typescript): downgrade to "<4.6.0" 2022-04-08 09:38:41 +02:00
1df78100ca feat(upgrade): changes to code to support new template 2022-04-08 09:37:26 +02:00
9cd36fcb9b Merge pull request #817 from schklom/patch-2
Automatic multi-platform Docker image build
2022-04-08 08:24:17 +02:00
24b32eb917 Merge pull request #811 from klejejs/main
A new template - Leafish
2022-04-08 08:24:10 +02:00
dec0e41fec Merge pull request #806 from AmruthPillai/i18n_main
New Crowdin updates
2022-04-08 08:21:05 +02:00
42700ad2b2 Update docker-build-push.yml
QEMU + Docker Buildx + multi-platform
2022-04-07 18:32:39 +02:00
df51d79f6b Merge pull request #812 from AmruthPillai/dependabot/gradle/app/org.jetbrains.kotlin.android-1.6.20
Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app
2022-04-04 09:57:39 +02:00
be1673a6a7 Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app
Bumps org.jetbrains.kotlin.android from 1.6.10 to 1.6.20.

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-04 02:21:29 +00:00
648f182e76 Added new template - Leafish 2022-04-03 20:23:06 +03:00
3aa56f0886 New translations landing.json (Portuguese) 2022-03-31 22:19:33 +02:00
b795534da7 New translations landing.json (Portuguese) 2022-03-31 21:13:27 +02:00
c67e2ac9f8 Merge pull request #791 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-28 16:44:24 +02:00
beb418bd5d chore(release): 3.2.11 2022-03-28 16:43:35 +02:00
2b3d9533b0 Merge pull request #797 from chandiwalaaadhar/fix/#795-No-Scrollbar-on-overflow
Fix-#795 No Scoll Behaviour on Overflow
2022-03-28 16:42:52 +02:00
b061f139bd Fix-#795 No Scoll Behaviour on Overflow 2022-03-28 19:56:54 +05:30
ac569324cf New translations common.json (Portuguese) 2022-03-25 15:24:14 +01:00
357d197bb3 New translations common.json (Portuguese) 2022-03-25 14:13:12 +01:00
5eed1186ff chore(release): 3.2.10 2022-03-24 11:59:03 +01:00
a87a9b3247 revert changes made to unreleased v3.2.10 2022-03-24 11:58:44 +01:00
7f1c82cd91 feat(i18n): add portuguese (pt) language to i18n locales 2022-03-24 11:57:16 +01:00
048c1ed3ed Merge pull request #764 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-24 11:54:48 +01:00
9a2570d7e7 New translations builder.json (Portuguese) 2022-03-24 11:46:44 +01:00
00b9c2156d chore(release): 3.2.10 2022-03-24 11:33:14 +01:00
ff8b22274f ci(docker): use docker compose yaml anchor values and extension fields 2022-03-24 11:32:57 +01:00
786937f847 ci(gh): add .devcontainer for GitHub Codespaces 2022-03-24 09:16:54 +00:00
c95efee8ec perf(security): generate random salt rounds integer 2022-03-24 08:45:22 +01:00
776d2f79a6 ci(dependabot): upgrade npm dependencies manually, using local chore 2022-03-24 08:38:54 +01:00
25a6b8cce6 chore(deps): update dependencies to latest 2022-03-24 08:37:57 +01:00
f6d7cae17b Merge pull request #789 from AmruthPillai/dependabot/npm_and_yarn/typeorm-0.3.3
Bump typeorm from 0.2.45 to 0.3.3
2022-03-24 08:16:39 +01:00
944a0b5fb1 Bump typeorm from 0.2.45 to 0.3.3
Bumps [typeorm](https://github.com/typeorm/typeorm) from 0.2.45 to 0.3.3.
- [Release notes](https://github.com/typeorm/typeorm/releases)
- [Changelog](https://github.com/typeorm/typeorm/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typeorm/typeorm/compare/0.2.45...0.3.3)

---
updated-dependencies:
- dependency-name: typeorm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:15:35 +00:00
7769653224 Merge pull request #782 from AmruthPillai/dependabot/npm_and_yarn/server/nestjs/config-2.0.0
Bump @nestjs/config from 1.2.1 to 2.0.0 in /server
2022-03-24 08:15:25 +01:00
ccdc5b5fae Merge pull request #781 from AmruthPillai/dependabot/npm_and_yarn/docs/types/react-17.0.42
Bump @types/react from 17.0.40 to 17.0.42 in /docs
2022-03-24 08:15:20 +01:00
20158f573e Merge pull request #779 from AmruthPillai/dependabot/npm_and_yarn/client/types/node-17.0.23
Bump @types/node from 17.0.21 to 17.0.23 in /client
2022-03-24 08:15:10 +01:00
87c60729b5 Merge branch 'main' into dependabot/npm_and_yarn/client/types/node-17.0.23 2022-03-24 08:14:59 +01:00
a03a50b7c6 Merge pull request #777 from AmruthPillai/dependabot/npm_and_yarn/server/googleapis-98.0.0
Bump googleapis from 97.0.0 to 98.0.0 in /server
2022-03-24 08:14:35 +01:00
fb85ccf501 Merge pull request #776 from AmruthPillai/dependabot/npm_and_yarn/client/types/react-17.0.42
Bump @types/react from 17.0.40 to 17.0.42 in /client
2022-03-24 08:14:31 +01:00
3179442d8f Merge pull request #773 from AmruthPillai/dependabot/github_actions/docker/build-push-action-2.10.0
Bump docker/build-push-action from 2.9.0 to 2.10.0
2022-03-24 08:14:27 +01:00
33d3c52cd9 Merge pull request #772 from AmruthPillai/dependabot/github_actions/digitalocean/action-doctl-2.1.1
Bump digitalocean/action-doctl from 2.1.0 to 2.1.1
2022-03-24 08:14:22 +01:00
1d33e01a43 Merge pull request #771 from AmruthPillai/dependabot/docker/client/node-17-alpine
Bump node from 16-alpine to 17-alpine in /client
2022-03-24 08:14:17 +01:00
52ff221dd1 Merge pull request #770 from AmruthPillai/dependabot/docker/server/node-17-alpine
Bump node from 16-alpine to 17-alpine in /server
2022-03-24 08:13:57 +01:00
5afe178e23 Update dependabot.yml 2022-03-24 08:13:38 +01:00
9118b76084 Bump @nestjs/config from 1.2.1 to 2.0.0 in /server
Bumps [@nestjs/config](https://github.com/nestjs/config) from 1.2.1 to 2.0.0.
- [Release notes](https://github.com/nestjs/config/releases)
- [Changelog](https://github.com/nestjs/config/blob/master/.release-it.json)
- [Commits](https://github.com/nestjs/config/compare/1.2.1...2.0.0)

---
updated-dependencies:
- dependency-name: "@nestjs/config"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:04:09 +00:00
5a62b527b9 Bump @types/react from 17.0.40 to 17.0.42 in /docs
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.40 to 17.0.42.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:04:08 +00:00
2e9e14dc72 Bump @types/node from 17.0.21 to 17.0.23 in /client
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 17.0.21 to 17.0.23.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:03:51 +00:00
0a0b4893aa Bump googleapis from 97.0.0 to 98.0.0 in /server
Bumps [googleapis](https://github.com/googleapis/google-api-nodejs-client) from 97.0.0 to 98.0.0.
- [Release notes](https://github.com/googleapis/google-api-nodejs-client/releases)
- [Changelog](https://github.com/googleapis/google-api-nodejs-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-nodejs-client/compare/googleapis-v97.0.0...googleapis-v98.0.0)

---
updated-dependencies:
- dependency-name: googleapis
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:03:37 +00:00
6277f81e26 Bump @types/react from 17.0.40 to 17.0.42 in /client
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.40 to 17.0.42.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:03:35 +00:00
d550150787 Bump docker/build-push-action from 2.9.0 to 2.10.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2.9.0 to 2.10.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2.9.0...v2.10.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:41 +00:00
7626b2153f Bump digitalocean/action-doctl from 2.1.0 to 2.1.1
Bumps [digitalocean/action-doctl](https://github.com/digitalocean/action-doctl) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/digitalocean/action-doctl/releases)
- [Commits](https://github.com/digitalocean/action-doctl/compare/v2.1.0...v2.1.1)

---
updated-dependencies:
- dependency-name: digitalocean/action-doctl
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:38 +00:00
6d17d1001d Bump node from 16-alpine to 17-alpine in /client
Bumps node from 16-alpine to 17-alpine.

---
updated-dependencies:
- dependency-name: node
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:34 +00:00
0273738d7a Bump node from 16-alpine to 17-alpine in /server
Bumps node from 16-alpine to 17-alpine.

---
updated-dependencies:
- dependency-name: node
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 07:02:34 +00:00
322df25ecc Merge pull request #769 from modem7/dependabot-changes
Dependabot
2022-03-24 08:02:15 +01:00
ab3867d9a8 Merge pull request #768 from modem7/DockerChanges
Docker changes
2022-03-24 08:01:07 +01:00
9bf8ec88f4 Merge pull request #767 from modem7/readme-update
Update README
2022-03-24 07:58:58 +01:00
685f4d37a6 Merge pull request #766 from modem7/image-size
Reduced image sizes
2022-03-24 07:58:19 +01:00
f3b3fe8ac9 Update dependabot.yml
added gradle
2022-03-24 00:47:21 +00:00
d5fa49172a Create dependabot.yml
This will assist with version updates and vulnerability scans.

Dependabot scans will need to be enabled in the repo itself under https://github.com/AmruthPillai/Reactive-Resume/settings/security_analysis

It would also be worthwhile pairing this with Snyk (https://app.snyk.io/) for vulnerability monitoring.
2022-03-23 23:04:47 +00:00
b8303b9977 Update .env.example
Updated env variables to be clearer about which service requires it.
2022-03-23 23:03:29 +00:00
16d06c6356 Update README.md
As the logo is already in the repo, might as well utilise it.

Added Docker build status
2022-03-23 22:54:33 +00:00
79ddd887d9 Docker changes
Added:
Healthchecks
Changed Postgres to Alpine + pinned
Pinned Traefik Version
Made Env Vars easier to see + change/reference for those using their own env file.
2022-03-23 22:52:30 +00:00
c394bc6725 Reduced image sizes
This reduces images size from a total of 9.22mb to 6.11mb.
2022-03-23 22:41:24 +00:00
9e6d7630f4 New translations landing.json (Portuguese) 2022-03-23 23:06:12 +01:00
e2fbdd3c2f New translations modals.json (Portuguese) 2022-03-23 21:57:14 +01:00
849171af8f New translations dashboard.json (Portuguese) 2022-03-23 21:01:36 +01:00
200 changed files with 29143 additions and 3221 deletions

5
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,5 @@
ARG VARIANT="lts-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm

View File

@ -0,0 +1,27 @@
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile",
"args": { "VARIANT": "16-bullseye" }
},
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "lokalise.i18n-ally"],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [80, 5432],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pnpm install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"features": {
"docker-from-docker": "latest"
}
}

View File

@ -1,33 +1,33 @@
# App
# Server + Client
TZ=UTC
SECRET_KEY=
PUBLIC_URL=http://localhost:3000
PUBLIC_SERVER_URL=http://localhost:3000/api
PUBLIC_GOOGLE_CLIENT_ID=
# URLs
PUBLIC_URL=http://<SERVER-IP>
PUBLIC_SERVER_URL=http://<SERVER-IP>/api
# Database
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USERNAME=postgres
# Server + Database
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DATABASE=postgres
POSTGRES_SSL_CERT=
# Auth
# Server
SECRET_KEY=
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_SSL_CERT=
JWT_SECRET=
JWT_EXPIRY_TIME=604800
# Google
PUBLIC_GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_API_KEY=
# SendGrid (Optional)
SENDGRID_API_KEY=
SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID=
SENDGRID_FROM_NAME=
SENDGRID_FROM_EMAIL=
STORAGE_BUCKET=
STORAGE_REGION=
STORAGE_ENDPOINT=
STORAGE_URL_PREFIX=
STORAGE_ACCESS_KEY=
STORAGE_SECRET_KEY=
# Flags (Optional)
# Flags (Client)
PUBLIC_FLAG_DISABLE_SIGNUPS=false

22
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: 'docker'
directory: '/server'
schedule:
interval: 'weekly'
- package-ecosystem: 'docker'
directory: '/client'
schedule:
interval: 'weekly'
- package-ecosystem: 'gradle'
directory: '/app'
schedule:
interval: 'weekly'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'

View File

@ -1,16 +0,0 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5.0.0
with:
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity. Remove the stale label or comment on this PR, otherwise it would be closed in 5 days.'
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity. Remove the stale label or comment on this issue, otherwise it would be closed in 5 days.'
days-before-stale: 30
days-before-close: 5

View File

@ -13,7 +13,7 @@ jobs:
steps:
- name: Install DigitalOcean CLI
uses: digitalocean/action-doctl@v2.1.0
uses: digitalocean/action-doctl@v2.1.1
with:
token: ${{ secrets.DIGITALOCEAN_TOKEN }}

View File

@ -5,26 +5,33 @@ on:
types: [published]
jobs:
docker_client:
name: Docker (Client)
client:
name: Client
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to Docker
- name: Login to Docker Hub
uses: docker/login-action@v1.14.1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1.14.1
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Client Image
uses: docker/build-push-action@v2.9.0
uses: docker/build-push-action@v2.10.0
with:
context: .
push: true
@ -32,27 +39,36 @@ jobs:
tags: |
amruthpillai/reactive-resume:client-latest
amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
ghcr.io/amruthpillai/reactive-resume:client-latest
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
docker_server:
name: Docker (Server)
server:
name: Server
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
uses: actions/checkout@v3.0.2
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to Docker
- name: Login to Docker Hub
uses: docker/login-action@v1.14.1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1.14.1
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Server Image
uses: docker/build-push-action@v2.9.0
uses: docker/build-push-action@v2.10.0
with:
context: .
push: true
@ -60,61 +76,5 @@ jobs:
tags: |
amruthpillai/reactive-resume:server-latest
amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
github_client:
name: GitHub (Client)
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1.14.1
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Client Image
uses: docker/build-push-action@v2.9.0
with:
context: .
push: true
file: client/Dockerfile
tags: |
ghcr.io/amruthpillai/reactive-resume:client-latest
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
github_server:
name: GitHub (Server)
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1.14.1
with:
registry: ghcr.io
username: $GITHUB_REPOSITORY_OWNER
password: ${{ secrets.GH_TOKEN }}
- name: Build and Push Server Image
uses: docker/build-push-action@v2.9.0
with:
context: .
push: true
file: server/Dockerfile
tags: |
ghcr.io/amruthpillai/reactive-resume:server-latest
ghcr.io/amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}

View File

@ -2,6 +2,65 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [3.4.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.2...v3.4.3) (2022-05-01)
### [3.4.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.1...v3.4.2) (2022-04-30)
### [3.4.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.0...v3.4.1) (2022-04-30)
### Bug Fixes
* **typeorm:** update typeorm to latest 0.2.x for secpatch ([5bdb92b](https://github.com/AmruthPillai/Reactive-Resume/commit/5bdb92b1cff9e56879f9bbf31801d6554a00a8d5))
### [3.4.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.3...v3.4.0) (2022-04-30)
### [3.3.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.3...v3.3.4) (2022-04-09)
### [3.3.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.2...v3.3.3) (2022-04-09)
### Features
* **profile:** add XING profile icon ([1e59f73](https://github.com/AmruthPillai/Reactive-Resume/commit/1e59f73f79a91d0264c0d2108906ee89d4eb27f8)), closes [#821](https://github.com/AmruthPillai/Reactive-Resume/issues/821)
* **s3:** implement non-ephemeral storage through S3/DO Spaces ([feb911a](https://github.com/AmruthPillai/Reactive-Resume/commit/feb911aea06bacf58ea933d2803a2a89fe36e57b))
### [3.3.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.1...v3.3.2) (2022-04-08)
### Bug Fixes
* **types/react:** downgrade to <18 ([fc77b54](https://github.com/AmruthPillai/Reactive-Resume/commit/fc77b548d8d61530b2d158ff83f088bed12d5080))
### [3.3.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.0...v3.3.1) (2022-04-08)
## [3.3.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.11...v3.3.0) (2022-04-08)
### Features
* **upgrade:** changes to code to support new template ([1df7810](https://github.com/AmruthPillai/Reactive-Resume/commit/1df78100ca0667ce9b7834cf2c25384eb21c67c2))
### What's Changed
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/791
* Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app by @dependabot in https://github.com/AmruthPillai/Reactive-Resume/pull/812
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/806
* A new template - Leafish by @klejejs in https://github.com/AmruthPillai/Reactive-Resume/pull/811
* Automatic multi-platform Docker image build by @schklom in https://github.com/AmruthPillai/Reactive-Resume/pull/817
### New Contributors
* @klejejs made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/811
* @schklom made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/817
### [3.2.11](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.10...v3.2.11) (2022-03-28)
### [3.2.10](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.9...v3.2.10) (2022-03-24)
### Features
* **i18n:** add portuguese (pt) language to i18n locales ([7f1c82c](https://github.com/AmruthPillai/Reactive-Resume/commit/7f1c82cd9185ebb44486a16132eb44d5c2fb747a))
### [3.2.9](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.8...v3.2.9) (2022-03-21)

View File

@ -1,4 +1,4 @@
<img src="https://i.imgur.com/pc8Ingg.png" alt="Reactive Resume" width="256px" height="256px" />
<img src="https://github.com/AmruthPillai/Reactive-Resume/blob/main/docs/static/logo.svg" alt="Reactive Resume" width="256px" height="256px" />
# Reactive Resume
@ -6,6 +6,7 @@
[![Project License](https://img.shields.io/github/license/AmruthPillai/Reactive-Resume?style=flat-square)](https://github.com/AmruthPillai/Reactive-Resume/blob/main/LICENSE)
[![Crowdin](https://badges.crowdin.net/reactive-resume/localized.svg)](https://translate.rxresu.me)
[![Docker Pulls](https://img.shields.io/docker/pulls/amruthpillai/reactive-resume?style=flat-square)](https://hub.docker.com/r/amruthpillai/reactive-resume)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/AmruthPillai/Reactive-Resume/Build%20and%20Push%20Docker%20Image?label=docker%20build&style=flat-square)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FAmruthPillai%2FReactive-Resume.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FAmruthPillai%2FReactive-Resume?ref=badge_shield)
## [Go to App](https://rxresu.me) | [Docs](https://docs.rxresu.me)
@ -14,6 +15,23 @@ Reactive Resume is a free and open source resume builder thats built to make
You have complete control over what goes into your resume, how it looks, what colors, what templates, even the layout in which sections placed. Want a dark mode resume? Its as easy as editing 3 values and youre done. You dont need to wait to see your changes either. Everything you type, everything you change, appears immediately on your resume and gets updated in real time.
## Table of Contents
- [Reactive Resume](#reactive-resume)
- [Go to App | [Docs](https://docs.rxresu.me)](#go-to-app--docs)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Languages](#languages)
- [Tutorial](#tutorial)
- [Build from Source](#build-from-source)
- [Contributing](#contributing)
- [Report Bugs and Feature Requests](#report-bugs-and-feature-requests)
- [Donations](#donations)
- [💸 PayPal](#-paypal)
- [Infrastructure](#infrastructure)
- [Contributors Wall](#contributors-wall)
- [License](#license)
## Features
- Free, forever
@ -39,18 +57,23 @@ You have complete control over what goes into your resume, how it looks, what co
- Arabic (اَلْعَرَبِيَّةُ)
- Bengali (বাংলা)
- Chinese (中文)
- Czech (čeština)
- Danish (Dansk)
- Dutch (Nederlands)
- English
- French (Français)
- German (Deutsch)
- Greek (Ελληνικά)
- Hindi (हिन्दी)
- Italian (Italiano)
- Kannada (ಕನ್ನಡ)
- Malayalam (മലയാളം)
- Odia (ଓଡ଼ିଆ)
- Polish (Polski)
- Portuguese (Português)
- Russian (русский)
- Spanish (Español)
- Swedish (Svenska)
- Tamil (தமிழ்)
- Turkish (Türkçe)
- Vietnamese (Tiếng Việt)
@ -77,7 +100,7 @@ This project makes use of [conventional commits](https://www.conventionalcommits
NOTE: Be sure to merge the latest from `main` before making a pull request!
## Bugs? Feature Requests?
## Report Bugs and Feature Requests
Use the [GitHub Issues](https://github.com/AmruthPillai/Reactive-Resume/issues/new/choose) platform to notify me about bugs or new features that you would like to see in Reactive Resume. Please check before creating new issues as there might already be one.

13
SECURITY.md Normal file
View File

@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.x.x | :white_check_mark: |
| 2.x.x | :x: |
| 1.x.x | :x: |
## Reporting a Vulnerability
Create an issue on GitHub or send me an email through the contact form on my website at https://amruthpillai.com/

View File

@ -1,7 +1,7 @@
plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
}
task clean(type: Delete) {

View File

@ -3,6 +3,7 @@
"ignorePatterns": [".next", "__ENV.js"],
"rules": {
"@next/next/no-img-element": "off",
"@next/next/no-sync-scripts": "off"
"@next/next/no-sync-scripts": "off",
"@next/next/no-html-link-for-pages": ["error", "pages"]
}
}

View File

@ -1,4 +1,4 @@
FROM node:16-alpine as dependencies
FROM node:lts-alpine as dependencies
RUN apk add --no-cache curl g++ make python3 \
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
@ -11,7 +11,7 @@ COPY ./client/package.json ./client/package.json
RUN pnpm install --frozen-lockfile
FROM node:16-alpine as builder
FROM node:lts-alpine as builder
RUN apk add --no-cache curl g++ make python3 \
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
@ -27,7 +27,7 @@ COPY --from=dependencies /app/client/node_modules ./client/node_modules
RUN pnpm run build:schema
RUN pnpm run build:client
FROM node:16-alpine as production
FROM node:lts-alpine as production
WORKDIR /app
@ -49,4 +49,7 @@ EXPOSE 3000
ENV PORT 3000
HEALTHCHECK --interval=30s --timeout=20s --retries=3 --start-period=15s \
CMD curl -fSs 127.0.0.1:3000 || exit 1
CMD [ "pnpm", "run", "start:client" ]

View File

@ -52,7 +52,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
const url = getResumeUrl(resume, { withHost: true });
await navigator.clipboard.writeText(url);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
const handleExportPDF = async () => {
@ -75,19 +75,19 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
})}
>
<div className={styles.controller}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-in') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-in')}>
<ButtonBase onClick={() => zoomIn(0.25)}>
<ZoomIn fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-out') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-out')}>
<ButtonBase onClick={() => zoomOut(0.25)}>
<ZoomOut fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.center-artboard') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.center-artboard')}>
<ButtonBase onClick={() => centerView(0.95)}>
<FilterCenterFocus fontSize="medium" />
</ButtonBase>
@ -98,7 +98,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
{isDesktop && (
<>
{pages.length > 1 && (
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-orientation') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-orientation')}>
<ButtonBase onClick={handleTogglePageOrientation}>
{orientation === 'vertical' ? (
<AlignHorizontalCenter fontSize="medium" />
@ -109,13 +109,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
</Tooltip>
)}
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-page-break-line') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-page-break-line')}>
<ButtonBase onClick={handleTogglePageBreakLine}>
<InsertPageBreak fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-sidebars') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-sidebars')}>
<ButtonBase onClick={handleToggleSidebar}>
<ViewSidebar fontSize="medium" />
</ButtonBase>
@ -125,13 +125,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
</>
)}
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.copy-link') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.copy-link')}>
<ButtonBase onClick={handleCopyLink}>
<Link fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.export-pdf') as string}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.export-pdf')}>
<ButtonBase onClick={handleExportPDF} disabled={isLoading}>
<Download fontSize="medium" />
</ButtonBase>

View File

@ -133,7 +133,7 @@ const Header = () => {
const url = getResumeUrl(resume, { withHost: true });
await navigator.clipboard.writeText(url);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
return (
@ -166,14 +166,14 @@ const Header = () => {
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.rename')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.rename')}</ListItemText>
</MenuItem>
<MenuItem onClick={handleDuplicate}>
<ListItemIcon>
<CopyAll className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.duplicate')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.duplicate')}</ListItemText>
</MenuItem>
{resume.public ? (
@ -181,27 +181,27 @@ const Header = () => {
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.share-link')}</ListItemText>
</MenuItem>
) : (
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.share-link') as string}>
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.share-link')}>
<div>
<MenuItem>
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.share-link')}</ListItemText>
</MenuItem>
</div>
</Tooltip>
)}
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.delete') as string}>
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.delete')}>
<MenuItem onClick={handleDelete}>
<ListItemIcon>
<Delete className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.header.menu.delete')}</ListItemText>
<ListItemText>{t<string>('builder.header.menu.delete')}</ListItemText>
</MenuItem>
</Tooltip>
</Menu>

View File

@ -48,9 +48,7 @@ const Page: React.FC<Props> = ({ page, showPageNumbers = false }) => {
</div>
{showPageNumbers && (
<h4 className={styles.pageNumber}>
{t('builder.common.glossary.page')} {page + 1}
</h4>
<h4 className={styles.pageNumber}>{`${t<string>('builder.common.glossary.page')} ${page + 1}`}</h4>
)}
</div>
);

View File

@ -81,14 +81,14 @@ const LeftSidebar = () => {
arrow
key={id}
placement="right"
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`))}
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`)) as string}
>
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
</Tooltip>
))}
{customSections.map(({ id }) => (
<Tooltip key={id} title={get(sections, `${id}.name`, '')} placement="right" arrow>
<Tooltip key={id} title={get(sections, `${id}.name`, '') as string} placement="right" arrow>
<IconButton onClick={() => handleClick(id)}>
<Star />
</IconButton>
@ -114,7 +114,9 @@ const LeftSidebar = () => {
<div className="py-6 text-right">
<Button fullWidth variant="outlined" startIcon={<Add />} onClick={handleAddSection}>
{t('builder.common.actions.add', { token: t('builder.leftSidebar.sections.section.heading') })}
{t<string>('builder.common.actions.add', {
token: t<string>('builder.leftSidebar.sections.section.heading'),
})}
</Button>
</div>
</main>

View File

@ -24,7 +24,7 @@ const Basics = () => {
return (
<>
<Heading path="sections.basics" name={t('builder.leftSidebar.sections.basics.heading')} />
<Heading path="sections.basics" name={t<string>('builder.leftSidebar.sections.basics.heading')} />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div className="grid items-center gap-4 sm:col-span-2 sm:grid-cols-3">
@ -33,10 +33,10 @@ const Basics = () => {
</div>
<div className="grid gap-2 w-full sm:col-span-2">
<ResumeInput label={t('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
<ResumeInput label={t<string>('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
<Button variant="outlined" startIcon={<PhotoFilter />} onClick={handleClick}>
{t('builder.leftSidebar.sections.basics.actions.photo-filters')}
{t<string>('builder.leftSidebar.sections.basics.actions.photo-filters')}
</Button>
<Popover
@ -57,20 +57,30 @@ const Basics = () => {
</div>
</div>
<ResumeInput label={t('builder.common.form.email.label')} path="basics.email" className="sm:col-span-2" />
<ResumeInput label={t('builder.common.form.phone.label')} path="basics.phone" />
<ResumeInput label={t('builder.common.form.url.label')} path="basics.website" />
<ResumeInput
type="date"
label={t<string>('builder.leftSidebar.sections.basics.birthdate.label')}
path="basics.birthdate"
className="sm:col-span-2"
/>
<ResumeInput
label={t<string>('builder.common.form.email.label')}
path="basics.email"
className="sm:col-span-2"
/>
<ResumeInput label={t<string>('builder.common.form.phone.label')} path="basics.phone" />
<ResumeInput label={t<string>('builder.common.form.url.label')} path="basics.website" />
<Divider className="sm:col-span-2" />
<ResumeInput
label={t('builder.leftSidebar.sections.basics.headline.label')}
label={t<string>('builder.leftSidebar.sections.basics.headline.label')}
path="basics.headline"
className="sm:col-span-2"
/>
<ResumeInput
type="textarea"
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
path="basics.summary"
className="sm:col-span-2"
markdownSupported

View File

@ -8,19 +8,28 @@ const Location = () => {
return (
<>
<Heading path="sections.location" name={t('builder.leftSidebar.sections.location.heading')} />
<Heading path="sections.location" name={t<string>('builder.leftSidebar.sections.location.heading')} />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<ResumeInput
label={t('builder.leftSidebar.sections.location.address.label')}
label={t<string>('builder.leftSidebar.sections.location.address.label')}
path="basics.location.address"
className="sm:col-span-2"
/>
<ResumeInput label={t('builder.leftSidebar.sections.location.city.label')} path="basics.location.city" />
<ResumeInput label={t('builder.leftSidebar.sections.location.region.label')} path="basics.location.region" />
<ResumeInput label={t('builder.leftSidebar.sections.location.country.label')} path="basics.location.country" />
<ResumeInput
label={t('builder.leftSidebar.sections.location.postal-code.label')}
label={t<string>('builder.leftSidebar.sections.location.city.label')}
path="basics.location.city"
/>
<ResumeInput
label={t<string>('builder.leftSidebar.sections.location.region.label')}
path="basics.location.region"
/>
<ResumeInput
label={t<string>('builder.leftSidebar.sections.location.country.label')}
path="basics.location.country"
/>
<ResumeInput
label={t<string>('builder.leftSidebar.sections.location.postal-code.label')}
path="basics.location.postalCode"
/>
</div>

View File

@ -32,7 +32,7 @@ const PhotoFilters = () => {
return (
<div className="flex flex-col gap-2 p-5 dark:bg-neutral-800">
<div>
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.size.heading')}</h4>
<h4 className="font-medium">{t<string>('builder.leftSidebar.sections.basics.photo-filters.size.heading')}</h4>
<div className="mx-2">
<Slider
@ -54,18 +54,20 @@ const PhotoFilters = () => {
<Divider />
<div>
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.effects.heading')}</h4>
<h4 className="font-medium">
{t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.heading')}
</h4>
<div className="flex items-center">
<FormControlLabel
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label') as string}
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label')}
control={
<Checkbox color="secondary" checked={grayscale} onChange={(_, value) => handleSetGrayscale(value)} />
}
/>
<FormControlLabel
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.border.label') as string}
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.border.label')}
control={<Checkbox color="secondary" checked={border} onChange={(_, value) => handleSetBorder(value)} />}
/>
</div>
@ -74,7 +76,7 @@ const PhotoFilters = () => {
<Divider />
<div className="flex flex-col gap-2">
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.shape.heading')}</h4>
<h4 className="font-medium">{t<string>('builder.leftSidebar.sections.basics.photo-filters.shape.heading')}</h4>
<ToggleButtonGroup exclusive value={shape} onChange={(_, value) => handleChangeShape(value)}>
<ToggleButton size="small" value="square" className="w-14">

View File

@ -49,7 +49,7 @@ const PhotoUpload: React.FC = () => {
const file = event.target.files[0];
if (file.size > FILE_UPLOAD_MAX_SIZE) {
toast.error(t('common.toast.error.upload-photo-size'));
toast.error(t<string>('common.toast.error.upload-photo-size'));
return;
}
@ -67,8 +67,8 @@ const PhotoUpload: React.FC = () => {
<Tooltip
title={
isEmpty(photo.url)
? (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
: (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
? (t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
: (t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
}
>
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />

View File

@ -28,7 +28,7 @@ const Profiles = () => {
return (
<>
<Heading path="sections.profiles" name={t('builder.leftSidebar.sections.profiles.heading')} />
<Heading path="sections.profiles" name={t<string>('builder.leftSidebar.sections.profiles.heading')} />
<List
path="basics.profiles"
@ -40,8 +40,8 @@ const Profiles = () => {
<footer className="flex justify-end">
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
{t('builder.common.actions.add', {
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
{t<string>('builder.common.actions.add', {
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
})}
</Button>
</footer>

View File

@ -74,7 +74,7 @@ const Section: React.FC<Props> = ({
<SectionSettings path={path} />
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
{t('builder.common.actions.add', { token: heading })}
{t<string>('builder.common.actions.add', { token: heading })}
</Button>
</footer>
</>

View File

@ -32,7 +32,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
return (
<div>
<Tooltip title={t('builder.common.columns.tooltip') as string}>
<Tooltip title={t<string>('builder.common.columns.tooltip')}>
<ButtonBase onClick={handleClick} sx={{ padding: 1, borderRadius: 1 }} className="opacity-50 hover:opacity-75">
<ViewWeek /> <span className="ml-1.5 text-xs">{columns}</span>
</ButtonBase>
@ -48,7 +48,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
}}
>
<div className="p-5 dark:bg-neutral-800">
<h4 className="mb-2 font-medium">{t('builder.common.columns.heading')}</h4>
<h4 className="mb-2 font-medium">{t<string>('builder.common.columns.heading')}</h4>
<ToggleButtonGroup exclusive value={columns} onChange={(_, value: number) => handleSetColumns(value)}>
{[1, 2, 3, 4].map((index) => (

View File

@ -25,7 +25,7 @@ const CustomCSS = () => {
return (
<>
<Heading path="metadata.css" name={t('builder.rightSidebar.sections.css.heading')} isHideable />
<Heading path="metadata.css" name={t<string>('builder.rightSidebar.sections.css.heading')} isHideable />
<Editor
height="200px"

View File

@ -19,12 +19,12 @@ const Export = () => {
const pdfListItemText = {
normal: {
primary: t('builder.rightSidebar.sections.export.pdf.normal.primary'),
secondary: t('builder.rightSidebar.sections.export.pdf.normal.secondary'),
primary: t<string>('builder.rightSidebar.sections.export.pdf.normal.primary'),
secondary: t<string>('builder.rightSidebar.sections.export.pdf.normal.secondary'),
},
loading: {
primary: t('builder.rightSidebar.sections.export.pdf.loading.primary'),
secondary: t('builder.rightSidebar.sections.export.pdf.loading.secondary'),
primary: t<string>('builder.rightSidebar.sections.export.pdf.loading.primary'),
secondary: t<string>('builder.rightSidebar.sections.export.pdf.loading.secondary'),
},
};
@ -53,7 +53,7 @@ const Export = () => {
return (
<>
<Heading path="metadata.export" name={t('builder.rightSidebar.sections.export.heading')} />
<Heading path="metadata.export" name={t<string>('builder.rightSidebar.sections.export.heading')} />
<List sx={{ padding: 0 }}>
<ListItem sx={{ padding: 0 }}>
@ -61,8 +61,8 @@ const Export = () => {
<Schema />
<ListItemText
primary={t('builder.rightSidebar.sections.export.json.primary')}
secondary={t('builder.rightSidebar.sections.export.json.secondary')}
primary={t<string>('builder.rightSidebar.sections.export.json.primary')}
secondary={t<string>('builder.rightSidebar.sections.export.json.secondary')}
/>
</ListItemButton>
</ListItem>

View File

@ -60,9 +60,9 @@ const Layout = () => {
<>
<Heading
path="metadata.layout"
name={t('builder.rightSidebar.sections.layout.heading')}
name={t<string>('builder.rightSidebar.sections.layout.heading')}
action={
<Tooltip title={t('builder.rightSidebar.sections.layout.tooltip.reset-layout') as string}>
<Tooltip title={t<string>('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
<IconButton onClick={handleResetLayout}>
<Restore />
</IconButton>
@ -76,12 +76,16 @@ const Layout = () => {
<div key={pageIndex} className={styles.page}>
<div className="flex items-center justify-between pr-3">
<p className={styles.heading}>
{t('builder.common.glossary.page')} {pageIndex + 1}
{t<string>('builder.common.glossary.page')} {pageIndex + 1}
</p>
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
<Tooltip
title={t('builder.common.actions.delete', { token: t('builder.common.glossary.page') }) as string}
title={
t<string>('builder.common.actions.delete', {
token: t<string>('builder.common.glossary.page'),
}) as string
}
>
<IconButton size="small" onClick={() => handleDeletePage(pageIndex)}>
<Close fontSize="small" />
@ -113,7 +117,7 @@ const Layout = () => {
[styles.disabled]: !get(resumeSections, `${sectionId}.visible`, true),
})}
>
{get(resumeSections, `${sectionId}.name`)}
{get(resumeSections, `${sectionId}.name`, '') as string}
</div>
</div>
)}
@ -132,7 +136,7 @@ const Layout = () => {
<div className="flex items-center justify-end">
<Button variant="outlined" startIcon={<Add />} onClick={handleAddPage}>
{t('builder.common.actions.add', { token: t('builder.common.glossary.page') })}
{t<string>('builder.common.actions.add', { token: t<string>('builder.common.glossary.page') })}
</Button>
</div>
</DragDropContext>

View File

@ -12,39 +12,41 @@ const Links = () => {
return (
<>
<Heading path="metadata.links" name={t('builder.rightSidebar.sections.links.heading')} />
<Heading path="metadata.links" name={t<string>('builder.rightSidebar.sections.links.heading')} />
<div className={styles.container}>
<div className={styles.section}>
<h2>
<Savings fontSize="small" />
{t('builder.rightSidebar.sections.links.donate.heading')}
{t<string>('builder.rightSidebar.sections.links.donate.heading')}
</h2>
<p>{t('builder.rightSidebar.sections.links.donate.body')}</p>
<p>{t<string>('builder.rightSidebar.sections.links.donate.body')}</p>
<a href={DONATION_URL} target="_blank" rel="noreferrer">
<Button startIcon={<Coffee />}>{t('builder.rightSidebar.sections.links.donate.button')}</Button>
<Button startIcon={<Coffee />}>{t<string>('builder.rightSidebar.sections.links.donate.button')}</Button>
</a>
</div>
<div className={styles.section}>
<h2>
<BugReport fontSize="small" />
{t('builder.rightSidebar.sections.links.bugs-features.heading')}
{t<string>('builder.rightSidebar.sections.links.bugs-features.heading')}
</h2>
<p>{t('builder.rightSidebar.sections.links.bugs-features.body')}</p>
<p>{t<string>('builder.rightSidebar.sections.links.bugs-features.body')}</p>
<a href={GITHUB_ISSUES_URL} target="_blank" rel="noreferrer">
<Button startIcon={<GitHub />}>{t('builder.rightSidebar.sections.links.bugs-features.button')}</Button>
<Button startIcon={<GitHub />}>
{t<string>('builder.rightSidebar.sections.links.bugs-features.button')}
</Button>
</a>
</div>
<div>
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<Link />}>
{t('builder.rightSidebar.sections.links.github')}
{t<string>('builder.rightSidebar.sections.links.github')}
</Button>
</a>
</div>

View File

@ -85,13 +85,13 @@ const Settings = () => {
return (
<>
<Heading path="metadata.settings" name={t('builder.rightSidebar.sections.settings.heading')} />
<Heading path="metadata.settings" name={t<string>('builder.rightSidebar.sections.settings.heading')} />
<List sx={{ padding: 0 }}>
{/* Global Settings */}
<>
<ListSubheader className="rounded">
{t('builder.rightSidebar.sections.settings.global.heading')}
{t<string>('builder.rightSidebar.sections.settings.global.heading')}
</ListSubheader>
<ListItem>
@ -99,7 +99,7 @@ const Settings = () => {
<Palette />
</ListItemIcon>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.global.theme.primary')}
primary={t<string>('builder.rightSidebar.sections.settings.global.theme.primary')}
secondary={themeString}
/>
<ThemeSwitch checked={isDarkMode} onChange={(_, value: boolean) => handleSetTheme(value)} />
@ -108,8 +108,8 @@ const Settings = () => {
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t('builder.rightSidebar.sections.settings.global.date.primary')}
secondary={t('builder.rightSidebar.sections.settings.global.date.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.global.date.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.global.date.secondary')}
/>
<Autocomplete<string, false, boolean, false>
disableClearable
@ -124,8 +124,8 @@ const Settings = () => {
<ListItem className="flex-col">
<ListItemText
className="w-full"
primary={t('builder.rightSidebar.sections.settings.global.language.primary')}
secondary={t('builder.rightSidebar.sections.settings.global.language.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.global.language.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.global.language.secondary')}
/>
<Autocomplete<Language, false, boolean, false>
disableClearable
@ -148,15 +148,17 @@ const Settings = () => {
{/* Page Settings */}
<>
<ListSubheader className="rounded">{t('builder.rightSidebar.sections.settings.page.heading')}</ListSubheader>
<ListSubheader className="rounded">
{t<string>('builder.rightSidebar.sections.settings.page.heading')}
</ListSubheader>
<ListItem>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.page.orientation.primary')}
primary={t<string>('builder.rightSidebar.sections.settings.page.orientation.primary')}
secondary={
pages.length === 1
? t('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t('builder.rightSidebar.sections.settings.page.orientation.secondary')
? t<string>('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t<string>('builder.rightSidebar.sections.settings.page.orientation.secondary')
}
/>
<Switch
@ -169,8 +171,8 @@ const Settings = () => {
<ListItem>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.page.break-line.primary')}
secondary={t('builder.rightSidebar.sections.settings.page.break-line.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.page.break-line.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.page.break-line.secondary')}
/>
<Switch color="secondary" checked={breakLine} onChange={() => dispatch(togglePageBreakLine())} />
</ListItem>
@ -179,7 +181,7 @@ const Settings = () => {
{/* Resume Settings */}
<>
<ListSubheader className="rounded">
{t('builder.rightSidebar.sections.settings.resume.heading')}
{t<string>('builder.rightSidebar.sections.settings.resume.heading')}
</ListSubheader>
<ListItem>
@ -188,8 +190,8 @@ const Settings = () => {
<Anchor />
</ListItemIcon>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.resume.sample.primary')}
secondary={t('builder.rightSidebar.sections.settings.resume.sample.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.resume.sample.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.resume.sample.secondary')}
/>
</ListItemButton>
</ListItem>
@ -200,8 +202,8 @@ const Settings = () => {
<DeleteForever />
</ListItemIcon>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.resume.reset.primary')}
secondary={t('builder.rightSidebar.sections.settings.resume.reset.secondary')}
primary={t<string>('builder.rightSidebar.sections.settings.resume.reset.primary')}
secondary={t<string>('builder.rightSidebar.sections.settings.resume.reset.secondary')}
/>
</ListItemButton>
</ListItem>

View File

@ -29,19 +29,19 @@ const Sharing = () => {
await navigator.clipboard.writeText(text);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
return (
<>
<Heading path="metadata.sharing" name={t('builder.rightSidebar.sections.sharing.heading')} />
<Heading path="metadata.sharing" name={t<string>('builder.rightSidebar.sections.sharing.heading')} />
<List sx={{ padding: 0 }}>
<ListItem className="flex flex-col" sx={{ padding: 0 }}>
<div className="flex w-full items-center justify-between">
<ListItemText
primary={t('builder.rightSidebar.sections.sharing.visibility.title')}
secondary={t('builder.rightSidebar.sections.sharing.visibility.subtitle')}
primary={t<string>('builder.rightSidebar.sections.sharing.visibility.title')}
secondary={t<string>('builder.rightSidebar.sections.sharing.visibility.subtitle')}
/>
<Switch color="secondary" checked={isPublic} onChange={(_, value) => handleSetVisibility(value)} />
</div>
@ -63,7 +63,7 @@ const Sharing = () => {
<div className="mt-1 flex w-full">
<FormControlLabel
label={t('builder.rightSidebar.sections.sharing.short-url.label') as string}
label={t<string>('builder.rightSidebar.sections.sharing.short-url.label')}
control={
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
}

View File

@ -24,7 +24,7 @@ const Templates = () => {
return (
<>
<Heading path="metadata.templates" name={t('builder.rightSidebar.sections.templates.heading')} />
<Heading path="metadata.templates" name={t<string>('builder.rightSidebar.sections.templates.heading')} />
<div className={styles.container}>
{Object.values(templateMap).map((template) => (

View File

@ -24,7 +24,7 @@ const Theme = () => {
return (
<>
<Heading path="metadata.theme" name={t('builder.rightSidebar.sections.theme.heading')} />
<Heading path="metadata.theme" name={t<string>('builder.rightSidebar.sections.theme.heading')} />
<div className={styles.container}>
<div className={styles.colorOptions}>
@ -34,18 +34,18 @@ const Theme = () => {
</div>
<ColorPicker
label={t('builder.rightSidebar.sections.theme.form.primary.label')}
label={t<string>('builder.rightSidebar.sections.theme.form.primary.label')}
color={primary}
className="col-span-2"
onChange={(color) => handleChange('primary', color)}
/>
<ColorPicker
label={t('builder.rightSidebar.sections.theme.form.background.label')}
label={t<string>('builder.rightSidebar.sections.theme.form.background.label')}
color={background}
onChange={(color) => handleChange('background', color)}
/>
<ColorPicker
label={t('builder.rightSidebar.sections.theme.form.text.label')}
label={t<string>('builder.rightSidebar.sections.theme.form.text.label')}
color={text}
onChange={(color) => handleChange('text', color)}
/>

View File

@ -64,7 +64,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
step={1}
marks={[
{ value: 12, label: '12px' },
{ value: 24, label: t('builder.rightSidebar.sections.typography.form.font-size.label') },
{ value: 24, label: t<string>('builder.rightSidebar.sections.typography.form.font-size.label') },
{ value: 36, label: '36px' },
]}
valueLabelDisplay="auto"
@ -82,7 +82,10 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
value={fonts.find((font) => font.family === family[category])}
onChange={(_, font: Font | null) => handleChange('family', font)}
renderInput={(params) => (
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
<TextField
{...params}
label={t<string>('builder.rightSidebar.sections.typography.form.font-family.label')}
/>
)}
/>
</div>
@ -95,10 +98,13 @@ const Typography = () => {
return (
<>
<Heading path="metadata.typography" name={t('builder.rightSidebar.sections.typography.heading')} />
<Heading path="metadata.typography" name={t<string>('builder.rightSidebar.sections.typography.heading')} />
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.headings.label')} category="heading" />
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
<Widgets
label={t<string>('builder.rightSidebar.sections.typography.widgets.headings.label')}
category="heading"
/>
<Widgets label={t<string>('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
</>
);
};

View File

@ -94,7 +94,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
const url = getResumeUrl(resume, { withHost: true });
await navigator.clipboard.writeText(url);
toast.success(t('common.toast.success.resume-link-copied'));
toast.success(t<string>('common.toast.success.resume-link-copied'));
};
const handleDelete = async () => {
@ -124,7 +124,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<footer>
<div className={styles.meta}>
<p>{resume.name}</p>
<p>{t('dashboard.resume.timestamp', { timestamp: getRelativeTime(resume.updatedAt) })}</p>
<p>{t<string>('dashboard.resume.timestamp', { timestamp: getRelativeTime(resume.updatedAt) })}</p>
</div>
<ButtonBase className={styles.menu} onClick={handleOpenMenu}>
@ -136,21 +136,21 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<ListItemIcon>
<OpenInNew className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.open')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.open')}</ListItemText>
</MenuItem>
<MenuItem onClick={handleRename}>
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.rename')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.rename')}</ListItemText>
</MenuItem>
<MenuItem onClick={handleDuplicate}>
<ListItemIcon>
<ContentCopy className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.duplicate')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.duplicate')}</ListItemText>
</MenuItem>
{resume.public ? (
@ -158,27 +158,27 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.share-link')}</ListItemText>
</MenuItem>
) : (
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.share-link') as string}>
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.share-link')}>
<div>
<MenuItem>
<ListItemIcon>
<LinkIcon className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.share-link')}</ListItemText>
</MenuItem>
</div>
</Tooltip>
)}
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.delete') as string}>
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.delete')}>
<MenuItem onClick={handleDelete}>
<ListItemIcon>
<DeleteOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('dashboard.resume.menu.delete')}</ListItemText>
<ListItemText>{t<string>('dashboard.resume.menu.delete')}</ListItemText>
</MenuItem>
</Tooltip>
</Menu>

View File

@ -56,12 +56,12 @@ const Avatar: React.FC<Props> = ({ size = 64 }) => {
<Menu anchorEl={anchorEl} onClose={handleClose} open={Boolean(anchorEl)}>
<MenuItem>
<div>
<span className="text-xs opacity-50">{t('common.avatar.menu.greeting')}</span>
<span className="text-xs opacity-50">{t<string>('common.avatar.menu.greeting')}</span>
<p>{user?.name}</p>
</div>
</MenuItem>
<Divider />
<MenuItem onClick={handleLogout}>{t('common.avatar.menu.logout')}</MenuItem>
<MenuItem onClick={handleLogout}>{t<string>('common.avatar.menu.logout')}</MenuItem>
</Menu>
</>
);

View File

@ -1,10 +1,16 @@
.content {
@apply rounded p-6 text-sm shadow lg:w-1/2 xl:w-2/5;
@apply rounded px-6 text-sm shadow lg:w-1/2 xl:w-2/5;
@apply absolute inset-4 sm:inset-x-4 sm:inset-y-auto lg:inset-auto;
@apply overflow-scroll bg-neutral-50 dark:bg-neutral-900 lg:overflow-auto;
@apply max-h-[90vh] min-h-fit;
&::-webkit-scrollbar {
display: none;
}
}
.header {
@apply sticky top-0 left-0 right-0 z-50 pt-6 bg-neutral-50 dark:bg-neutral-900;
@apply flex items-center justify-between;
@apply w-full border-b pb-5 dark:border-white/10;
@ -27,6 +33,7 @@
}
.footer {
@apply sticky bottom-0 left-0 right-0 z-50 pb-6 bg-neutral-50 dark:bg-neutral-900;
@apply flex items-center justify-end gap-x-4;
@apply w-full border-t pt-5 dark:border-white/10;
}

View File

@ -5,11 +5,12 @@ import { useRouter } from 'next/router';
import styles from './BaseModal.module.scss';
type Props = {
icon?: React.ReactNode;
isOpen: boolean;
heading: string;
handleClose: () => void;
icon?: React.ReactNode;
children?: React.ReactNode;
footerChildren?: React.ReactNode;
handleClose: () => void;
};
const BaseModal: React.FC<Props> = ({ icon, isOpen, heading, children, handleClose, footerChildren }) => {

View File

@ -10,7 +10,7 @@ const Footer: React.FC<Props> = ({ className }) => {
return (
<div className={clsx('text-xs', className)}>
<p>{t('common.footer.license')}</p>
<p>{t<string>('common.footer.license')}</p>
<p>
<Trans t={t} i18nKey="common.footer.credit">

View File

@ -72,19 +72,19 @@ const Heading: React.FC<Props> = ({
})}
>
{isEditable && (
<Tooltip title={t('builder.common.tooltip.rename-section') as string}>
<Tooltip title={t<string>('builder.common.tooltip.rename-section')}>
<IconButton onClick={toggleEditMode}>{editMode ? <Check /> : <DriveFileRenameOutline />}</IconButton>
</Tooltip>
)}
{isHideable && (
<Tooltip title={t('builder.common.tooltip.toggle-visibility') as string}>
<Tooltip title={t<string>('builder.common.tooltip.toggle-visibility')}>
<IconButton onClick={toggleVisibility}>{visibility ? <Visibility /> : <VisibilityOff />}</IconButton>
</Tooltip>
)}
{isDeletable && (
<Tooltip title={t('builder.common.tooltip.delete-section') as string}>
<Tooltip title={t<string>('builder.common.tooltip.delete-section')}>
<IconButton onClick={handleDelete}>
<Delete />
</IconButton>

View File

@ -66,7 +66,7 @@ const List: React.FC<Props> = ({
return (
<DndProvider backend={HTML5Backend}>
<div className={clsx(styles.container, className)}>
{isEmpty(list) && <div className={styles.empty}>{t('builder.common.list.empty-text')}</div>}
{isEmpty(list) && <div className={styles.empty}>{t<string>('builder.common.list.empty-text')}</div>}
{list.map((item, index) => {
const title = get(item, titleKey, '');
@ -76,6 +76,7 @@ const List: React.FC<Props> = ({
return (
<ListItem
key={item.id}
path={path}
item={item}
index={index}
title={title}

View File

@ -17,6 +17,7 @@ interface DragItem {
type Props = {
item: ListItemType;
path: string;
index: number;
title: string;
subtitle?: string;
@ -26,14 +27,14 @@ type Props = {
onDuplicate?: (item: ListItemType) => void;
};
const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
const ListItem: React.FC<Props> = ({ item, path, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
const { t } = useTranslation();
const ref = useRef<HTMLDivElement>(null);
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
const [{ handlerId }, drop] = useDrop<DragItem, any, any>({
accept: 'ListItem',
accept: path,
collect(monitor) {
return { handlerId: monitor.getHandlerId() };
},
@ -68,7 +69,7 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
});
const [{ isDragging }, drag] = useDrag({
type: 'ListItem',
type: path,
item: () => {
return { id: item.id, index };
},
@ -125,25 +126,25 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.common.list.actions.edit')}</ListItemText>
<ListItemText>{t<string>('builder.common.list.actions.edit')}</ListItemText>
</MenuItem>
<MenuItem onClick={() => handleDuplicate(item)}>
<ListItemIcon>
<FileCopy className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.common.list.actions.duplicate')}</ListItemText>
<ListItemText>{t<string>('builder.common.list.actions.duplicate')}</ListItemText>
</MenuItem>
<Divider />
<Tooltip arrow placement="right" title={t('builder.common.tooltip.delete-item') as string}>
<Tooltip arrow placement="right" title={t<string>('builder.common.tooltip.delete-item')}>
<div>
<MenuItem onClick={() => handleDelete(item)}>
<ListItemIcon>
<DeleteOutline className="scale-90" />
</ListItemIcon>
<ListItemText>{t('builder.common.list.actions.delete')}</ListItemText>
<ListItemText>{t<string>('builder.common.list.actions.delete')}</ListItemText>
</MenuItem>
</div>
</Tooltip>

View File

@ -1,5 +0,0 @@
import dynamic from 'next/dynamic';
const NoSSR: React.FC = ({ children }) => <>{children}</>;
export default dynamic(() => Promise.resolve(NoSSR), { ssr: false });

View File

@ -1,4 +1,7 @@
import { DatePicker } from '@mui/lab';
import { TextField } from '@mui/material';
import dayjs from 'dayjs';
import { isEmpty } from 'lodash';
import get from 'lodash/get';
import { useEffect, useState } from 'react';
@ -8,7 +11,7 @@ import { setResumeState } from '@/store/resume/resumeSlice';
import MarkdownSupported from './MarkdownSupported';
interface Props {
type?: 'text' | 'textarea';
type?: 'text' | 'textarea' | 'date';
label: string;
path: string;
className?: string;
@ -31,6 +34,11 @@ const ResumeInput: React.FC<Props> = ({ type = 'text', label, path, className, m
dispatch(setResumeState({ path, value: event.target.value }));
};
const onChangeValue = (value: string) => {
setValue(value);
dispatch(setResumeState({ path, value }));
};
if (type === 'textarea') {
return (
<TextField
@ -45,6 +53,22 @@ const ResumeInput: React.FC<Props> = ({ type = 'text', label, path, className, m
);
}
if (type === 'date') {
return (
<DatePicker
openTo="year"
label={label}
value={value}
views={['year', 'month', 'day']}
renderInput={(params) => <TextField {...params} error={false} className={className} />}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && onChangeValue('');
date && dayjs(date).isValid() && onChangeValue(date.toISOString());
}}
/>
);
}
return <TextField type={type} label={label} value={value} onChange={onChange} className={className} />;
};

View File

@ -7,8 +7,10 @@ export type Language = {
export const languages: Language[] = [
{ code: 'ar', name: 'Arabic', localName: 'اَلْعَرَبِيَّةُ' },
{ code: 'bn', name: 'Bengali', localName: 'বাংলা' },
{ code: 'cs', name: 'Czech', localName: 'čeština' },
{ code: 'da', name: 'Danish', localName: 'Dansk' },
{ code: 'de', name: 'German', localName: 'Deutsch' },
{ code: 'el', name: 'Greek', localName: 'Ελληνικά' },
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Spanish', localName: 'Español' },
{ code: 'fr', name: 'French', localName: 'Français' },
@ -17,8 +19,11 @@ export const languages: Language[] = [
{ code: 'kn', name: 'Kannada', localName: 'ಕನ್ನಡ' },
{ code: 'ml', name: 'Malayalam', localName: 'മലയാളം' },
{ code: 'nl', name: 'Dutch', localName: 'Nederlands' },
{ code: 'or', name: 'Odia', localName: 'ଓଡ଼ିଆ' },
{ code: 'pl', name: 'Polish', localName: 'Polski' },
{ code: 'pt', name: 'Portuguese', localName: 'Português' },
{ code: 'ru', name: 'Russian', localName: 'русский' },
{ code: 'sv', name: 'Swedish', localName: 'Svenska' },
{ code: 'ta', name: 'Tamil', localName: 'தமிழ்' },
{ code: 'tr', name: 'Turkish', localName: 'Türkçe' },
{ code: 'vi', name: 'Vietnamese', localName: 'Tiếng Việt' },

View File

@ -54,16 +54,16 @@ const ForgotPasswordModal: React.FC = () => {
<BaseModal
icon={<Password />}
isOpen={isOpen}
heading={t('modals.auth.forgot-password.heading')}
heading={t<string>('modals.auth.forgot-password.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.auth.forgot-password.actions.send-email')}
{t<string>('modals.auth.forgot-password.actions.send-email')}
</Button>
}
>
<div className="grid gap-4">
<p>{t('modals.auth.forgot-password.body')}</p>
<p>{t<string>('modals.auth.forgot-password.body')}</p>
<form className="grid gap-4 xl:w-2/3">
<Controller
@ -72,7 +72,7 @@ const ForgotPasswordModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.auth.forgot-password.form.email.label')}
label={t<string>('modals.auth.forgot-password.form.email.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -81,7 +81,7 @@ const ForgotPasswordModal: React.FC = () => {
/>
</form>
<p className="text-xs">{t('modals.auth.forgot-password.help-text')}</p>
<p className="text-xs">{t<string>('modals.auth.forgot-password.help-text')}</p>
</div>
</BaseModal>
</>

View File

@ -6,7 +6,6 @@ import Joi from 'joi';
import { isEmpty } from 'lodash';
import { Trans, useTranslation } from 'next-i18next';
import { useMemo, useState } from 'react';
import { GoogleLoginResponse, GoogleLoginResponseOffline, useGoogleLogin } from 'react-google-login';
import { Controller, useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import { useIsMutating, useMutation } from 'react-query';
@ -18,6 +17,8 @@ import { ServerError } from '@/services/axios';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
declare const google: any;
type FormData = {
identifier: string;
password: string;
@ -56,15 +57,6 @@ const LoginModal: React.FC = () => {
loginWithGoogle
);
const { signIn } = useGoogleLogin({
clientId: env('GOOGLE_CLIENT_ID'),
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
handleClose();
},
});
const handleClose = () => {
dispatch(setModalState({ modal: 'auth.login', state: { open: false } }));
reset();
@ -93,8 +85,18 @@ const LoginModal: React.FC = () => {
dispatch(setModalState({ modal: 'auth.forgot', state: { open: true } }));
};
const handleLoginWithGoogle = () => {
signIn();
const handleLoginWithGoogle = async () => {
google.accounts.id.initialize({
client_id: env('GOOGLE_CLIENT_ID'),
callback: async (response: any) => {
await loginWithGoogleMutation({ credential: response.credential });
handleClose();
},
auto_select: false,
});
google.accounts.id.prompt();
};
const PasswordVisibility = (): React.ReactElement => {
@ -113,7 +115,7 @@ const LoginModal: React.FC = () => {
<BaseModal
icon={<Login />}
isOpen={isOpen}
heading={t('modals.auth.login.heading')}
heading={t<string>('modals.auth.login.heading')}
handleClose={handleClose}
footerChildren={
<div className="flex gap-4">
@ -125,17 +127,17 @@ const LoginModal: React.FC = () => {
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.login.actions.google')}
{t<string>('modals.auth.login.actions.google')}
</Button>
)}
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.login.actions.login')}
{t<string>('modals.auth.login.actions.login')}
</Button>
</div>
}
>
<p>{t('modals.auth.login.body')}</p>
<p>{t<string>('modals.auth.login.body')}</p>
<form className="grid gap-4 xl:w-2/3">
<Controller
@ -144,9 +146,9 @@ const LoginModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.auth.login.form.username.label')}
label={t<string>('modals.auth.login.form.username.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message || t('modals.auth.login.form.username.help-text')}
helperText={fieldState.error?.message || t<string>('modals.auth.login.form.username.help-text')}
{...field}
/>
)}
@ -158,7 +160,7 @@ const LoginModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type={showPassword ? 'text' : 'password'}
label={t('modals.auth.login.form.password.label')}
label={t<string>('modals.auth.login.form.password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
InputProps={{ endAdornment: <PasswordVisibility /> }}

View File

@ -5,7 +5,6 @@ import { Button, TextField } from '@mui/material';
import Joi from 'joi';
import { isEmpty } from 'lodash';
import { Trans, useTranslation } from 'next-i18next';
import { GoogleLoginResponse, GoogleLoginResponseOffline, useGoogleLogin } from 'react-google-login';
import { Controller, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';
@ -15,6 +14,8 @@ import { ServerError } from '@/services/axios';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
declare const google: any;
type FormData = {
name: string;
username: string;
@ -63,15 +64,6 @@ const RegisterModal: React.FC = () => {
loginWithGoogle
);
const { signIn } = useGoogleLogin({
clientId: env('GOOGLE_CLIENT_ID'),
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
handleClose();
},
});
const handleClose = () => {
dispatch(setModalState({ modal: 'auth.register', state: { open: false } }));
reset();
@ -87,15 +79,25 @@ const RegisterModal: React.FC = () => {
dispatch(setModalState({ modal: 'auth.login', state: { open: true } }));
};
const handleLoginWithGoogle = () => {
signIn();
const handleLoginWithGoogle = async () => {
google.accounts.id.initialize({
client_id: env('GOOGLE_CLIENT_ID'),
callback: async (response: any) => {
await loginWithGoogleMutation({ credential: response.credential });
handleClose();
},
auto_select: false,
});
google.accounts.id.prompt();
};
return (
<BaseModal
icon={<HowToReg />}
isOpen={isOpen}
heading={t('modals.auth.register.heading')}
heading={t<string>('modals.auth.register.heading')}
handleClose={handleClose}
footerChildren={
<div className="flex gap-4">
@ -107,17 +109,17 @@ const RegisterModal: React.FC = () => {
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.register.actions.google')}
{t<string>('modals.auth.register.actions.google')}
</Button>
)}
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.register.actions.register')}
{t<string>('modals.auth.register.actions.register')}
</Button>
</div>
}
>
<p>{t('modals.auth.register.body')}</p>
<p>{t<string>('modals.auth.register.body')}</p>
<form className="grid gap-4 md:grid-cols-2">
<Controller
@ -126,7 +128,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.auth.register.form.name.label')}
label={t<string>('modals.auth.register.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -139,7 +141,7 @@ const RegisterModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('modals.auth.register.form.username.label')}
label={t<string>('modals.auth.register.form.username.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -153,7 +155,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="email"
label={t('modals.auth.register.form.email.label')}
label={t<string>('modals.auth.register.form.email.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -168,7 +170,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="password"
label={t('modals.auth.register.form.password.label')}
label={t<string>('modals.auth.register.form.password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -182,7 +184,7 @@ const RegisterModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="password"
label={t('modals.auth.register.form.confirm-password.label')}
label={t<string>('modals.auth.register.form.confirm-password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -65,15 +65,15 @@ const ResetPasswordModal: React.FC = () => {
<BaseModal
icon={<LockReset />}
isOpen={isOpen}
heading={t('modals.auth.reset-password.heading')}
heading={t<string>('modals.auth.reset-password.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.auth.reset-password.actions.set-password')}
{t<string>('modals.auth.reset-password.actions.set-password')}
</Button>
}
>
<p>{t('modals.auth.reset-password.body')}</p>
<p>{t<string>('modals.auth.reset-password.body')}</p>
<form className="grid gap-4 md:grid-cols-2">
<Controller
@ -83,7 +83,7 @@ const ResetPasswordModal: React.FC = () => {
<TextField
autoFocus
type="password"
label={t('modals.auth.reset-password.form.password.label')}
label={t<string>('modals.auth.reset-password.form.password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -97,7 +97,7 @@ const ResetPasswordModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
type="password"
label={t('modals.auth.reset-password.form.confirm-password.label')}
label={t<string>('modals.auth.reset-password.form.confirm-password.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -50,8 +50,8 @@ const AwardModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -101,7 +101,7 @@ const AwardModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.title.label')}
label={t<string>('builder.common.form.title.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const AwardModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.awards.form.awarder.label')}
label={t<string>('builder.leftSidebar.sections.awards.form.awarder.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -130,7 +130,7 @@ const AwardModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.date.label')}
label={t<string>('builder.common.form.date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -152,7 +152,7 @@ const AwardModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -169,7 +169,7 @@ const AwardModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -50,8 +50,8 @@ const CertificateModal: React.FC = () => {
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -101,7 +101,7 @@ const CertificateModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const CertificateModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.certifications.form.issuer.label')}
label={t<string>('builder.leftSidebar.sections.certifications.form.issuer.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -130,7 +130,7 @@ const CertificateModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.date.label')}
label={t<string>('builder.common.form.date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -152,7 +152,7 @@ const CertificateModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -169,7 +169,7 @@ const CertificateModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -67,8 +67,8 @@ const CustomModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -118,7 +118,7 @@ const CustomModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.title.label')}
label={t<string>('builder.common.form.title.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -131,7 +131,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.subtitle.label')}
label={t<string>('builder.common.form.subtitle.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -146,7 +146,7 @@ const CustomModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -170,7 +170,7 @@ const CustomModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -192,7 +192,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -207,7 +207,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.level.label')}
label={t<string>('builder.common.form.level.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -221,7 +221,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field }) => (
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
<div className="px-10">
<Slider
@ -245,7 +245,7 @@ const CustomModal: React.FC = () => {
defaultValue={0}
color="secondary"
valueLabelDisplay="auto"
aria-label={t('builder.common.form.levelNum.label')}
aria-label={t<string>('builder.common.form.levelNum.label')}
/>
</div>
</div>
@ -260,7 +260,7 @@ const CustomModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}
@ -274,7 +274,7 @@ const CustomModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -63,8 +63,8 @@ const EducationModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -114,7 +114,7 @@ const EducationModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.leftSidebar.sections.education.form.institution.label')}
label={t<string>('builder.leftSidebar.sections.education.form.institution.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -128,7 +128,7 @@ const EducationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.education.form.degree.label')}
label={t<string>('builder.leftSidebar.sections.education.form.degree.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -141,7 +141,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.leftSidebar.sections.education.form.area-study.label')}
label={t<string>('builder.leftSidebar.sections.education.form.area-study.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -154,7 +154,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.leftSidebar.sections.education.form.grade.label')}
label={t<string>('builder.leftSidebar.sections.education.form.grade.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -169,7 +169,7 @@ const EducationModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -193,7 +193,7 @@ const EducationModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -203,7 +203,7 @@ const EducationModal: React.FC = () => {
<TextField
{...params}
error={!!fieldState.error}
helperText={fieldState.error?.message || t('builder.common.form.end-date.help-text')}
helperText={fieldState.error?.message || t<string>('builder.common.form.end-date.help-text')}
/>
)}
/>
@ -215,7 +215,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -233,7 +233,7 @@ const EducationModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}
@ -247,7 +247,7 @@ const EducationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.leftSidebar.sections.education.form.courses.label')}
label={t<string>('builder.leftSidebar.sections.education.form.courses.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -41,8 +41,8 @@ const InterestModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -92,7 +92,7 @@ const InterestModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -106,7 +106,7 @@ const InterestModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -42,8 +42,8 @@ const LanguageModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -93,7 +93,7 @@ const LanguageModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -107,7 +107,7 @@ const LanguageModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.level.label')}
label={t<string>('builder.common.form.level.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -120,7 +120,7 @@ const LanguageModal: React.FC = () => {
control={control}
render={({ field }) => (
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
<div className="px-10">
<Slider
@ -144,7 +144,7 @@ const LanguageModal: React.FC = () => {
defaultValue={0}
color="secondary"
valueLabelDisplay="auto"
aria-label={t('builder.common.form.levelNum.label')}
aria-label={t<string>('builder.common.form.levelNum.label')}
/>
</div>
</div>

View File

@ -42,11 +42,11 @@ const ProfileModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = t('builder.common.actions.add', {
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
const addText = t<string>('builder.common.actions.add', {
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
});
const editText = t('builder.common.actions.edit', {
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
const editText = t<string>('builder.common.actions.edit', {
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
});
const { reset, control, handleSubmit } = useForm<FormData>({
@ -97,7 +97,7 @@ const ProfileModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.leftSidebar.sections.profiles.form.network.label')}
label={t<string>('builder.leftSidebar.sections.profiles.form.network.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -111,7 +111,7 @@ const ProfileModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.profiles.form.username.label')}
label={t<string>('builder.leftSidebar.sections.profiles.form.username.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
InputProps={{
@ -127,7 +127,7 @@ const ProfileModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
className="col-span-2"
placeholder="https://"
error={!!fieldState.error}

View File

@ -59,8 +59,8 @@ const ProjectModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -110,7 +110,7 @@ const ProjectModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -124,7 +124,7 @@ const ProjectModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.description.label')}
label={t<string>('builder.common.form.description.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -139,7 +139,7 @@ const ProjectModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -163,7 +163,7 @@ const ProjectModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -185,7 +185,7 @@ const ProjectModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -203,7 +203,7 @@ const ProjectModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}
@ -217,7 +217,7 @@ const ProjectModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value as string[]}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -50,8 +50,8 @@ const PublicationModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -101,7 +101,7 @@ const PublicationModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const PublicationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.publications.form.publisher.label')}
label={t<string>('builder.leftSidebar.sections.publications.form.publisher.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -130,7 +130,7 @@ const PublicationModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.date.label')}
label={t<string>('builder.common.form.date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -152,7 +152,7 @@ const PublicationModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -169,7 +169,7 @@ const PublicationModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -47,8 +47,8 @@ const ReferenceModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -98,7 +98,7 @@ const ReferenceModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -112,7 +112,7 @@ const ReferenceModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.leftSidebar.sections.references.form.relationship.label')}
label={t<string>('builder.leftSidebar.sections.references.form.relationship.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -125,7 +125,7 @@ const ReferenceModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.phone.label')}
label={t<string>('builder.common.form.phone.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -138,7 +138,7 @@ const ReferenceModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.email.label')}
label={t<string>('builder.common.form.email.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -154,7 +154,7 @@ const ReferenceModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -45,8 +45,8 @@ const SkillModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -96,7 +96,7 @@ const SkillModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -109,7 +109,7 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.level.label')}
label={t<string>('builder.common.form.level.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -122,7 +122,7 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field }) => (
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
<div className="px-3">
<Slider
@ -146,7 +146,7 @@ const SkillModal: React.FC = () => {
defaultValue={0}
color="secondary"
valueLabelDisplay="auto"
aria-label={t('builder.common.form.levelNum.label')}
aria-label={t<string>('builder.common.form.levelNum.label')}
/>
</div>
</div>
@ -158,7 +158,7 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
label={t<string>('builder.common.form.keywords.label')}
value={field.value}
onChange={field.onChange}
errors={fieldState.error}

View File

@ -56,8 +56,8 @@ const VolunteerModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -107,7 +107,7 @@ const VolunteerModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.leftSidebar.sections.volunteer.form.organization.label')}
label={t<string>('builder.leftSidebar.sections.volunteer.form.organization.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -121,7 +121,7 @@ const VolunteerModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.position.label')}
label={t<string>('builder.common.form.position.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -136,7 +136,7 @@ const VolunteerModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -160,7 +160,7 @@ const VolunteerModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -182,7 +182,7 @@ const VolunteerModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -200,7 +200,7 @@ const VolunteerModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -56,8 +56,8 @@ const WorkModal: React.FC = () => {
const item: FormData = get(payload, 'item', null);
const isEditMode = useMemo(() => !!item, [item]);
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
const { reset, control, handleSubmit } = useForm<FormData>({
defaultValues: defaultState,
@ -107,7 +107,7 @@ const WorkModal: React.FC = () => {
<TextField
required
autoFocus
label={t('builder.common.form.name.label')}
label={t<string>('builder.common.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -121,7 +121,7 @@ const WorkModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.position.label')}
label={t<string>('builder.common.form.position.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -136,7 +136,7 @@ const WorkModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.start-date.label')}
label={t<string>('builder.common.form.start-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -160,7 +160,7 @@ const WorkModal: React.FC = () => {
<DatePicker
{...field}
openTo="year"
label={t('builder.common.form.end-date.label')}
label={t<string>('builder.common.form.end-date.label')}
views={['year', 'month', 'day']}
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
isEmpty(keyboardInputValue) && field.onChange('');
@ -170,7 +170,7 @@ const WorkModal: React.FC = () => {
<TextField
{...params}
error={!!fieldState.error}
helperText={fieldState.error?.message || t('builder.common.form.end-date.help-text')}
helperText={fieldState.error?.message || t<string>('builder.common.form.end-date.help-text')}
/>
)}
/>
@ -182,7 +182,7 @@ const WorkModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
label={t<string>('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
@ -200,7 +200,7 @@ const WorkModal: React.FC = () => {
multiline
minRows={3}
maxRows={6}
label={t('builder.common.form.summary.label')}
label={t<string>('builder.common.form.summary.label')}
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message || <MarkdownSupported />}

View File

@ -85,15 +85,15 @@ const CreateResumeModal: React.FC = () => {
<BaseModal
isOpen={isOpen}
icon={<Add />}
heading={t('modals.dashboard.create-resume.heading')}
heading={t<string>('modals.dashboard.create-resume.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.dashboard.create-resume.actions.create-resume')}
{t<string>('modals.dashboard.create-resume.actions.create-resume')}
</Button>
}
>
<p>{t('modals.dashboard.create-resume.body')}</p>
<p>{t<string>('modals.dashboard.create-resume.body')}</p>
<form className="grid gap-4">
<Controller
@ -102,7 +102,7 @@ const CreateResumeModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.dashboard.create-resume.form.name.label')}
label={t<string>('modals.dashboard.create-resume.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -115,7 +115,7 @@ const CreateResumeModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('modals.dashboard.create-resume.form.slug.label')}
label={t<string>('modals.dashboard.create-resume.form.slug.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -125,7 +125,7 @@ const CreateResumeModal: React.FC = () => {
<FormGroup>
<FormControlLabel
label={t('modals.dashboard.create-resume.form.public.label') as string}
label={t<string>('modals.dashboard.create-resume.form.public.label')}
control={
<Controller
name="isPublic"

View File

@ -63,7 +63,7 @@ const ImportExternalModal: React.FC = () => {
const file = event.target.files[0];
if (file.size > FILE_UPLOAD_MAX_SIZE) {
toast.error(t('common.toast.error.upload-file-size'));
toast.error(t<string>('common.toast.error.upload-file-size'));
return;
}
@ -78,13 +78,13 @@ const ImportExternalModal: React.FC = () => {
<BaseModal
isOpen={isOpen}
icon={<ImportExport />}
heading={t('modals.dashboard.import-external.heading')}
heading={t<string>('modals.dashboard.import-external.heading')}
handleClose={handleClose}
>
<div className="grid gap-5">
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
<LinkedIn />
{t('modals.dashboard.import-external.linkedin.heading')}
{t<string>('modals.dashboard.import-external.linkedin.heading')}
</h2>
<p className="mb-2">
@ -110,7 +110,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('linkedin')}
>
{t('modals.dashboard.import-external.linkedin.actions.upload-archive')}
{t<string>('modals.dashboard.import-external.linkedin.actions.upload-archive')}
</Button>
<input
@ -128,7 +128,7 @@ const ImportExternalModal: React.FC = () => {
<div className="grid gap-5">
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
<Code />
{t('modals.dashboard.import-external.json-resume.heading')}
{t<string>('modals.dashboard.import-external.json-resume.heading')}
</h2>
<p className="mb-2">
@ -154,7 +154,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('json-resume')}
>
{t('modals.dashboard.import-external.json-resume.actions.upload-json')}
{t<string>('modals.dashboard.import-external.json-resume.actions.upload-json')}
</Button>
<input
@ -172,10 +172,10 @@ const ImportExternalModal: React.FC = () => {
<div className="grid gap-5">
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
<TrackChanges />
{t('modals.dashboard.import-external.reactive-resume.heading')}
{t<string>('modals.dashboard.import-external.reactive-resume.heading')}
</h2>
<p className="mb-2">{t('modals.dashboard.import-external.reactive-resume.body')}</p>
<p className="mb-2">{t<string>('modals.dashboard.import-external.reactive-resume.body')}</p>
<div className="flex gap-4">
<Button
@ -184,7 +184,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('reactive-resume')}
>
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
{t<string>('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
</Button>
<Button
@ -193,7 +193,7 @@ const ImportExternalModal: React.FC = () => {
startIcon={<UploadFile />}
onClick={() => handleClick('reactive-resume-v2')}
>
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
{t<string>('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
</Button>
<input

View File

@ -92,11 +92,11 @@ const RenameResumeModal: React.FC = () => {
<BaseModal
icon={<DriveFileRenameOutline />}
isOpen={isOpen}
heading={t('modals.dashboard.rename-resume.heading')}
heading={t<string>('modals.dashboard.rename-resume.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
{t('modals.dashboard.rename-resume.actions.rename-resume')}
{t<string>('modals.dashboard.rename-resume.actions.rename-resume')}
</Button>
}
>
@ -107,7 +107,7 @@ const RenameResumeModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
autoFocus
label={t('modals.dashboard.rename-resume.form.name.label')}
label={t<string>('modals.dashboard.rename-resume.form.name.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -120,7 +120,7 @@ const RenameResumeModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
label={t('modals.dashboard.rename-resume.form.slug.label')}
label={t<string>('modals.dashboard.rename-resume.form.slug.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -17,6 +17,7 @@ const i18nConfig = {
'ml',
'nl',
'pl',
'pt',
'ru',
'ta',
'tr',

View File

@ -12,7 +12,7 @@ const nextConfig = {
},
images: {
domains: ['www.gravatar.com'],
domains: ['cdn.rxresu.me', 'www.gravatar.com'],
},
async rewrites() {

View File

@ -9,70 +9,70 @@
},
"dependencies": {
"@beam-australia/react-env": "^3.1.1",
"@emotion/css": "^11.7.1",
"@emotion/react": "^11.8.2",
"@emotion/css": "^11.9.0",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@hookform/resolvers": "2.8.8",
"@monaco-editor/react": "^4.3.1",
"@mui/icons-material": "^5.5.1",
"@mui/lab": "^5.0.0-alpha.73",
"@mui/material": "^5.5.1",
"@reduxjs/toolkit": "^1.8.0",
"axios": "^0.26.1",
"@monaco-editor/react": "^4.4.4",
"@mui/icons-material": "^5.6.2",
"@mui/lab": "^5.0.0-alpha.79",
"@mui/material": "^5.6.3",
"@reduxjs/toolkit": "^1.8.1",
"axios": "^0.27.2",
"clsx": "^1.1.1",
"dayjs": "^1.11.0",
"dayjs": "^1.11.1",
"downloadjs": "^1.4.7",
"joi": "^17.6.0",
"lodash": "^4.17.21",
"md5-hex": "^4.0.0",
"monaco-editor": "^0.33.0",
"nanoid": "^3.3.1",
"next": "12.1.0",
"next-i18next": "^10.5.0",
"react": ">=17",
"nanoid": "^3.3.3",
"next": "12.1.5",
"next-i18next": "^11.0.0",
"react": "17.0.2",
"react-beautiful-dnd": "^13.1.0",
"react-colorful": "^5.5.1",
"react-dnd": "^15.1.1",
"react-dnd-html5-backend": "^15.1.2",
"react-dom": ">=17",
"react-google-login": "^5.2.2",
"react-hook-form": "^7.28.0",
"react-dnd": "15.1.2",
"react-dnd-html5-backend": "15.1.3",
"react-dom": "17.0.2",
"react-hook-form": "^7.30.0",
"react-hot-toast": "2.2.0",
"react-hotkeys-hook": "^3.4.4",
"react-icons": "^4.3.1",
"react-markdown": "^8.0.1",
"react-query": "^3.34.16",
"react-redux": "^7.2.6",
"react-markdown": "^8.0.3",
"react-query": "^3.38.0",
"react-redux": "^8.0.1",
"react-zoom-pan-pinch": "^2.1.3",
"redux": "^4.1.2",
"redux": "^4.2.0",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"remark-gfm": "^3.0.1",
"sharp": "^0.30.3",
"sharp": "^0.30.4",
"uuid": "^8.3.2",
"webfontloader": "^1.6.28"
},
"devDependencies": {
"@babel/core": "^7.17.7",
"@babel/core": "^7.17.10",
"@reactive-resume/schema": "workspace:*",
"@tailwindcss/typography": "^0.5.2",
"@types/downloadjs": "^1.4.3",
"@types/lodash": "^4.14.180",
"@types/node": "17.0.21",
"@types/react": "17.0.40",
"@types/lodash": "^4.14.182",
"@types/node": "17.0.30",
"@types/react": "17.0.2",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-redux": "^7.1.23",
"@types/tailwindcss": "^3.0.9",
"@types/react-redux": "^7.1.24",
"@types/tailwindcss": "^3.0.10",
"@types/uuid": "^8.3.4",
"@types/webfontloader": "^1.6.34",
"autoprefixer": "^10.4.3",
"eslint": "^8.11.0",
"eslint-config-next": "12.1.0",
"next-sitemap": "^2.5.10",
"postcss": "^8.4.11",
"prettier": "^2.6.0",
"sass": "^1.49.9",
"tailwindcss": "^3.0.23",
"typescript": "<4.6.0"
"autoprefixer": "^10.4.5",
"csstype": "^3.0.11",
"eslint": "^8.14.0",
"eslint-config-next": "12.1.5",
"next-sitemap": "^2.5.20",
"postcss": "^8.4.13",
"prettier": "^2.6.2",
"sass": "^1.51.0",
"tailwindcss": "^3.0.24",
"typescript": "^4.6.4"
}
}

View File

@ -62,7 +62,7 @@ const Build: NextPage<Props> = ({ username, slug }) => {
<div className={styles.container}>
<Head>
<title>
{resume.name} | {t('common.title')}
{resume.name} | {t<string>('common.title')}
</title>
</Head>

View File

@ -4,6 +4,7 @@ import DateAdapter from '@mui/lab/AdapterDayjs';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import Script from 'next/script';
import { appWithTranslation } from 'next-i18next';
import { Toaster } from 'react-hot-toast';
import { QueryClientProvider } from 'react-query';
@ -52,6 +53,8 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
</PersistGate>
</LocalizationProvider>
</ReduxProvider>
<Script src="https://accounts.google.com/gsi/client" />
</>
);
};

View File

@ -33,7 +33,7 @@ const Dashboard: NextPage = () => {
<div className={styles.container}>
<Head>
<title>
{t('dashboard.title')} | {t('common.title')}
{t<string>('dashboard.title')} | {t<string>('common.title')}
</title>
</Head>
@ -51,15 +51,15 @@ const Dashboard: NextPage = () => {
<ResumeCard
modal="dashboard.create-resume"
icon={Add}
title={t('dashboard.create-resume.title')}
subtitle={t('dashboard.create-resume.subtitle')}
title={t<string>('dashboard.create-resume.title')}
subtitle={t<string>('dashboard.create-resume.subtitle')}
/>
<ResumeCard
modal="dashboard.import-external"
icon={ImportExport}
title={t('dashboard.import-external.title')}
subtitle={t('dashboard.import-external.subtitle')}
title={t<string>('dashboard.import-external.title')}
subtitle={t<string>('dashboard.import-external.subtitle')}
/>
{data.map((resume) => (

View File

@ -1,6 +1,6 @@
import { DarkMode, LightMode, Link as LinkIcon } from '@mui/icons-material';
import { Masonry } from '@mui/lab';
import { Button, IconButton } from '@mui/material';
import { Button, IconButton, NoSsr } from '@mui/material';
import type { GetStaticProps, NextPage } from 'next';
import Image from 'next/image';
import Link from 'next/link';
@ -11,7 +11,6 @@ import Testimony from '@/components/landing/Testimony';
import Footer from '@/components/shared/Footer';
import LanguageSwitcher from '@/components/shared/LanguageSwitcher';
import Logo from '@/components/shared/Logo';
import NoSSR from '@/components/shared/NoSSR';
import { screenshots } from '@/config/screenshots';
import { FLAG_DISABLE_SIGNUPS } from '@/constants/flags';
import testimonials from '@/data/testimonials';
@ -55,52 +54,52 @@ const Home: NextPage = () => {
</div>
<div className={styles.main}>
<h1>{t('common.title')}</h1>
<h1>{t<string>('common.title')}</h1>
<h2>{t('common.subtitle')}</h2>
<h2>{t<string>('common.subtitle')}</h2>
<NoSSR>
<NoSsr>
<div className={styles.buttonWrapper}>
{isLoggedIn ? (
<>
<Link href="/dashboard" passHref>
<Button>{t('landing.actions.app')}</Button>
<Button>{t<string>('landing.actions.app')}</Button>
</Link>
<Button variant="outlined" onClick={handleLogout}>
{t('landing.actions.logout')}
{t<string>('landing.actions.logout')}
</Button>
</>
) : (
<>
<Button onClick={handleLogin}>{t('landing.actions.login')}</Button>
<Button onClick={handleLogin}>{t<string>('landing.actions.login')}</Button>
<Button variant="outlined" onClick={handleRegister} disabled={FLAG_DISABLE_SIGNUPS}>
{t('landing.actions.register')}
{t<string>('landing.actions.register')}
</Button>
</>
)}
</div>
</NoSSR>
</NoSsr>
</div>
</div>
<section className={styles.section}>
<h6>{t('landing.summary.heading')}</h6>
<h6>{t<string>('landing.summary.heading')}</h6>
<p>{t('landing.summary.body')}</p>
<p>{t<string>('landing.summary.body')}</p>
</section>
<section className={styles.section}>
<h6>{t('landing.features.heading')}</h6>
<h6>{t<string>('landing.features.heading')}</h6>
<ul className="list-inside list-disc leading-loose">
<li>{t('landing.features.list.free')}</li>
<li>{t('landing.features.list.ads')}</li>
<li>{t('landing.features.list.tracking')}</li>
<li>{t('landing.features.list.languages')}</li>
<li>{t('landing.features.list.import')}</li>
<li>{t('landing.features.list.export')}</li>
<li>{t<string>('landing.features.list.free')}</li>
<li>{t<string>('landing.features.list.ads')}</li>
<li>{t<string>('landing.features.list.tracking')}</li>
<li>{t<string>('landing.features.list.languages')}</li>
<li>{t<string>('landing.features.list.import')}</li>
<li>{t<string>('landing.features.list.export')}</li>
<li>
<Trans t={t} i18nKey="landing.features.list.more">
And a lot of exciting features,
@ -113,7 +112,7 @@ const Home: NextPage = () => {
</section>
<section className={styles.section}>
<h6>{t('landing.screenshots.heading')}</h6>
<h6>{t<string>('landing.screenshots.heading')}</h6>
<div className={styles.screenshots}>
{screenshots.map(({ src, alt }) => (
@ -125,7 +124,7 @@ const Home: NextPage = () => {
</section>
<section className={styles.section}>
<h6>{t('landing.testimonials.heading')}</h6>
<h6>{t<string>('landing.testimonials.heading')}</h6>
<p className="my-3">
<Trans t={t} i18nKey="landing.testimonials.body">
@ -150,30 +149,30 @@ const Home: NextPage = () => {
</section>
<section className={styles.section}>
<h6>{t('landing.links.heading')}</h6>
<h6>{t<string>('landing.links.heading')}</h6>
<div>
<Link href="/meta/privacy" passHref>
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.privacy')}
{t<string>('landing.links.links.privacy')}
</Button>
</Link>
<Link href="/meta/service" passHref>
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.service')}
{t<string>('landing.links.links.service')}
</Button>
</Link>
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.github')}
{t<string>('landing.links.links.github')}
</Button>
</a>
<a href={DONATION_URL} target="_blank" rel="noreferrer">
<Button variant="text" startIcon={<LinkIcon />}>
{t('landing.links.links.donate')}
{t<string>('landing.links.links.donate')}
</Button>
</a>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Some files were not shown because too many files have changed in this diff Show More