Compare commits

...

271 Commits

Author SHA1 Message Date
0e1e2bbe4e chore(release): 3.2.7 2022-03-18 09:29:54 +01:00
3a2e62be4c feat(i18n): add Malayalam (മലയാളം) language to i18n locales 2022-03-18 09:27:04 +01:00
697ceef8f2 Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-03-18 09:25:13 +01:00
c8e81a456d Merge pull request #731 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-18 09:25:09 +01:00
2b334e5c5a Merge pull request #727 from chandiwalaaadhar/fix/crash-on-pasting-hex-without-#-prefix
Fix-Crash on Entering Primary Color Hex Code without # Prefix
2022-03-18 09:24:54 +01:00
90321e1284 fix(printer/i18n): fix dates not showing up in resume language when printing
fix #729
2022-03-18 09:24:33 +01:00
9bcddb4b5c New translations modals.json (Malayalam) 2022-03-18 02:48:34 +01:00
72fdc05f69 New translations landing.json (Malayalam) 2022-03-18 02:48:33 +01:00
e1d6540500 New translations dashboard.json (Malayalam) 2022-03-18 02:48:32 +01:00
4b17719c69 New translations common.json (Malayalam) 2022-03-18 02:48:31 +01:00
da056307dd New translations builder.json (Malayalam) 2022-03-18 02:48:29 +01:00
e4950728d8 Refactored- Avoiding modifying the prop 2022-03-18 06:18:17 +05:30
dac4e862b8 Fix-Crash on Entering Primary Color Hex Code without # Prefix 2022-03-17 19:42:26 +05:30
5fa45ef5bd chore(release): 3.2.6 2022-03-17 14:05:31 +01:00
9e6dafc8ca fix(i18n): add missing languages to dayjs date wrapper locales
fix #719
2022-03-17 14:05:13 +01:00
a02b85b4bb fix(linkedin): fix skill modal crashing when importing from linkedin
fix #718
2022-03-17 13:58:49 +01:00
b3ff7805cd fix(json-export): add mimeType and charset to JSON export
fix #726
2022-03-17 13:11:18 +01:00
7f0ee40af4 feat(client/auth/google): disable google login/registration if GOOGLE_CLIENT_ID is not in ENV
fix #724
2022-03-17 12:17:41 +01:00
39fa6da5dd feat(i18n): add arabic language to i18n locale 2022-03-17 12:16:25 +01:00
7fd96a4540 Merge pull request #723 from GovindKrishnan/main
Adding Contributors Wall to README
2022-03-17 07:07:03 +01:00
8f5832b2ca Merge branch 'main' into main 2022-03-17 11:34:46 +05:30
58ce09ee06 Contributors Wall to index.mdx 2022-03-17 11:32:40 +05:30
3f5323d5a3 Update bug-report.md 2022-03-17 07:02:09 +01:00
d62482b280 Merge pull request #722 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-17 06:53:14 +01:00
a609ea551a Merge pull request #720 from chandiwalaaadhar/fix/shared-resume-not-scrollable-on-phone-screen
Fix- Resume Shared is not Scrollable on Phone Screen
2022-03-17 06:52:55 +01:00
1f8e3647d3 Styling 2022-03-16 22:20:58 +05:30
76975ddc6c Adding Contributors Wall to README
Using an open-source web tool called contrib.rocks that sync daily with Contributors Club.

Sort of experimental as I came across this today. But yea, it does no harm to production to say the least. 😅
2022-03-16 22:11:33 +05:30
6ed0bb62b4 New translations modals.json (Arabic) 2022-03-16 17:34:58 +01:00
11d15d8dbb New translations builder.json (Arabic) 2022-03-16 17:34:55 +01:00
7cf92ddb81 New translations dashboard.json (Arabic) 2022-03-16 17:34:53 +01:00
d907b36d59 New translations landing.json (Arabic) 2022-03-16 16:22:21 +01:00
307b626189 Fix- Shared Resume not Scrollable on Phone Screen 2022-03-16 18:45:10 +05:30
f573e60079 Merge pull request #717 from chandiwalaaadhar/fix/integrations-empty-date-sections-not-loading
Fix-Json with Empty Date Strings in Sections doesn't get loaded in the Resume
2022-03-16 11:48:34 +01:00
d3c52476f7 Merge pull request #716 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-16 11:47:00 +01:00
4f9d2ea846 New translations modals.json (Vietnamese) 2022-03-16 09:10:28 +01:00
ec617d682e Revert "Fix- Language Modal Slider Component Label Text Overlapping"
This reverts commit 5a60c99df9.
2022-03-16 13:39:27 +05:30
72d3d46e88 Fix- Integration LinkedIn Empty Date 2022-03-16 13:36:21 +05:30
110797da9d Fix - Integration JSON Resume Empty Date 2022-03-16 13:32:59 +05:30
ab90a2e1dd Fix- Reactive Resume v2 Integration Empty Date 2022-03-16 13:29:37 +05:30
1a3c950847 New translations dashboard.json (Vietnamese) 2022-03-16 08:11:13 +01:00
7fcc792255 New translations landing.json (Vietnamese) 2022-03-16 08:11:10 +01:00
97a13f9f41 New translations builder.json (Vietnamese) 2022-03-16 08:11:08 +01:00
29f1afac9a New translations common.json (Vietnamese) 2022-03-16 08:11:03 +01:00
c5d0abdc79 Merge pull request #714 from chandiwalaaadhar/fix/publication-modal-label-text
Fix- Publication Modal Label text
2022-03-16 07:24:31 +01:00
5a60c99df9 Fix- Language Modal Slider Component Label Text Overlapping 2022-03-16 11:25:48 +05:30
7d188622a8 chore(release): 3.2.5 2022-03-16 06:50:18 +01:00
97e9432d6b feat(i18n): add danish, polish and turkish locales to i18n 2022-03-16 06:48:33 +01:00
c46b8fc162 Fix- Publication Modal Label text 2022-03-16 11:17:33 +05:30
b2f1fb3a55 fix(client/templates): fix text veering off of artboard in most templates
fix #702
2022-03-16 06:41:48 +01:00
4743828e6b chore(deps): update dependencies to match latest patch fixes 2022-03-16 06:40:49 +01:00
519fbbd1b2 Merge pull request #689 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-16 06:21:54 +01:00
ebc084ad52 Create FUNDING.yml 2022-03-16 06:09:50 +01:00
26fdd72610 New translations modals.json (Italian) 2022-03-15 16:28:53 +01:00
ea704c6d99 New translations modals.json (Chinese Simplified) 2022-03-15 16:28:52 +01:00
ea88044d25 New translations modals.json (Bengali) 2022-03-15 16:28:51 +01:00
a461cc147b New translations modals.json (Hindi) 2022-03-15 16:28:50 +01:00
5aefcae2ac New translations modals.json (German) 2022-03-15 16:28:40 +01:00
ba1e968510 New translations modals.json (Spanish) 2022-03-15 16:28:38 +01:00
ba12abe506 New translations modals.json (French) 2022-03-15 16:28:37 +01:00
29fb1dcca3 New translations modals.json (Kannada) 2022-03-15 16:28:14 +01:00
4be6c48aab New translations modals.json (Tamil) 2022-03-15 16:28:13 +01:00
ee1017aa25 Merge pull request #699 from chandiwalaaadhar/fix/pikachu-profile-image-uncontrolled-size
Fix - Pikachu User Image upload, uncontrolled Image Size
2022-03-15 16:25:19 +01:00
bf806c5ecf New translations dashboard.json (Italian) 2022-03-15 15:52:23 +01:00
bf9709ed8e New translations landing.json (Italian) 2022-03-15 15:52:21 +01:00
6c74ecfef7 New translations builder.json (Italian) 2022-03-15 15:52:17 +01:00
fb8c925037 New translations common.json (Italian) 2022-03-15 15:52:13 +01:00
c8c154c2f4 Merge pull request #701 from GovindKrishnan/main
Fixed a Typo in README
2022-03-15 15:15:39 +01:00
92b2c4b757 New translations modals.json (Polish) 2022-03-15 14:41:14 +01:00
260a354c22 New translations dashboard.json (Polish) 2022-03-15 14:41:11 +01:00
c67a969353 New translations landing.json (Polish) 2022-03-15 14:41:09 +01:00
8d61703250 New translations builder.json (Polish) 2022-03-15 14:41:04 +01:00
28df783bba New translations common.json (Polish) 2022-03-15 14:41:03 +01:00
51575a340b New translations modals.json (Danish) 2022-03-15 13:44:39 +01:00
8068d34bf3 New translations dashboard.json (Danish) 2022-03-15 13:44:35 +01:00
b154fae0fa New translations landing.json (Danish) 2022-03-15 13:44:34 +01:00
c5ba1730c3 New translations builder.json (Danish) 2022-03-15 13:44:29 +01:00
a7d90da30e New translations common.json (Danish) 2022-03-15 13:44:26 +01:00
0bbc54a97f Merge pull request #1 from GovindKrishnan/patch-1
Fixed Same Typos in index.mdx
2022-03-15 17:07:47 +05:30
2081f1344f Fixed Same Typos in index.mdx 2022-03-15 17:05:46 +05:30
d029607e16 Fixing Typos in README 2022-03-15 16:46:58 +05:30
5fe0c02cec Fixed a Typo in README
Very trivial. But still, here's my contribution! 😄 

After all, grammar is very important in resumes. 😉
2022-03-15 16:41:10 +05:30
70b45b3686 New translations modals.json (Turkish) 2022-03-15 11:49:35 +01:00
ff098d5df1 New translations landing.json (Turkish) 2022-03-15 11:49:30 +01:00
95d7d70caa New translations builder.json (Turkish) 2022-03-15 10:34:48 +01:00
107ba6e525 New translations common.json (Turkish) 2022-03-15 10:34:45 +01:00
f72e0556e5 Fix - Pikachu User Image after upload covers the center content 2022-03-15 05:57:50 +05:30
0ef975a177 chore(release): 3.2.4 2022-03-14 22:08:16 +01:00
eb9f5450df chore(donation): replace buymeacoffee links with paypal.me links 2022-03-14 22:08:04 +01:00
c7fffff495 chore(release): 3.2.3 2022-03-14 21:50:20 +01:00
42408ce8c5 feat(client/import): implement import json from reactive resume v2 2022-03-14 21:50:04 +01:00
7c49b50979 New translations builder.json (Czech) 2022-03-14 21:27:52 +01:00
59b2fc9fd6 New translations common.json (Portuguese) 2022-03-14 18:58:46 +01:00
f93ac987ac New translations dashboard.json (Turkish) 2022-03-14 16:52:59 +01:00
fb32f9b523 New translations common.json (Arabic) 2022-03-14 16:52:52 +01:00
ed78f8fc4e Merge pull request #687 from chandiwalaaadhar/fix/pikachu-masthead-asymmetric-basic-details
Fix-Pikachu Masthead Basic Details looks asymmetric Due to Centred Alignment
2022-03-14 15:51:16 +01:00
318145f007 Create CODE_OF_CONDUCT.md 2022-03-14 15:09:47 +01:00
c2a35a1066 Merge pull request #685 from chandiwalaaadhar/fix/work-experience-website-link-redirects-404
Fix - Work Experience Website Link Redirects to 404 if manually entered without http/https
2022-03-14 15:08:54 +01:00
541cfa784d Fix-Pikachu Masthead Asymmetric Basic Details 2022-03-14 19:38:49 +05:30
de53d8dfe7 Removed url && in the link prop 2022-03-14 19:32:12 +05:30
c28afbc75d Fix Work Experience Website Link redirects to 404 if entered without http or https 2022-03-14 19:12:36 +05:30
40e6227aa9 chore(release): 3.2.2 2022-03-14 10:28:29 +01:00
02e396bfdb fix(client/skills): make skill level optional 2022-03-14 10:26:57 +01:00
4dc83c1d7f docs(docker): update docs to add docker deployment example to droplet 2022-03-14 10:18:04 +01:00
143a123212 Create docker.mdx 2022-03-14 10:11:52 +01:00
c64b96619f docs(source-code): fix links to docker, local-build on source-code index page 2022-03-14 09:26:15 +01:00
ff35a2a95c chore(release): 3.2.1 2022-03-14 09:23:16 +01:00
549363bbe5 feat(i18n): add Chinese (Simplified) language to locales 2022-03-14 09:23:01 +01:00
e6bda688ac fix(client/basics): fix issue with overlapping photo filters on safari/webkit/iOS 2022-03-14 09:19:22 +01:00
64b0c5e7cf Merge pull request #681 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-14 09:09:26 +01:00
57f7edc134 fix(docker): fix docker-compose for production grade deployments 2022-03-14 09:03:47 +01:00
c62a3c2dfd New translations modals.json (Chinese Simplified) 2022-03-14 07:38:30 +01:00
b7f024913c New translations dashboard.json (Chinese Simplified) 2022-03-14 07:38:28 +01:00
488631e6b0 New translations landing.json (Chinese Simplified) 2022-03-14 07:38:25 +01:00
ca5a866249 New translations builder.json (Chinese Simplified) 2022-03-14 07:38:23 +01:00
3a0cd4e150 New translations common.json (Chinese Simplified) 2022-03-14 07:38:19 +01:00
e82e714e41 chore(release): 3.2.0 2022-03-14 06:40:41 +01:00
21931bc324 feat(i18n): add Bengali, Italian and other languages 2022-03-14 06:40:16 +01:00
ed75a85827 fix(client): fix issue with react-query cache 2022-03-14 06:33:14 +01:00
fbb0285d0d Merge pull request #678 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-14 06:10:51 +01:00
b056b002b7 New translations builder.json (Italian) 2022-03-14 02:04:09 +01:00
8b32bfb9f4 New translations modals.json (Italian) 2022-03-13 22:03:59 +01:00
cf3696c976 New translations dashboard.json (Italian) 2022-03-13 22:03:56 +01:00
aa0dc1d7fb New translations landing.json (Italian) 2022-03-13 22:03:54 +01:00
f5bf77cfd0 New translations builder.json (Italian) 2022-03-13 22:03:51 +01:00
9ddbc7cab2 New translations common.json (Italian) 2022-03-13 22:03:49 +01:00
f7d11c5fd2 New translations landing.json (Bengali) 2022-03-13 21:03:51 +01:00
bede07656b New translations dashboard.json (Bengali) 2022-03-13 21:03:48 +01:00
49b56f7a76 New translations modals.json (Bengali) 2022-03-13 20:08:25 +01:00
1421fc5183 New translations common.json (Bengali) 2022-03-13 20:08:20 +01:00
b3da226d24 New translations builder.json (Bengali) 2022-03-13 20:08:19 +01:00
3d7a5b9313 Merge pull request #675 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-13 19:02:01 +01:00
86ca4602fd Merge pull request #667 from chandiwalaaadhar/fix/skillModal-disable-and-beginner-text-clashing
Fixed Near Overlapping of "Disable" & "Beginner" Label Text in Skills Modal for Desktop Screen
2022-03-13 19:01:52 +01:00
3dde7e5772 Merge pull request #669 from chandiwalaaadhar/fix/gengar-theme-masthead-icons-disapper
Fix-Gengar Theme MastHead Icons Disappear on Theme/Primary Color Change
2022-03-13 19:01:45 +01:00
0782c616ea Merge branch 'main' into fix/gengar-theme-masthead-icons-disapper 2022-03-13 18:56:14 +01:00
d1d3f240b4 Merge branch 'main' of github.com:AmruthPillai/Reactive-Resume 2022-03-13 18:54:03 +01:00
b18120b3f7 fix(app): fix issue with external link redirection in android app 2022-03-13 18:53:48 +01:00
b5809ea449 New translations common.json (Vietnamese) 2022-03-13 17:52:24 +01:00
01acec4a51 New translations common.json (Spanish) 2022-03-13 17:52:21 +01:00
9d076d384c Merge branch 'main' into fix/gengar-theme-masthead-icons-disapper 2022-03-13 21:35:16 +05:30
e7a8596456 Fix-Gengar Theme MastHead Icons Disappear on Theme Change 2022-03-13 12:47:57 +05:30
ab4df6193c Fixed Near Overlapping of Disable & Beginner Text in Skills Modal for Desktop 2022-03-13 12:00:25 +05:30
e4a9f269d2 Merge pull request #662 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-13 07:24:36 +01:00
189cc702c2 New translations modals.json (Italian) 2022-03-13 07:13:32 +01:00
c348b6449b New translations landing.json (Italian) 2022-03-13 07:13:29 +01:00
708920df44 New translations landing.json (German) 2022-03-13 07:13:28 +01:00
81733e5855 New translations landing.json (Spanish) 2022-03-13 07:13:27 +01:00
794c7df374 New translations modals.json (German) 2022-03-13 07:13:24 +01:00
267f593ec2 New translations modals.json (Spanish) 2022-03-13 07:13:23 +01:00
048927a163 New translations dashboard.json (Spanish) 2022-03-13 07:13:16 +01:00
f4a65122c6 New translations dashboard.json (German) 2022-03-13 07:13:15 +01:00
6587c76397 New translations dashboard.json (Italian) 2022-03-13 07:13:14 +01:00
80223a240c New translations builder.json (Italian) 2022-03-13 07:13:12 +01:00
50faa5dff3 New translations modals.json (French) 2022-03-12 20:25:37 +01:00
6a4521b057 New translations landing.json (French) 2022-03-12 20:25:33 +01:00
81a4d7291a New translations dashboard.json (French) 2022-03-12 20:25:32 +01:00
381cfcc220 New translations builder.json (French) 2022-03-12 20:25:28 +01:00
0f555e4f88 New translations common.json (French) 2022-03-12 20:25:27 +01:00
ebd9253038 chore(release): 3.1.4 2022-03-12 19:46:45 +01:00
cf670af403 fix(client): exported pdf did not contain "Present" keyword with translations 2022-03-12 19:46:30 +01:00
dfccb3130f fix(client): fix issues raised through lgtm alerts 2022-03-12 18:56:00 +01:00
ef06240935 docs(readme): add localization percentage badge 2022-03-12 18:47:34 +01:00
55e57353a4 New translations modals.json (Italian) 2022-03-12 18:23:47 +01:00
f0144cc6e7 New translations landing.json (Italian) 2022-03-12 18:23:44 +01:00
e5150ab128 New translations common.json (Italian) 2022-03-12 18:23:40 +01:00
d61905db10 chore(release): 3.1.3 2022-03-12 17:41:29 +01:00
6d55f917ea fix(server): reform url for pdf generation and download
fix #661
2022-03-12 17:41:16 +01:00
4371f3b693 New translations dashboard.json (Italian) 2022-03-12 17:28:42 +01:00
c8c5916d02 Update local-build.mdx 2022-03-12 16:09:08 +01:00
3ca27f2326 docs(style): update CHANGELOG.md 2022-03-12 15:59:34 +01:00
f78f24c972 chore(release): 3.1.2 2022-03-12 15:57:28 +01:00
11cb066573 ci(docker): include traefik routing and proxy to ensure server connections pass in local 2022-03-12 15:55:04 +01:00
528ac84d3b chore(release): 3.1.1 2022-03-12 15:20:01 +01:00
b515fc36e7 feat(client): add product hunt announcement banner 2022-03-12 15:19:19 +01:00
d7268423df chore(release): 3.1.0 2022-03-12 13:01:40 +01:00
bf167f81a3 feat(client): add "spanish (es)" language to i18n locales 2022-03-12 13:01:16 +01:00
9e2f22d878 Merge pull request #654 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-12 12:58:17 +01:00
084b909152 New translations common.json (Hindi) 2022-03-12 12:57:47 +01:00
3955afee8d New translations common.json (German) 2022-03-12 12:57:42 +01:00
f2dd2b5fcf New translations common.json (Kannada) 2022-03-12 12:57:37 +01:00
305561955a New translations common.json (Tamil) 2022-03-12 12:57:36 +01:00
cadbd3dfe8 New translations common.json (Spanish) 2022-03-12 12:57:34 +01:00
b5cd6c412b fix(client): show "present" string if end date is not entered, also add to i18n locales
fix #653
2022-03-12 12:49:11 +01:00
799f20823e fix(server): photo uploads not working, fix save location and returned url
fix #658
2022-03-12 12:37:04 +01:00
dda42b4c6b fix(client): remove hard-coded "keywords:" in certain templates
fix #650
2022-03-12 12:32:35 +01:00
f1c260736a New translations builder.json (Spanish) 2022-03-12 12:16:43 +01:00
b5a9b26f34 New translations builder.json (German) 2022-03-12 12:06:43 +01:00
918bd555c1 New translations builder.json (Spanish) 2022-03-12 12:06:42 +01:00
9ea2775790 New translations builder.json (Kannada) 2022-03-12 12:06:38 +01:00
9d83b997f5 New translations builder.json (Hindi) 2022-03-12 12:06:36 +01:00
228fb42ba5 New translations builder.json (Tamil) 2022-03-12 12:06:35 +01:00
01da1a06b8 feat(client): disable "Toggle Page Orientation" when there's only one page on the artboard
fix #655
2022-03-12 11:59:14 +01:00
82bf44daa2 feat(client): add mm/yyyy date option to date format options
fixes #656
2022-03-12 11:48:07 +01:00
2cbc582a12 feat(client): add sitemap generation to next app 2022-03-12 11:44:51 +01:00
2b9f016b95 New translations modals.json (Spanish) 2022-03-12 09:55:25 +01:00
358c97eb71 New translations dashboard.json (Spanish) 2022-03-12 09:55:19 +01:00
76ef513b46 New translations landing.json (Spanish) 2022-03-12 09:55:18 +01:00
497c6e01f1 New translations builder.json (Spanish) 2022-03-12 09:55:14 +01:00
e78c4a9adb New translations common.json (Spanish) 2022-03-12 09:55:12 +01:00
30d0151bdb Merge pull request #646 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-11 20:28:50 +01:00
4dd94c3363 Update CHANGELOG.md 2022-03-11 20:27:25 +01:00
f711b089bc New translations landing.json (German) 2022-03-11 20:25:38 +01:00
01c1125153 New translations modals.json (German) 2022-03-11 20:25:37 +01:00
fa42d82416 New translations dashboard.json (German) 2022-03-11 20:25:32 +01:00
6322d4d105 New translations builder.json (German) 2022-03-11 20:25:28 +01:00
77467929c7 New translations common.json (German) 2022-03-11 20:25:27 +01:00
3a524f9c9c fix(lang): add hi, de to next-i18next 2022-03-11 20:21:35 +01:00
63f900870b chore(release): 3.0.0 2022-03-11 20:03:50 +01:00
32f78e85f7 Merge pull request #645 from AmruthPillai/feat/add-docs-workspace
Add docs powered by Docusaurus v2
2022-03-11 20:03:29 +01:00
1cc2232730 docs(docusaurus): update docs, add languages, ready to build 2022-03-11 20:02:16 +01:00
2ff6761630 Merge branch 'main' into feat/add-docs-workspace 2022-03-11 19:48:35 +01:00
5836e55a36 docs(readme): update readme with languages section, add license badge 2022-03-11 19:42:07 +01:00
ec98c14fbd Create LICENSE 2022-03-11 19:40:38 +01:00
78c1f5a380 Delete feature_request.md 2022-03-11 19:29:10 +01:00
808fa45124 Delete bug_report.md 2022-03-11 19:29:04 +01:00
2625ed4f3d Merge pull request #644 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-11 19:27:42 +01:00
40085f8d78 New translations modals.json (Hindi) 2022-03-11 19:26:50 +01:00
f4e3be178c New translations landing.json (German) 2022-03-11 19:26:48 +01:00
601f61c59a New translations dashboard.json (Hindi) 2022-03-11 19:26:47 +01:00
59049e8f77 New translations modals.json (German) 2022-03-11 19:26:45 +01:00
798e77f693 New translations landing.json (Hindi) 2022-03-11 19:26:44 +01:00
78565079e7 New translations common.json (Hindi) 2022-03-11 19:26:42 +01:00
0bec4cff05 New translations dashboard.json (German) 2022-03-11 19:26:38 +01:00
26dc0069f9 New translations common.json (German) 2022-03-11 19:26:36 +01:00
90bb80b1e2 New translations builder.json (German) 2022-03-11 19:26:35 +01:00
61ed3ff018 New translations modals.json (Kannada) 2022-03-11 19:26:34 +01:00
36a12e82a2 New translations builder.json (Hindi) 2022-03-11 19:26:26 +01:00
a3cf1752cc Merge pull request #643 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-11 19:06:12 +01:00
5b79e23564 Merge branch 'main' into i18n_main 2022-03-11 19:06:05 +01:00
300e4a790d New translations modals.json (Kannada) 2022-03-11 19:04:32 +01:00
ba4666b767 New translations modals.json (Tamil) 2022-03-11 19:04:31 +01:00
b283c6ee8f New translations landing.json (Tamil) 2022-03-11 19:04:29 +01:00
316eca35ef New translations common.json (Kannada) 2022-03-11 19:04:27 +01:00
16c18de964 New translations common.json (Tamil) 2022-03-11 19:04:26 +01:00
0c23af4be8 New translations builder.json (Kannada) 2022-03-11 19:04:25 +01:00
fe1b325fdf New translations builder.json (Tamil) 2022-03-11 19:04:24 +01:00
9395a4d578 docs(style): update CHANGELOG.md 2022-03-11 15:46:49 +01:00
c11f92841b chore(release): 3.0.0-beta.6 2022-03-11 15:44:42 +01:00
2654cba039 fix(webkit): fix issue with webkit not supporting .at() 2022-03-11 15:40:25 +01:00
7d8828a358 fix(i18n): add missing translation keys, update lang/locale logic 2022-03-11 08:43:20 +01:00
8bc7d2599e feat(lang): add language switcher on the landing page, in the footer 2022-03-10 21:59:16 +01:00
036adbfc96 Delete .DS_Store 2022-03-10 15:34:02 +01:00
4b7e43424c style(changelog): add standard-version to automate releases and tags 2022-03-10 15:32:46 +01:00
0f1c3a8142 chore(release): 3.0.0 2022-03-10 15:29:49 +01:00
8dc27ecf07 Merge pull request #641 from AmruthPillai/i18n_main
New Crowdin updates
2022-03-10 14:58:45 +01:00
a05917b00d New translations modals.json (Kannada) 2022-03-10 14:58:17 +01:00
d5f2eea34c New translations landing.json (Kannada) 2022-03-10 14:58:16 +01:00
29bc3f33a6 New translations dashboard.json (Kannada) 2022-03-10 14:58:15 +01:00
b332b77eff New translations dashboard.json (Tamil) 2022-03-10 14:58:14 +01:00
8e09db276e New translations builder.json (Kannada) 2022-03-10 14:58:12 +01:00
2f7cfd2add New translations builder.json (Tamil) 2022-03-10 14:58:11 +01:00
6a4464b239 New translations common.json (Kannada) 2022-03-10 14:29:16 +01:00
972e8b1bcf fix(app): fix issue with using swipelayout 2022-03-10 14:13:54 +01:00
ad916c5b07 Create close-stale.yml 2022-03-10 09:37:47 +01:00
eca80a1663 feat(health): add health checks to server api 2022-03-10 09:25:15 +01:00
8f48f5fcd6 remove codemagic.yaml 2022-03-10 00:18:50 +01:00
40f5111eba update local.properties path 2022-03-10 00:12:33 +01:00
55a09c0c05 remove other group from codemagic.yml 2022-03-09 23:58:25 +01:00
1e72efa7ac ci(codemagic): add android app ci to build and publish automatically 2022-03-09 23:49:22 +01:00
fd752bfd70 Merge pull request #640 from AmruthPillai/feat/android-app
Adding Android App Source Code to the Monorepo
2022-03-09 23:40:56 +01:00
ee328186c8 fix(client): add safety check on path.id split 2022-03-09 23:39:04 +01:00
ecab1e0bfa style(eslint): do not log all files when linting, just errors 2022-03-09 22:43:45 +01:00
cbbdc92c66 style(prettier): add android app to ignore files for eslint, prettier and docker 2022-03-09 22:41:57 +01:00
5d54f8101b feat(app): add an android app that loads beta.rxresu.me through a webview 2022-03-09 22:40:59 +01:00
4fe5788b23 docs(landing): add links to privacy policy and terms of service 2022-03-09 20:19:05 +01:00
612335696c ci(docker): use version instead of commit sha 2022-03-09 19:30:30 +01:00
781dc4d231 ci(release): remove release-it 2022-03-09 19:18:31 +01:00
5d37dcb0ed ci(release-it): add release-it to auto-generate changelogs and release to github 2022-03-09 19:15:20 +01:00
6255849822 fix(printer): fix issue with printer service, locating the right URL of the server 2022-03-09 18:55:17 +01:00
ef3b2c5638 docs(source-code): add docs to build project from source, docker + local build 2022-03-09 14:05:40 +01:00
6c671f2dba Merge branch 'main' into feat/add-docs-workspace 2022-03-09 11:08:17 +01:00
dc4aa0b496 feat(docs): add docusaurus workspace, initial setup of docs 2022-03-08 23:54:00 +01:00
265 changed files with 19265 additions and 1091 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -15,4 +15,7 @@ node_modules
# Docker
Dockerfile
.dockerignore
docker-compose.yml
docker-compose.yml
# Android App
/app

View File

@ -1,26 +1,27 @@
# App
TZ=UTC
SECRET_KEY=change-me
SECRET_KEY=
# URLs
PUBLIC_URL=http://localhost:3000
PUBLIC_URL=http://<SERVER-IP>
PUBLIC_SERVER_URL=http://<SERVER-IP>/api
# Database
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DATABASE=reactive_resume
POSTGRES_DATABASE=postgres
POSTGRES_SSL_CERT=
# Auth
JWT_SECRET=change-me
JWT_SECRET=
JWT_EXPIRY_TIME=604800
# Google
PUBLIC_GOOGLE_CLIENT_ID=change-me
GOOGLE_CLIENT_SECRET=change-me
GOOGLE_API_KEY=change-me
PUBLIC_GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_API_KEY=
# SendGrid (Optional)
SENDGRID_API_KEY=

View File

@ -1,5 +1,6 @@
{
"root": true,
"ignorePatterns": ["/app"],
"parser": "@typescript-eslint/parser",
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
"plugins": ["@typescript-eslint/eslint-plugin", "simple-import-sort", "unused-imports"],

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: https://paypal.me/RajaRajanA

View File

@ -10,6 +10,10 @@ assignees: ''
**Describe the bug**
A clear and concise description of what the bug is.
**Product Flavor**
- [ ] Managed (https://rxresu.me)
- [ ] Self Hosted
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
@ -28,11 +32,5 @@ If applicable, add screenshots to help explain your problem.
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help improve
title: "[BUG] "
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE] "
labels: enhancement
assignees: AmruthPillai
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

16
.github/workflows/close-stale.yml vendored Normal file
View File

@ -0,0 +1,16 @@
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,9 +13,9 @@ jobs:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: slug
name: Get Short Commit SHA
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to Docker
uses: docker/login-action@v1.14.1
@ -31,7 +31,7 @@ jobs:
file: client/Dockerfile
tags: |
amruthpillai/reactive-resume:client-latest
amruthpillai/reactive-resume:client-${{ steps.slug.outputs.sha8 }}
amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
docker_server:
name: Docker (Server)
@ -41,9 +41,9 @@ jobs:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: slug
name: Get Short Commit SHA
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- id: version
name: Get Version
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Login to Docker
uses: docker/login-action@v1.14.1
@ -59,7 +59,7 @@ jobs:
file: server/Dockerfile
tags: |
amruthpillai/reactive-resume:server-latest
amruthpillai/reactive-resume:server-${{ steps.slug.outputs.sha8 }}
amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
github_client:
name: GitHub (Client)
@ -69,9 +69,9 @@ jobs:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: slug
name: Get Short Commit SHA
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- 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
@ -88,7 +88,7 @@ jobs:
file: client/Dockerfile
tags: |
ghcr.io/amruthpillai/reactive-resume:client-latest
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.slug.outputs.sha8 }}
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
github_server:
name: GitHub (Server)
@ -98,9 +98,9 @@ jobs:
- name: Checkout the repository
uses: actions/checkout@v3.0.0
- id: slug
name: Get Short Commit SHA
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
- 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
@ -117,4 +117,4 @@ jobs:
file: server/Dockerfile
tags: |
ghcr.io/amruthpillai/reactive-resume:server-latest
ghcr.io/amruthpillai/reactive-resume:server-${{ steps.slug.outputs.sha8 }}
ghcr.io/amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}

3
.gitignore vendored
View File

@ -5,3 +5,6 @@
# Project Dependencies
node_modules
# macOS
.DS_Store

View File

@ -1,4 +1,32 @@
dist
.next
__ENV.js
node_modules
# Schema
schema/dist
# Server
server/dist
# Client
client/.next
client/public/__ENV.js
# IDEs
.vscode
# Project Metadata
LICENSE
README.md
CHANGELOG.md
# Project Dependencies
node_modules
# Docker
Dockerfile
.dockerignore
docker-compose.yml
# Android App
/app
# Docs
docs/build
docs/.docusaurus

26
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Debug: Server",
"port": 9229,
"restart": true,
"stopOnEntry": false,
"protocol": "inspector"
},
{
"name": "Debug: Client",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev:client",
"console": "integratedTerminal",
"serverReadyAction": {
"pattern": "started server on .+, url: (https?://.+)",
"uriFormat": "%s",
"action": "debugWithChrome"
}
}
]
}

24
.vscode/settings.json vendored
View File

@ -1,15 +1,25 @@
{
"css.validate": false,
"scss.validate": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.wordWrap": "on",
"eslint.workingDirectories": ["schema", "client", "server"],
"i18n-ally.enabledFrameworks": ["i18next"],
"i18n-ally.localesPaths": ["client/public/locales"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.keystyle": "nested"
}
"eslint.workingDirectories": [
"schema",
"client",
"server"
],
"i18n-ally.enabledFrameworks": [
"react"
],
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": [
"client/public/locales"
],
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.sortKeys": true,
"scss.validate": false
}

View File

@ -1,19 +1,155 @@
## v3.0.0-beta.1 (2022-03-09)
# Changelog
### New feature:
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.
- **client/landing**: add testimonials section to landing page([`6f02048`](https://github.com/AmruthPillai/Reactive-Resume/commit/6f02048ebd29b2a5b53aa291e0cdd10df93d032f)) (by Amruth Pillai)
- **client**: add language selector, language detector and privacy/tos pages([`a131bb3`](https://github.com/AmruthPillai/Reactive-Resume/commit/a131bb36525bf85eaee5cdb65542289cdfcff36e)) (by Amruth Pillai)
### [3.2.7](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.6...v3.2.7) (2022-03-18)
### Bugs fixed:
- **pnpm**: install deps to update pnpm-lock.yaml([`54fd97b`](https://github.com/AmruthPillai/Reactive-Resume/commit/54fd97b5ecce629456a0dd1848981658136bbaa9)) (by Amruth Pillai)
- **mail.service**: use sendgrid api instead of nodemailer for better deliverability([`9df1219`](https://github.com/AmruthPillai/Reactive-Resume/commit/9df12194bf465d2f9c040c642036e05edef8d945)) (by Amruth Pillai)
- **printer.service**: add --disable-dev-shm-usage flag to chromium headless playwright browser([`e96b090`](https://github.com/AmruthPillai/Reactive-Resume/commit/e96b09090485fefc044dfc8e3daa9f52e123d946)) (by Amruth Pillai)
- **playwright**: use playwright docker image due to runtime error([`2696a54`](https://github.com/AmruthPillai/Reactive-Resume/commit/2696a54d176dd8821be97881447e075c05f9e8fb)) (by Amruth Pillai)
- **databasemodule**: make ssl optional, pass ca cert as base64 env([`c738f31`](https://github.com/AmruthPillai/Reactive-Resume/commit/c738f311dabdbe77770bb3c33959ac121d60019e)) (by Amruth Pillai)
- **i18n**: load locales from file system, instead of http-backend([`a4983ac`](https://github.com/AmruthPillai/Reactive-Resume/commit/a4983ac6bc35efee5b10de0768203dec9110b866)) (by Amruth Pillai)
### Features
### Performance improves:
* **i18n:** add Malayalam (മലയാളം) language to i18n locales ([3a2e62b](https://github.com/AmruthPillai/Reactive-Resume/commit/3a2e62be4c9acc14f17277c060cc9ea2c417a478))
- **app**: working docker build stage, with github actions ci to push image([`5104ea6`](https://github.com/AmruthPillai/Reactive-Resume/commit/5104ea6438d5e37d6c591949d6b3861cef4295b7)) (by Amruth Pillai)
### Bug Fixes
* **printer/i18n:** fix dates not showing up in resume language when printing ([90321e1](https://github.com/AmruthPillai/Reactive-Resume/commit/90321e1284409ab9442883c04a9b4c591d36f95d)), closes [#729](https://github.com/AmruthPillai/Reactive-Resume/issues/729)
### [3.2.6](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.5...v3.2.6) (2022-03-17)
### Features
* **client/auth/google:** disable google login/registration if GOOGLE_CLIENT_ID is not in ENV ([7f0ee40](https://github.com/AmruthPillai/Reactive-Resume/commit/7f0ee40af4acc7eb41514406ecee3218ace9e891)), closes [#724](https://github.com/AmruthPillai/Reactive-Resume/issues/724)
* **i18n:** add arabic language to i18n locale ([39fa6da](https://github.com/AmruthPillai/Reactive-Resume/commit/39fa6da5dd77ce2e12e81530fa18c2eac722c1f2))
### Bug Fixes
* **i18n:** add missing languages to dayjs date wrapper locales ([9e6dafc](https://github.com/AmruthPillai/Reactive-Resume/commit/9e6dafc8cada5c01559894905996b81004bedaec)), closes [#719](https://github.com/AmruthPillai/Reactive-Resume/issues/719)
* **json-export:** add mimeType and charset to JSON export ([b3ff780](https://github.com/AmruthPillai/Reactive-Resume/commit/b3ff7805cd856a52900d9acef0554867d8ce0b01)), closes [#726](https://github.com/AmruthPillai/Reactive-Resume/issues/726)
* **linkedin:** fix skill modal crashing when importing from linkedin ([a02b85b](https://github.com/AmruthPillai/Reactive-Resume/commit/a02b85b4bb1c4a1499aacddeac7bc59bcb1f7adb)), closes [#718](https://github.com/AmruthPillai/Reactive-Resume/issues/718)
### [3.2.5](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.4...v3.2.5) (2022-03-16)
### Features
* **i18n:** add danish, polish and turkish locales to i18n ([97e9432](https://github.com/AmruthPillai/Reactive-Resume/commit/97e9432d6bd887e666a3443fbfde9a92cef53965))
### Bug Fixes
* **client/templates:** fix text veering off of artboard in most templates ([b2f1fb3](https://github.com/AmruthPillai/Reactive-Resume/commit/b2f1fb3a5502988a49c5cd3e496d9d165f5c1792)), closes [#702](https://github.com/AmruthPillai/Reactive-Resume/issues/702)
### [3.2.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.3...v3.2.4) (2022-03-14)
### [3.2.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.2...v3.2.3) (2022-03-14)
### Features
* **client/import:** implement import json from reactive resume v2 ([42408ce](https://github.com/AmruthPillai/Reactive-Resume/commit/42408ce8c5ce55904854f9f6e0481889a01edfb8))
### [3.2.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.1...v3.2.2) (2022-03-14)
### Bug Fixes
* **client/skills:** make skill level optional ([02e396b](https://github.com/AmruthPillai/Reactive-Resume/commit/02e396bfdbf07ae75661f1e7e4e55060cacee7d0))
### [3.2.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.0...v3.2.1) (2022-03-14)
### Features
* **i18n:** add Chinese (Simplified) language to locales ([549363b](https://github.com/AmruthPillai/Reactive-Resume/commit/549363bbe5bdd781699dea9506bd4baedf5740d1))
### Bug Fixes
* **client/basics:** fix issue with overlapping photo filters on safari/webkit/iOS ([e6bda68](https://github.com/AmruthPillai/Reactive-Resume/commit/e6bda688ac3ba1c04e82721add92e755ea5386c3))
* **docker:** fix docker-compose for production grade deployments ([57f7edc](https://github.com/AmruthPillai/Reactive-Resume/commit/57f7edc13432a038c907afc6cb74b5182a9b2333))
## [3.2.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.1.4...v3.2.0) (2022-03-14)
### Features
* **i18n:** add Bengali, Italian and other languages ([21931bc](https://github.com/AmruthPillai/Reactive-Resume/commit/21931bc324b5e2440baaaaa2e52a93b4f2c766f8))
### Bug Fixes
* **app:** fix issue with external link redirection in android app ([b18120b](https://github.com/AmruthPillai/Reactive-Resume/commit/b18120b3f7223981e28c0441a6b7725787186edb))
* **client:** fix issue with react-query cache ([ed75a85](https://github.com/AmruthPillai/Reactive-Resume/commit/ed75a858279047dfd43152e041c1a09a625417f5))
### [3.1.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.1.3...v3.1.4) (2022-03-12)
### Bug Fixes
* **client:** exported pdf did not contain "Present" keyword with translations ([cf670af](https://github.com/AmruthPillai/Reactive-Resume/commit/cf670af4035dc9b462cf5b1aad06ca089cf1d40c))
* **client:** fix issues raised through lgtm alerts ([dfccb31](https://github.com/AmruthPillai/Reactive-Resume/commit/dfccb3130f889934d31196226be3d33e772f323b))
### [3.1.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.1.2...v3.1.3) (2022-03-12)
### Bug Fixes
* **server:** reform url for pdf generation and download ([6d55f91](https://github.com/AmruthPillai/Reactive-Resume/commit/6d55f917eab3cb2f5f3a90c5a18f03b625d60021)), closes [#661](https://github.com/AmruthPillai/Reactive-Resume/issues/661)
### [3.1.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.1.1...v3.1.2) (2022-03-12)
### CI
* **docker:**: include traefik routing and proxy to ensure server connections pass in local ([11cb066](https://github.com/AmruthPillai/Reactive-Resume/commit/11cb066573c6917857b79c028b97fcda1acaf90a))
### [3.1.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.1.0...v3.1.1) (2022-03-12)
### Features
* **client:** add product hunt announcement banner ([b515fc3](https://github.com/AmruthPillai/Reactive-Resume/commit/b515fc36e7f282db92e8eb509b6c5004a944fa95))
## [3.1.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.0.0...v3.1.0) (2022-03-12)
### Features
* **client:** add "spanish (es)" language to i18n locales ([bf167f8](https://github.com/AmruthPillai/Reactive-Resume/commit/bf167f81a3659677dada55856f5eaf0fc469e697))
* **client:** add mm/yyyy date option to date format options ([82bf44d](https://github.com/AmruthPillai/Reactive-Resume/commit/82bf44daa24422156779e9b38d3dc695176eaa09)), closes [#656](https://github.com/AmruthPillai/Reactive-Resume/issues/656)
* **client:** add sitemap generation to next app ([2cbc582](https://github.com/AmruthPillai/Reactive-Resume/commit/2cbc582a12b72b3012246022d4b518ed657d4c08))
* **client:** disable "Toggle Page Orientation" when there's only one page on the artboard ([01da1a0](https://github.com/AmruthPillai/Reactive-Resume/commit/01da1a06b802f1063a41d7a9a682e76b1daf9461)), closes [#655](https://github.com/AmruthPillai/Reactive-Resume/issues/655)
### Bug Fixes
* **client:** remove hard-coded "keywords:" in certain templates ([dda42b4](https://github.com/AmruthPillai/Reactive-Resume/commit/dda42b4c6b3bc359ac4f2bb91ca8118ddc84ec07)), closes [#650](https://github.com/AmruthPillai/Reactive-Resume/issues/650)
* **client:** show "present" string if end date is not entered, also add to i18n locales ([b5cd6c4](https://github.com/AmruthPillai/Reactive-Resume/commit/b5cd6c412b5b6b6ca7bb43c3801762de451f06b4)), closes [#653](https://github.com/AmruthPillai/Reactive-Resume/issues/653)
* **server:** photo uploads not working, fix save location and returned url ([799f208](https://github.com/AmruthPillai/Reactive-Resume/commit/799f20823e6d97a1ff0ba2c45c61d56304d0fa58)), closes [#658](https://github.com/AmruthPillai/Reactive-Resume/issues/658)
## [3.0.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.0.0-beta.6...v3.0.0) (2022-03-11)
### Features
* **lang**: add German, Kannada and Tamil languages to the app ([3a524f9](https://github.com/AmruthPillai/Reactive-Resume/commit/3a524f9c9c7a0e446491265b2242ad3dfeae188c))
* **docs:** add docusaurus workspace, initial setup of docs ([dc4aa0b](https://github.com/AmruthPillai/Reactive-Resume/commit/dc4aa0b496096bd59c45426bfcea6ba7db5f5c01))
## [3.0.0-beta.6](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2022-03-11)
### Features
* **lang:** add language switcher on the landing page, in the footer ([8bc7d25](https://github.com/AmruthPillai/Reactive-Resume/commit/8bc7d2599ef6af7a07bfbe886c43844152b0d9f7))
### Bug Fixes
* **i18n:** add missing translation keys, update lang/locale logic ([7d8828a](https://github.com/AmruthPillai/Reactive-Resume/commit/7d8828a358d653bb162877a64c75028eb82678cd))
* **webkit:** fix issue with webkit not supporting .at() ([2654cba](https://github.com/AmruthPillai/Reactive-Resume/commit/2654cba039eb73d33257c36fa90a52cabc9fda96))
## [3.0.0-beta.5](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.0.0-beta.4...v3.0.0-beta.5) (2022-03-10)
### Bug Fixes
* **app:** fix issue with using swipelayout ([972e8b1](https://github.com/AmruthPillai/Reactive-Resume/commit/972e8b1bcf9ad44d8915bf23d189711672937bc0))

128
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
im.amruth@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Amruth Pillai
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

104
README.md
View File

@ -2,10 +2,13 @@
# Reactive Resume
![Project Version](https://img.shields.io/github/package-json/v/AmruthPillai/Reactive-Resume?style=flat-square)
![Project License](https://img.shields.io/github/license/AmruthPillai/Reactive-Resume?style=flat-square)
[![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)
[![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://beta.rxresu.me/)
## [Go to App](https://rxresu.me) | [Docs](https://docs.rxresu.me)
Reactive Resume is a free and open source resume builder thats built to make the mundane tasks of creating, updating and sharing your resume as easy as 1, 2, 3. With this app, you can create multiple resumes, share them with recruiters through a unique link and print as PDF, all for free, no advertisements, without losing the integrity and privacy of your data.
@ -15,13 +18,13 @@ You have complete control over what goes into your resume, how it looks, what co
- Free, forever
- No Advertising
- No Tracking (no 🍪s too)
- No User Tracking
- Sync your data across devices
- Accessible in multiple languages
- Import data from [LinkedIn](https://www.linkedin.com/), [JSON Resume](https://jsonresume.org/)
- Manage multiple resumes with one account
- Open Source (with large community support)
- Send your resume to others with a unique sharable link
- Accessible in multiple languages, [help translate here](https://translate.rxresu.me/)
- Pick any font from [Google Fonts](https://fonts.google.com/) to use on your resume
- Choose from 6 vibrant templates and more coming soon
- Export your resume to JSON or PDF format with just one click
@ -31,64 +34,37 @@ You have complete control over what goes into your resume, how it looks, what co
- Tailor-made Backend and Database, isolated from Google, Amazon etc.
- **Oh, and did I mention that it's free?**
## Docker Setup
## Languages
You can pull the prebuilt docker images right off the shelf from either [Docker Hub](https://hub.docker.com/repository/docker/amruthpillai/reactive-resume) or [GitHub Container Registry](https://ghcr.io/amruthpillai/reactive-resume). Keep in mind, you would also need a database for this to work as intended.
- Arabic (اَلْعَرَبِيَّةُ)
- Bengali (বাংলা)
- Chinese (中文)
- Danish (Dansk)
- English
- French (Français)
- German (Deutsch)
- Hindi (हिन्दी)
- Italian (Italiano)
- Kannada (ಕನ್ನಡ)
- Malayalam (മലയാളം)
- Polish (Polski)
- Spanish (Español)
- Tamil (தமிழ்)
- Turkish (Türkçe)
```sh
# Server
docker run -p 3100:3100 --env-file .env amruthpillai/reactive-resume:server-latest
Help by [translating Reactive Resume](https://translate.rxresu.me) to your language!
# Client
docker run -p 3000:3000 --env-file .env amruthpillai/reactive-resume:client-latest
```
## Tutorial
Or, to make your life easier there's a simple `docker-compose.yml` included to help you get set up for success.
```sh
docker compose up
```
The docs include an extensive [Tutorial](https://docs.rxresu.me/tutorial) section which outline the features of Reactive Resume and help you through building your first resume on the app.
## Build from Source
If you don't want to use Docker, I understand. There's an old-school way to build the app too. This project, and these instructions rely heavily on [pnpm](https://pnpm.io/) so you might want to have that installed on your system before you continue.
1. Clone the repository locally, or use GitHub Codespaces or CodeSandbox
```
git clone https://github.com/AmruthPillai/Reactive-Resume.git
cd Reactive-Resume
```
2. Install dependencies using `pnpm`, but feel free to use any other package manager that supports npm workspaces.
```
pnpm install
```
3. Copy the `.env.example` file to `.env` in the project root and fill it with values according to your setup. You can skip the SendGrid variables if you don't want to set up mail right away.
```
cp .env.example .env
```
1. Use Docker Compose to create a PostgreSQL instance and a `reactive_resume` database, or feel free to use your own and modify the variables used in `.env`
```
docker-compose up -d postgres
```
5. Run the project and start building!
```
pnpm dev
```
For extensive information on how to build the app on your local machine, head over to the docs's [Source Code](https://docs.rxresu.me/source-code) section.
## Contributing
Please refer to the project's style and contribution guidelines for submitting pull requests.
In general, this project follows the "fork-and-pull" Git workflow.
This project makes use of [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) style and workflow for commit messages to ensure that the CHANGELOG is auto-generated. In general, this project follows the "fork-and-pull" Git workflow.
1. **Fork** the repo on GitHub
2. **Clone** the project to your own machine
@ -104,22 +80,32 @@ Use the [GitHub Issues](https://github.com/AmruthPillai/Reactive-Resume/issues/n
## Donations
Reactive Resume would be nothing without the folks who supported me and kept the project alive in the beginning, and your cotinued support is what keeps me going. If you found Reactive Resume to be useful, helpful or just insightful and appreciate the effort I took to make the project, please consider donating as little or as much as your can.
Reactive Resume would be nothing without the folks who supported me and kept the project alive in the beginning, and your continued support is what keeps me going. If you found Reactive Resume to be useful, helpful or just insightful and appreciate the effort I took to make the project, please consider donating as little or as much as you can.
[☕️ Buy me a coffee](https://www.buymeacoffee.com/AmruthPillai)
### [💸 PayPal](https://paypal.me/RajaRajanA)
## Infrastructure
- Next.js, frontend
- NestJS, backend
- PostgreSQL, database
- DigitalOcean, infrastructure provider
- Crowdin, translation management platform
- [Next.js](https://nextjs.org/), frontend
- [NestJS](https://nestjs.com/), backend
- [PostgreSQL](https://www.postgresql.org/), database
- [DigitalOcean](https://www.digitalocean.com/), infrastructure provider
- [Crowdin](https://translate.rxresu.me/), translation management platform
<a href="https://www.digitalocean.com/">
&nbsp;
<a href="https://pillai.xyz/digitalocean">
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_blue.svg" width="200px" />
</a>
## Contributors Wall
<a href="https://github.com/AmruthPillai/Reactive-Resume/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AmruthPillai/Reactive-Resume" />
</a>
_Note: It may take up to 24h for the [contrib.rocks](https://contrib.rocks/image?repo=AmruthPillai/Reactive-Resume) plugin to update because it's refreshed once a day._
## License
Reactive Resume is packaged and distributed using the [MIT License](https://choosealicense.com/licenses/mit/) which allows for commercial use, distribution, modification and private use provided that all copies of the software contain the same license and copyright.

33
app/.gitignore vendored Normal file
View File

@ -0,0 +1,33 @@
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof

8
app/app/.editorconfig Normal file
View File

@ -0,0 +1,8 @@
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

2
app/app/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build
/release

46
app/app/build.gradle Normal file
View File

@ -0,0 +1,46 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 32
defaultConfig {
applicationId "me.rxresu.app"
minSdk 21
targetSdk 32
versionCode 3
versionName "1.0"
resConfigs "en"
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'com.google.android.material:material:1.5.0'
}

21
app/app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="me.rxresu.app">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:configChanges="orientation|screenSize"
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,21 @@
package me.rxresu.app
import android.content.Intent
import android.net.Uri
import android.webkit.WebView
import android.webkit.WebViewClient
internal class CustomWebViewClient : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
val hostname = "rxresu.me"
val uri = Uri.parse(url)
if (uri.host != null && uri.host!!.endsWith(hostname)) {
return false
}
view.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
return true
}
}

View File

@ -0,0 +1,35 @@
package me.rxresu.app
import android.annotation.SuppressLint
import android.os.Bundle
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
private var url = "https://rxresu.me"
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webview)
webView.webViewClient = CustomWebViewClient()
webView.settings.javaScriptEnabled = true
webView.settings.userAgentString = "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Mobile Safari/537.36"
webView.loadUrl(url)
}
override fun onBackPressed() {
if (webView.canGoBack()) {
webView.goBack()
} else {
super.onBackPressed()
}
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<include
layout="@layout/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webview"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Reactive Resume</string>
</resources>

View File

@ -0,0 +1,6 @@
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

9
app/build.gradle Normal file
View File

@ -0,0 +1,9 @@
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
}
task clean(type: Delete) {
delete rootProject.buildDir
}

23
app/gradle.properties Normal file
View File

@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

BIN
app/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Wed Mar 09 21:34:49 CET 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

185
app/gradlew vendored Executable file
View File

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
app/gradlew.bat vendored Normal file
View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

16
app/settings.gradle Normal file
View File

@ -0,0 +1,16 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Reactive Resume"
include ':app'

View File

@ -36,13 +36,14 @@ RUN apk add --no-cache curl \
COPY --from=builder /app/pnpm-*.yaml ./
COPY --from=builder /app/package.json ./
COPY --from=builder /app/client/package.json ./client/package.json
RUN pnpm install -F client --frozen-lockfile --prod
COPY --from=builder /app/client/.next ./client/.next
COPY --from=builder /app/client/public ./client/public
COPY --from=builder /app/client/next.config.js ./client/next.config.js
COPY --from=builder /app/client/next-i18next.config.js ./client/next-i18next.config.js
COPY --from=builder /app/client/package.json ./client/package.json
RUN pnpm install -F client --frozen-lockfile --prod
EXPOSE 3000

View File

@ -33,6 +33,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
const resume = useAppSelector((state) => state.resume);
const isDesktop = useMediaQuery(theme.breakpoints.up('sm'));
const pages = useAppSelector((state) => state.resume.metadata.layout);
const { left, right } = useAppSelector((state) => state.build.sidebar);
const orientation = useAppSelector((state) => state.build.page.orientation);
@ -62,7 +63,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
const url = await mutateAsync({ username, slug });
download(url);
download(`/api${url}`);
};
return (
@ -74,19 +75,19 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
})}
>
<div className={styles.controller}>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-in')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-in') as string}>
<ButtonBase onClick={() => zoomIn(0.25)}>
<ZoomIn fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-out')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-out') as string}>
<ButtonBase onClick={() => zoomOut(0.25)}>
<ZoomOut fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.center-artboard')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.center-artboard') as string}>
<ButtonBase onClick={() => centerView(0.95)}>
<FilterCenterFocus fontSize="medium" />
</ButtonBase>
@ -96,23 +97,25 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
{isDesktop && (
<>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-orientation')}>
<ButtonBase onClick={handleTogglePageOrientation}>
{orientation === 'vertical' ? (
<AlignHorizontalCenter fontSize="medium" />
) : (
<AlignVerticalCenter fontSize="medium" />
)}
</ButtonBase>
</Tooltip>
{pages.length > 1 && (
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-orientation') as string}>
<ButtonBase onClick={handleTogglePageOrientation}>
{orientation === 'vertical' ? (
<AlignHorizontalCenter fontSize="medium" />
) : (
<AlignVerticalCenter fontSize="medium" />
)}
</ButtonBase>
</Tooltip>
)}
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-page-break-line')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-page-break-line') as string}>
<ButtonBase onClick={handleTogglePageBreakLine}>
<InsertPageBreak fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-sidebars')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-sidebars') as string}>
<ButtonBase onClick={handleToggleSidebar}>
<ViewSidebar fontSize="medium" />
</ButtonBase>
@ -122,13 +125,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
</>
)}
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.copy-link')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.copy-link') as string}>
<ButtonBase onClick={handleCopyLink}>
<Link fontSize="medium" />
</ButtonBase>
</Tooltip>
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.export-pdf')}>
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.export-pdf') as string}>
<ButtonBase onClick={handleExportPDF} disabled={isLoading}>
<Download fontSize="medium" />
</ButtonBase>

View File

@ -184,7 +184,7 @@ const Header = () => {
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
</MenuItem>
) : (
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.share-link')}>
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.share-link') as string}>
<div>
<MenuItem>
<ListItemIcon>
@ -196,7 +196,7 @@ const Header = () => {
</Tooltip>
)}
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.delete')}>
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.delete') as string}>
<MenuItem onClick={handleDelete}>
<ListItemIcon>
<Delete className="scale-90" />

View File

@ -27,10 +27,12 @@ const Basics = () => {
<Heading path="sections.basics" name={t('builder.leftSidebar.sections.basics.heading')} />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div className="flex flex-col items-center gap-4 sm:col-span-2 sm:flex-row">
<PhotoUpload />
<div className="grid items-center gap-4 sm:col-span-2 sm:grid-cols-3">
<div className="mx-auto">
<PhotoUpload />
</div>
<div className="flex w-full flex-col-reverse gap-4 sm:flex-col sm:gap-2">
<div className="grid gap-2 w-full sm:col-span-2">
<ResumeInput label={t('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
<Button variant="outlined" startIcon={<PhotoFilter />} onClick={handleClick}>

View File

@ -58,14 +58,14 @@ const PhotoFilters = () => {
<div className="flex items-center">
<FormControlLabel
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label')}
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label') as string}
control={
<Checkbox color="secondary" checked={grayscale} onChange={(_, value) => handleSetGrayscale(value)} />
}
/>
<FormControlLabel
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.border.label')}
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.border.label') as string}
control={<Checkbox color="secondary" checked={border} onChange={(_, value) => handleSetBorder(value)} />}
/>
</div>

View File

@ -67,8 +67,8 @@ const PhotoUpload: React.FC = () => {
<Tooltip
title={
isEmpty(photo.url)
? t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload')
: t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove')
? (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
: (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
}
>
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />

View File

@ -41,7 +41,7 @@ const Profiles = () => {
<footer className="flex justify-end">
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
{t('builder.common.actions.add', {
section: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
})}
</Button>
</footer>

View File

@ -41,14 +41,14 @@ const Section: React.FC<Props> = ({
const visibility = useAppSelector<boolean>((state) => get(state.resume, `${path}.visible`, true));
const handleAdd = () => {
const id = path.split('.').at(-1) as string;
const id = path.split('.')[1];
const modal: ModalName = validate(id) ? 'builder.sections.custom' : `builder.${path}`;
dispatch(setModalState({ modal, state: { open: true, payload: { path } } }));
};
const handleEdit = (item: ListItem) => {
const id = path.split('.').at(-1) as string;
const id = path.split('.')[1];
const modal: ModalName = validate(id) ? 'builder.sections.custom' : `builder.${path}`;
const payload = validate(id) ? { path, item } : { item };

View File

@ -32,7 +32,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
return (
<div>
<Tooltip title={t<string>('builder.common.columns.tooltip')}>
<Tooltip title={t('builder.common.columns.tooltip') as string}>
<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>

View File

@ -34,9 +34,10 @@ const Export = () => {
const redactedResume = pick(resume, ['basics', 'sections', 'metadata', 'public']);
const jsonString = JSON.stringify(redactedResume, null, 4);
const jsonBlob = new Blob([jsonString], { type: 'application/json;charset=utf-8' });
const filename = `RxResume_JSONExport_${nanoid()}.json`;
download(jsonString, filename, 'application/json');
download(jsonBlob, filename);
};
const handleExportPDF = async () => {
@ -47,7 +48,7 @@ const Export = () => {
const url = await mutateAsync({ username, slug });
download(url);
download(`/api${url}`);
};
return (

View File

@ -62,7 +62,7 @@ const Layout = () => {
path="metadata.layout"
name={t('builder.rightSidebar.sections.layout.heading')}
action={
<Tooltip title={t<string>('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
<Tooltip title={t('builder.rightSidebar.sections.layout.tooltip.reset-layout') as string}>
<IconButton onClick={handleResetLayout}>
<Restore />
</IconButton>
@ -81,7 +81,7 @@ const Layout = () => {
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
<Tooltip
title={t<string>('builder.common.actions.delete', { token: t('builder.common.glossary.page') })}
title={t('builder.common.actions.delete', { token: t('builder.common.glossary.page') }) as string}
>
<IconButton size="small" onClick={() => handleDeletePage(pageIndex)}>
<Close fontSize="small" />

View File

@ -13,17 +13,18 @@ import {
import { DateConfig, Resume } from '@reactive-resume/schema';
import dayjs from 'dayjs';
import get from 'lodash/get';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { useMemo } from 'react';
import { useMutation } from 'react-query';
import Heading from '@/components/shared/Heading';
import ThemeSwitch from '@/components/shared/ThemeSwitch';
import { Language, languages } from '@/config/languages';
import { Language, languageMap, languages } from '@/config/languages';
import { ServerError } from '@/services/axios';
import queryClient from '@/services/react-query';
import { loadSampleData, LoadSampleDataParams, resetResume, ResetResumeParams } from '@/services/resume';
import { setLanguage, setTheme, togglePageBreakLine, togglePageOrientation } from '@/store/build/buildSlice';
import { setTheme, togglePageBreakLine, togglePageOrientation } from '@/store/build/buildSlice';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setResumeState } from '@/store/resume/resumeSlice';
import { dateFormatOptions } from '@/utils/date';
@ -33,9 +34,11 @@ const Settings = () => {
const dispatch = useAppDispatch();
const { locale, ...router } = useRouter();
const resume = useAppSelector((state) => state.resume);
const theme = useAppSelector((state) => state.build.theme);
const language = useAppSelector((state) => state.build.language);
const pages = useAppSelector((state) => state.resume.metadata.layout);
const breakLine = useAppSelector((state) => state.build.page.breakLine);
const orientation = useAppSelector((state) => state.build.page.orientation);
@ -59,7 +62,13 @@ const Settings = () => {
dispatch(setResumeState({ path: 'metadata.date.format', value }));
const handleChangeLanguage = (value: Language | null) => {
dispatch(setLanguage({ language: value?.code || 'en' }));
const { pathname, asPath, query, push } = router;
const code = value?.code || 'en';
document.cookie = `NEXT_LOCALE=${code}; path=/; expires=2147483647`;
dispatch(setResumeState({ path: 'metadata.locale', value: code }));
push({ pathname, query }, asPath, { locale: code });
};
const handleLoadSampleData = async () => {
@ -122,7 +131,7 @@ const Settings = () => {
disableClearable
className="my-2 w-full"
options={languages}
value={language}
value={languageMap[locale ?? 'en']}
isOptionEqualToValue={(a, b) => a.code === b.code}
onChange={(_, value) => handleChangeLanguage(value)}
renderInput={(params) => <TextField {...params} />}
@ -144,10 +153,15 @@ const Settings = () => {
<ListItem>
<ListItemText
primary={t('builder.rightSidebar.sections.settings.page.orientation.primary')}
secondary={t('builder.rightSidebar.sections.settings.page.orientation.secondary')}
secondary={
pages.length === 1
? t('builder.rightSidebar.sections.settings.page.orientation.disabled')
: t('builder.rightSidebar.sections.settings.page.orientation.secondary')
}
/>
<Switch
color="secondary"
disabled={pages.length === 1}
checked={orientation === 'horizontal'}
onChange={() => dispatch(togglePageOrientation())}
/>

View File

@ -63,7 +63,7 @@ const Sharing = () => {
<div className="mt-1 flex w-full">
<FormControlLabel
label={t<string>('builder.rightSidebar.sections.sharing.short-url.label')}
label={t('builder.rightSidebar.sections.sharing.short-url.label') as string}
control={
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
}

View File

@ -1,4 +1,4 @@
import { Theme } from '@reactive-resume/schema';
import { Theme as ThemeType } from '@reactive-resume/schema';
import get from 'lodash/get';
import { useTranslation } from 'next-i18next';
@ -16,10 +16,10 @@ const Theme = () => {
const dispatch = useAppDispatch();
const { background, text, primary } = useAppSelector<Theme>((state) => get(state.resume, 'metadata.theme'));
const { background, text, primary } = useAppSelector<ThemeType>((state) => get(state.resume, 'metadata.theme'));
const handleChange = (property: string, color: string) => {
dispatch(setResumeState({ path: `metadata.theme.${property}`, value: color }));
dispatch(setResumeState({ path: `metadata.theme.${property}`, value: color[0] !== '#' ? `#${color}` : color }));
};
return (

View File

@ -161,7 +161,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
</MenuItem>
) : (
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.share-link')}>
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.share-link') as string}>
<div>
<MenuItem>
<ListItemIcon>
@ -173,7 +173,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
</Tooltip>
)}
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.delete')}>
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.delete') as string}>
<MenuItem onClick={handleDelete}>
<ListItemIcon>
<DeleteOutline className="scale-90" />

View File

@ -1,8 +1,8 @@
import { Testimony } from '@/data/testimonials';
import { Testimony as TestimonyType } from '@/data/testimonials';
import styles from './Testimony.module.scss';
type Props = Testimony;
type Props = TestimonyType;
const Testimony: React.FC<Props> = ({ name, message }) => {
return (

View File

@ -8,14 +8,14 @@ import styles from './ArrayInput.module.scss';
type Props = {
label: string;
value: string[];
value?: string[];
className?: string;
onChange: (event: any) => void;
errors?: FieldError | FieldError[];
};
const ArrayInput: React.FC<Props> = ({ value, label, onChange, errors, className }) => {
const [items, setItems] = useState<string[]>(value);
const [items, setItems] = useState<string[]>(value || []);
const onAdd = () => setItems([...items, '']);

View File

@ -12,7 +12,7 @@ const ColorAvatar: React.FC<Props> = ({ color, size = 20, onClick }) => {
return (
<IconButton onClick={handleClick}>
<Avatar sx={{ bgcolor: color, width: size, height: size }}> </Avatar>
<Avatar sx={{ bgcolor: color, width: size, height: size }}>&nbsp;</Avatar>
</IconButton>
);
};

View File

@ -9,8 +9,9 @@ const Footer: React.FC<Props> = ({ className }) => {
const { t } = useTranslation();
return (
<footer className={clsx('text-xs', className)}>
<div className={clsx('text-xs', className)}>
<p>{t('common.footer.license')}</p>
<p>
<Trans t={t} i18nKey="common.footer.credit">
A passion project by
@ -19,7 +20,7 @@ const Footer: React.FC<Props> = ({ className }) => {
</a>
</Trans>
</p>
</footer>
</div>
);
};

View File

@ -37,7 +37,7 @@ const Heading: React.FC<Props> = ({
const [editMode, setEditMode] = useState(false);
const id = useMemo(() => path && path.split('.').at(-1), [path]);
const id = useMemo(() => path.split('.')[1], [path]);
const icon = sections.find((x) => x.id === id)?.icon || <Grade />;
@ -72,19 +72,19 @@ const Heading: React.FC<Props> = ({
})}
>
{isEditable && (
<Tooltip title={t<string>('builder.common.tooltip.rename-section')}>
<Tooltip title={t('builder.common.tooltip.rename-section') as string}>
<IconButton onClick={toggleEditMode}>{editMode ? <Check /> : <DriveFileRenameOutline />}</IconButton>
</Tooltip>
)}
{isHideable && (
<Tooltip title={t<string>('builder.common.tooltip.toggle-visibility')}>
<Tooltip title={t('builder.common.tooltip.toggle-visibility') as string}>
<IconButton onClick={toggleVisibility}>{visibility ? <Visibility /> : <VisibilityOff />}</IconButton>
</Tooltip>
)}
{isDeletable && (
<Tooltip title={t<string>('builder.common.tooltip.delete-section')}>
<Tooltip title={t('builder.common.tooltip.delete-section') as string}>
<IconButton onClick={handleDelete}>
<Delete />
</IconButton>

View File

@ -0,0 +1,13 @@
.popover {
width: 460px;
@apply px-4 py-2;
}
.container {
@apply grid grid-cols-3 items-center justify-center gap-x-2;
}
.language {
@apply py-2 px-4 cursor-pointer text-center hover:underline;
}

View File

@ -0,0 +1,72 @@
import { Language } from '@mui/icons-material';
import { IconButton, Popover } from '@mui/material';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { MouseEvent, useState } from 'react';
import { languages } from '@/config/languages';
import { useAppDispatch } from '@/store/hooks';
import { setResumeState } from '@/store/resume/resumeSlice';
import styles from './LanguageSwitcher.module.scss';
const LanguageSwitcher = () => {
const router = useRouter();
const { t } = useTranslation();
const dispatch = useAppDispatch();
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const handleClick = (event: MouseEvent<HTMLButtonElement>) => setAnchorEl(event.currentTarget);
const handleClose = () => setAnchorEl(null);
const handleChangeLanguage = (locale: string) => {
const { pathname, asPath, query } = router;
document.cookie = `NEXT_LOCALE=${locale}; path=/; expires=2147483647`;
dispatch(setResumeState({ path: 'metadata.locale', value: locale }));
router.push({ pathname, query }, asPath, { locale });
};
return (
<div>
<IconButton onClick={handleClick}>
<Language />
</IconButton>
<Popover
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleClose}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
>
<div className={styles.popover}>
<div className={styles.container}>
{languages.map(({ code, name, localName }) => (
<p key={code} className={styles.language} onClick={() => handleChangeLanguage(code)}>
{name} {localName && `(${localName})`}
</p>
))}
<a href="https://translate.rxresu.me" target="_blank" rel="noreferrer" className={styles.language}>
{t('common.footer.language.missing')}
</a>
</div>
</div>
</Popover>
</div>
);
};
export default LanguageSwitcher;

View File

@ -3,6 +3,7 @@ import { Divider, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, Toolti
import { ListItem as ListItemType } from '@reactive-resume/schema';
import clsx from 'clsx';
import isFunction from 'lodash/isFunction';
import { useTranslation } from 'next-i18next';
import React, { useRef, useState } from 'react';
import { DropTargetMonitor, useDrag, useDrop, XYCoord } from 'react-dnd';
@ -26,6 +27,8 @@ type Props = {
};
const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
const { t } = useTranslation();
const ref = useRef<HTMLDivElement>(null);
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
@ -122,29 +125,25 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
<ListItemIcon>
<DriveFileRenameOutline className="scale-90" />
</ListItemIcon>
<ListItemText>Edit</ListItemText>
<ListItemText>{t('builder.common.list.actions.edit')}</ListItemText>
</MenuItem>
<MenuItem onClick={() => handleDuplicate(item)}>
<ListItemIcon>
<FileCopy className="scale-90" />
</ListItemIcon>
<ListItemText>Duplicate</ListItemText>
<ListItemText>{t('builder.common.list.actions.duplicate')}</ListItemText>
</MenuItem>
<Divider />
<Tooltip
arrow
placement="right"
title="Are you sure you want to delete this item? This is an irreversible action."
>
<Tooltip arrow placement="right" title={t('builder.common.tooltip.delete-item') as string}>
<div>
<MenuItem onClick={() => handleDelete(item)}>
<ListItemIcon>
<DeleteOutline className="scale-90" />
</ListItemIcon>
<ListItemText>Delete</ListItemText>
<ListItemText>{t('builder.common.list.actions.delete')}</ListItemText>
</MenuItem>
</div>
</Tooltip>

View File

@ -5,11 +5,22 @@ export type Language = {
};
export const languages: Language[] = [
{
code: 'en',
name: 'English',
},
];
{ code: 'ar', name: 'Arabic', localName: 'اَلْعَرَبِيَّةُ' },
{ code: 'bn', name: 'Bengali', localName: 'বাংলা' },
{ code: 'da', name: 'Danish', localName: 'Dansk' },
{ code: 'de', name: 'German', localName: 'Deutsch' },
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Spanish', localName: 'Español' },
{ code: 'fr', name: 'French', localName: 'Français' },
{ code: 'hi', name: 'Hindi', localName: 'हिन्दी' },
{ code: 'it', name: 'Italian', localName: 'Italiano' },
{ code: 'kn', name: 'Kannada', localName: 'ಕನ್ನಡ' },
{ code: 'ml', name: 'Malayalam', localName: 'മലയാളം' },
{ code: 'pl', name: 'Polish', localName: 'Polski' },
{ code: 'ta', name: 'Tamil', localName: 'தமிழ்' },
{ code: 'tr', name: 'Turkish', localName: 'Türkçe' },
{ code: 'zh', name: 'Chinese', localName: '中文' },
].sort((a, b) => a.name.localeCompare(b.name));
export const languageMap: Record<string, Language> = languages.reduce(
(acc, lang) => ({

View File

@ -2,10 +2,14 @@
export const FONTS_QUERY = 'fonts';
export const RESUMES_QUERY = 'resumes';
// Regular Expressions
export const VALID_URL_REGEX = /[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/;
// Date Formats
export const FILENAME_TIMESTAMP = 'DDMMYYYYHHmmss';
// Links
export const DONATION_URL = 'https://www.buymeacoffee.com/AmruthPillai';
export const DONATION_URL = 'https://paypal.me/RajaRajanA';
export const GITHUB_URL = 'https://github.com/AmruthPillai/Reactive-Resume';
export const PRODUCT_HUNT_URL = 'https://www.producthunt.com/posts/reactive-resume-v3';
export const GITHUB_ISSUES_URL = 'https://github.com/AmruthPillai/Reactive-Resume/issues/new/choose';

View File

@ -3,6 +3,7 @@ import { joiResolver } from '@hookform/resolvers/joi';
import { Google, Login, Visibility, VisibilityOff } from '@mui/icons-material';
import { Button, IconButton, InputAdornment, TextField } from '@mui/material';
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';
@ -115,15 +116,17 @@ const LoginModal: React.FC = () => {
handleClose={handleClose}
footerChildren={
<div className="flex gap-4">
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.login.actions.login-google')}
</Button>
{!isEmpty(env('GOOGLE_CLIENT_ID')) && (
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.login.actions.google')}
</Button>
)}
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.login.actions.login')}

View File

@ -1,13 +1,16 @@
import env from '@beam-australia/react-env';
import { joiResolver } from '@hookform/resolvers/joi';
import { HowToReg } from '@mui/icons-material';
import { Google, HowToReg } from '@mui/icons-material';
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';
import BaseModal from '@/components/shared/BaseModal';
import { register as registerUser, RegisterParams } from '@/services/auth';
import { loginWithGoogle, LoginWithGoogleParams, register as registerUser, RegisterParams } from '@/services/auth';
import { ServerError } from '@/services/axios';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
@ -56,6 +59,19 @@ const RegisterModal: React.FC = () => {
const { mutateAsync, isLoading } = useMutation<void, ServerError, RegisterParams>(registerUser);
const { mutateAsync: loginWithGoogleMutation } = useMutation<void, ServerError, LoginWithGoogleParams>(
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();
@ -63,7 +79,6 @@ const RegisterModal: React.FC = () => {
const onSubmit = async ({ name, username, email, password }: FormData) => {
await mutateAsync({ name, username, email, password });
handleClose();
};
@ -72,6 +87,10 @@ const RegisterModal: React.FC = () => {
dispatch(setModalState({ modal: 'auth.login', state: { open: true } }));
};
const handleLoginWithGoogle = () => {
signIn();
};
return (
<BaseModal
icon={<HowToReg />}
@ -79,9 +98,23 @@ const RegisterModal: React.FC = () => {
heading={t('modals.auth.register.heading')}
handleClose={handleClose}
footerChildren={
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.register.actions.register')}
</Button>
<div className="flex gap-4">
{!isEmpty(env('GOOGLE_CLIENT_ID')) && (
<Button
type="submit"
variant="outlined"
disabled={isLoading}
startIcon={<Google />}
onClick={handleLoginWithGoogle}
>
{t('modals.auth.register.actions.google')}
</Button>
)}
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
{t('modals.auth.register.actions.register')}
</Button>
</div>
}
>
<p>{t('modals.auth.register.body')}</p>

View File

@ -13,6 +13,7 @@ import { Controller, useForm } from 'react-hook-form';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -34,9 +35,7 @@ const schema = Joi.object<FormData>().keys({
title: Joi.string().required(),
awarder: Joi.string().required(),
date: Joi.string().allow(''),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
});
@ -154,6 +153,7 @@ const AwardModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -13,6 +13,7 @@ import { Controller, useForm } from 'react-hook-form';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -34,9 +35,7 @@ const schema = Joi.object<FormData>().keys({
name: Joi.string().required(),
issuer: Joi.string().required(),
date: Joi.string().allow(''),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
});
@ -154,6 +153,7 @@ const CertificateModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -14,6 +14,7 @@ import { Controller, useForm } from 'react-hook-form';
import ArrayInput from '@/components/shared/ArrayInput';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -47,9 +48,7 @@ const schema = Joi.object<FormData>().keys({
start: Joi.string().allow(''),
end: Joi.string().allow(''),
}),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
level: Joi.string().allow(''),
levelNum: Joi.number().min(0).max(10),
summary: Joi.string().allow(''),
@ -194,6 +193,7 @@ const CustomModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}

View File

@ -14,6 +14,7 @@ import { Controller, useForm } from 'react-hook-form';
import ArrayInput from '@/components/shared/ArrayInput';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -46,9 +47,7 @@ const schema = Joi.object<FormData>().keys({
start: Joi.string().allow(''),
end: Joi.string().allow(''),
}),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
courses: Joi.array().items(Joi.string().optional()),
});
@ -217,6 +216,7 @@ const EducationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}

View File

@ -10,6 +10,7 @@ import { useEffect, useMemo } from 'react';
import { Controller, useForm } from 'react-hook-form';
import BaseModal from '@/components/shared/BaseModal';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -21,17 +22,14 @@ const path = 'sections.profile';
const defaultState: FormData = {
network: '',
username: '',
url: 'https://',
url: '',
};
const schema = Joi.object<FormData>({
id: Joi.string(),
network: Joi.string().required(),
username: Joi.string().required(),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.default('https://')
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
});
const ProfileModal: React.FC = () => {
@ -45,10 +43,10 @@ const ProfileModal: React.FC = () => {
const isEditMode = useMemo(() => !!item, [item]);
const addText = t('builder.common.actions.add', {
section: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
});
const editText = t('builder.common.actions.edit', {
section: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
});
const { reset, control, handleSubmit } = useForm<FormData>({
@ -131,6 +129,7 @@ const ProfileModal: React.FC = () => {
<TextField
label={t('builder.common.form.url.label')}
className="col-span-2"
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -14,6 +14,7 @@ import { Controller, useForm } from 'react-hook-form';
import ArrayInput from '@/components/shared/ArrayInput';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -42,9 +43,7 @@ const schema = Joi.object<FormData>().keys({
start: Joi.string().allow(''),
end: Joi.string().allow(''),
}),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
keywords: Joi.array().items(Joi.string().optional()),
});
@ -187,6 +186,7 @@ const ProjectModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}

View File

@ -13,6 +13,7 @@ import { Controller, useForm } from 'react-hook-form';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -34,9 +35,7 @@ const schema = Joi.object<FormData>().keys({
name: Joi.string().required(),
publisher: Joi.string().required(),
date: Joi.string().allow(''),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
});
@ -116,7 +115,7 @@ const PublicationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
required
label="{t('builder.leftSidebar.sections.publications.form.publisher.label')}"
label={t('builder.leftSidebar.sections.publications.form.publisher.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}
@ -154,6 +153,7 @@ const PublicationModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
error={!!fieldState.error}
helperText={fieldState.error?.message}
{...field}

View File

@ -29,7 +29,7 @@ const defaultState: FormData = {
const schema = Joi.object<FormData>().keys({
id: Joi.string(),
name: Joi.string().required(),
level: Joi.string().required(),
level: Joi.string().allow(''),
levelNum: Joi.number().min(0).max(10).required(),
keywords: Joi.array().items(Joi.string().optional()),
});
@ -109,7 +109,6 @@ const SkillModal: React.FC = () => {
control={control}
render={({ field, fieldState }) => (
<TextField
required
label={t('builder.common.form.level.label')}
error={!!fieldState.error}
helperText={fieldState.error?.message}
@ -125,7 +124,7 @@ const SkillModal: React.FC = () => {
<div className="col-span-2">
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
<div className="px-10">
<div className="px-3">
<Slider
{...field}
marks={[
@ -160,7 +159,7 @@ const SkillModal: React.FC = () => {
render={({ field, fieldState }) => (
<ArrayInput
label={t('builder.common.form.keywords.label')}
value={field.value as string[]}
value={field.value}
onChange={field.onChange}
errors={fieldState.error}
className="col-span-2"

View File

@ -13,6 +13,7 @@ import { Controller, useForm } from 'react-hook-form';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -40,9 +41,7 @@ const schema = Joi.object<FormData>().keys({
start: Joi.string().allow(''),
end: Joi.string().allow(''),
}),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
});
@ -184,6 +183,7 @@ const VolunteerModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}

View File

@ -13,6 +13,7 @@ import { Controller, useForm } from 'react-hook-form';
import BaseModal from '@/components/shared/BaseModal';
import MarkdownSupported from '@/components/shared/MarkdownSupported';
import { VALID_URL_REGEX } from '@/constants/index';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { setModalState } from '@/store/modal/modalSlice';
import { addItem, editItem } from '@/store/resume/resumeSlice';
@ -40,9 +41,7 @@ const schema = Joi.object<FormData>().keys({
start: Joi.string().allow(''),
end: Joi.string().allow(''),
}),
url: Joi.string()
.pattern(/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/, { name: 'valid URL' })
.allow(''),
url: Joi.string().pattern(VALID_URL_REGEX, { name: 'valid URL' }).allow(''),
summary: Joi.string().allow(''),
});
@ -184,6 +183,7 @@ const WorkModal: React.FC = () => {
render={({ field, fieldState }) => (
<TextField
label={t('builder.common.form.url.label')}
placeholder="https://"
className="col-span-2"
error={!!fieldState.error}
helperText={fieldState.error?.message}

View File

@ -125,7 +125,7 @@ const CreateResumeModal: React.FC = () => {
<FormGroup>
<FormControlLabel
label={t<string>('modals.dashboard.create-resume.form.public.label')}
label={t('modals.dashboard.create-resume.form.public.label') as string}
control={
<Controller
name="isPublic"

View File

@ -24,6 +24,7 @@ const ImportExternalModal: React.FC = () => {
const linkedinInputRef = useRef<HTMLInputElement>(null);
const jsonResumeInputRef = useRef<HTMLInputElement>(null);
const reactiveResumeInputRef = useRef<HTMLInputElement>(null);
const reactiveResumeV2InputRef = useRef<HTMLInputElement>(null);
const { open: isOpen } = useAppSelector((state) => state.modal['dashboard.import-external']);
@ -49,6 +50,11 @@ const ImportExternalModal: React.FC = () => {
reactiveResumeInputRef.current.click();
reactiveResumeInputRef.current.value = '';
}
} else if (integration === 'reactive-resume-v2') {
if (reactiveResumeV2InputRef.current) {
reactiveResumeV2InputRef.current.click();
reactiveResumeV2InputRef.current.value = '';
}
}
};
@ -84,7 +90,7 @@ const ImportExternalModal: React.FC = () => {
<p className="mb-2">
<Trans t={t} i18nKey="modals.dashboard.import-external.linkedin.body">
You can save time by exporting your data from LinkedIn and using it to auto-fill fields on Reactive Resume.
Head on over to the
Head over to the
<a
href="https://www.linkedin.com/psettings/member-data"
className="underline"
@ -93,7 +99,7 @@ const ImportExternalModal: React.FC = () => {
>
Data Privacy
</a>
section on LinkedIn and request an archive of your data. Once it is available, upload the ZIP archive below.
section on LinkedIn and request an archive of your data. Once it is available, upload the ZIP file below.
</Trans>
</p>
@ -171,7 +177,7 @@ const ImportExternalModal: React.FC = () => {
<p className="mb-2">{t('modals.dashboard.import-external.reactive-resume.body')}</p>
<div>
<div className="flex gap-4">
<Button
variant="contained"
disabled={isLoading}
@ -181,6 +187,15 @@ const ImportExternalModal: React.FC = () => {
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
</Button>
<Button
variant="contained"
disabled={isLoading}
startIcon={<UploadFile />}
onClick={() => handleClick('reactive-resume-v2')}
>
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
</Button>
<input
hidden
type="file"
@ -188,6 +203,14 @@ const ImportExternalModal: React.FC = () => {
onChange={(event) => handleChange(event, 'reactive-resume')}
accept="application/json"
/>
<input
hidden
type="file"
ref={reactiveResumeV2InputRef}
onChange={(event) => handleChange(event, 'reactive-resume-v2')}
accept="application/json"
/>
</div>
</div>
</BaseModal>

View File

@ -3,7 +3,7 @@ const path = require('path');
const i18nConfig = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'ta'],
locales: ['ar', 'bn', 'da', 'de', 'en', 'es', 'fr', 'hi', 'it', 'kn', 'ml', 'pl', 'ta', 'tr', 'zh'],
},
nsSeparator: '.',
localePath: path.resolve('./public/locales'),

View File

@ -0,0 +1,6 @@
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: 'https://rxresu.me',
changefreq: 'monthly',
generateRobotsTxt: true,
};

View File

@ -2,29 +2,30 @@
"name": "@reactive-resume/client",
"scripts": {
"dev": "react-env --prefix PUBLIC -- next dev",
"build": "next build",
"build": "next build && npm run sitemap",
"start": "react-env --prefix PUBLIC -- next start",
"lint": "next lint --fix"
"lint": "next lint --fix",
"sitemap": "next-sitemap --config next-sitemap.config.js"
},
"dependencies": {
"@beam-australia/react-env": "^3.1.1",
"@emotion/css": "^11.7.1",
"@emotion/react": "^11.8.1",
"@emotion/react": "^11.8.2",
"@emotion/styled": "^11.8.1",
"@hookform/resolvers": "2.8.8",
"@monaco-editor/react": "^4.3.1",
"@mui/icons-material": "^5.5.0",
"@mui/lab": "^5.0.0-alpha.72",
"@mui/material": "^5.5.0",
"@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.0",
"axios": "^0.26.1",
"clsx": "^1.1.1",
"dayjs": "^1.10.8",
"dayjs": "^1.11.0",
"downloadjs": "^1.4.7",
"joi": "^17.6.0",
"lodash": "^4.17.21",
"md5-hex": "^4.0.0",
"monaco-editor": "^0.32.1",
"monaco-editor": "^0.33.0",
"nanoid": "^3.3.1",
"next": "12.1.0",
"next-i18next": "^10.5.0",
@ -35,11 +36,11 @@
"react-dnd-html5-backend": "^15.1.2",
"react-dom": ">=17",
"react-google-login": "^5.2.2",
"react-hook-form": "^7.27.1",
"react-hook-form": "^7.28.0",
"react-hot-toast": "2.2.0",
"react-hotkeys-hook": "^3.4.4",
"react-icons": "^4.3.1",
"react-markdown": "^8.0.0",
"react-markdown": "^8.0.1",
"react-query": "^3.34.16",
"react-redux": "^7.2.6",
"react-zoom-pan-pinch": "^2.1.3",
@ -47,28 +48,29 @@
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"remark-gfm": "^3.0.1",
"sharp": "^0.30.2",
"sharp": "^0.30.3",
"uuid": "^8.3.2",
"webfontloader": "^1.6.28"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@babel/core": "^7.17.7",
"@reactive-resume/schema": "workspace:*",
"@tailwindcss/typography": "^0.5.2",
"@types/downloadjs": "^1.4.3",
"@types/lodash": "^4.14.179",
"@types/lodash": "^4.14.180",
"@types/node": "17.0.21",
"@types/react": "17.0.39",
"@types/react": "17.0.40",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-redux": "^7.1.23",
"@types/tailwindcss": "^3.0.9",
"@types/uuid": "^8.3.4",
"@types/webfontloader": "^1.6.34",
"autoprefixer": "^10.4.2",
"eslint": "^8.10.0",
"autoprefixer": "^10.4.3",
"eslint": "^8.11.0",
"eslint-config-next": "12.1.0",
"postcss": "^8.4.8",
"prettier": "^2.5.1",
"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"

View File

@ -42,6 +42,7 @@ const Build: NextPage<Props> = ({ username, slug }) => {
`resume/${username}/${slug}`,
() => fetchResumeByIdentifier({ username, slug }),
{
cacheTime: 0,
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,

View File

@ -90,7 +90,7 @@ const Preview: NextPage<Props> = ({ username, slug, resume: initialData }) => {
try {
const url = await mutateAsync({ username, slug });
download(url);
download(`/api${url}`);
} catch {
toast.error('Something went wrong, please try again later.');
}

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