Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bf7a168f2e | |||
| 17b1551bab | |||
| 8864243558 | |||
| 37aab7a16f | |||
| 86e1bdf7ea | |||
| 4547fd213d | |||
| 5aacec40cc | |||
| 1df78100ca | |||
| 9cd36fcb9b | |||
| 24b32eb917 | |||
| dec0e41fec | |||
| 42700ad2b2 | |||
| df51d79f6b | |||
| be1673a6a7 | |||
| 648f182e76 | |||
| 3aa56f0886 | |||
| b795534da7 | |||
| c67e2ac9f8 | |||
| beb418bd5d | |||
| 2b3d9533b0 | |||
| b061f139bd | |||
| ac569324cf | |||
| 357d197bb3 | |||
| 5eed1186ff | |||
| a87a9b3247 | |||
| 7f1c82cd91 | |||
| 048c1ed3ed | |||
| 9a2570d7e7 | |||
| 00b9c2156d | |||
| ff8b22274f | |||
| 786937f847 | |||
| c95efee8ec | |||
| 776d2f79a6 | |||
| 25a6b8cce6 | |||
| f6d7cae17b | |||
| 944a0b5fb1 | |||
| 7769653224 | |||
| ccdc5b5fae | |||
| 20158f573e | |||
| 87c60729b5 | |||
| a03a50b7c6 | |||
| fb85ccf501 | |||
| 3179442d8f | |||
| 33d3c52cd9 | |||
| 1d33e01a43 | |||
| 52ff221dd1 | |||
| 5afe178e23 | |||
| 9118b76084 | |||
| 5a62b527b9 | |||
| 2e9e14dc72 | |||
| 0a0b4893aa | |||
| 6277f81e26 | |||
| d550150787 | |||
| 7626b2153f | |||
| 6d17d1001d | |||
| 0273738d7a | |||
| 322df25ecc | |||
| ab3867d9a8 | |||
| 9bf8ec88f4 | |||
| 685f4d37a6 | |||
| f3b3fe8ac9 | |||
| d5fa49172a | |||
| b8303b9977 | |||
| 16d06c6356 | |||
| 79ddd887d9 | |||
| c394bc6725 | |||
| 9e6d7630f4 | |||
| e2fbdd3c2f | |||
| 849171af8f |
5
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
ARG VARIANT="16-bullseye"
|
||||
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||
|
||||
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
27
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "Node.js",
|
||||
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": { "VARIANT": "16-bullseye" }
|
||||
},
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "lokalise.i18n-ally"],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [80, 5432],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "pnpm install",
|
||||
|
||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node",
|
||||
|
||||
"features": {
|
||||
"docker-from-docker": "latest"
|
||||
}
|
||||
}
|
||||
29
.env.example
@ -1,33 +1,28 @@
|
||||
# App
|
||||
# Shared
|
||||
TZ=UTC
|
||||
SECRET_KEY=
|
||||
|
||||
# URLs
|
||||
PUBLIC_URL=http://<SERVER-IP>
|
||||
PUBLIC_SERVER_URL=http://<SERVER-IP>/api
|
||||
PUBLIC_URL=http://localhost
|
||||
PUBLIC_SERVER_URL=http://localhost/api
|
||||
PUBLIC_GOOGLE_CLIENT_ID=
|
||||
|
||||
# Database
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USERNAME=postgres
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DATABASE=postgres
|
||||
POSTGRES_SSL_CERT=
|
||||
|
||||
# Auth
|
||||
# Server
|
||||
SECRET_KEY=
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_SSL_CERT=
|
||||
JWT_SECRET=
|
||||
JWT_EXPIRY_TIME=604800
|
||||
|
||||
# Google
|
||||
PUBLIC_GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
GOOGLE_API_KEY=
|
||||
|
||||
# SendGrid (Optional)
|
||||
SENDGRID_API_KEY=
|
||||
SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID=
|
||||
SENDGRID_FROM_NAME=
|
||||
SENDGRID_FROM_EMAIL=
|
||||
|
||||
# Flags (Optional)
|
||||
# Flags
|
||||
PUBLIC_FLAG_DISABLE_SIGNUPS=false
|
||||
22
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: 'docker'
|
||||
directory: '/server'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
|
||||
- package-ecosystem: 'docker'
|
||||
directory: '/client'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
|
||||
- package-ecosystem: 'gradle'
|
||||
directory: '/app'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
2
.github/workflows/digitalocean-deploy.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Install DigitalOcean CLI
|
||||
uses: digitalocean/action-doctl@v2.1.0
|
||||
uses: digitalocean/action-doctl@v2.1.1
|
||||
with:
|
||||
token: ${{ secrets.DIGITALOCEAN_TOKEN }}
|
||||
|
||||
|
||||
36
.github/workflows/docker-build-push.yml
vendored
@ -17,6 +17,12 @@ jobs:
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1.6.0
|
||||
|
||||
- name: Login to Docker
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
@ -24,11 +30,12 @@ jobs:
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and Push Client Image
|
||||
uses: docker/build-push-action@v2.9.0
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: client/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
amruthpillai/reactive-resume:client-latest
|
||||
amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
|
||||
@ -45,6 +52,12 @@ jobs:
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1.6.0
|
||||
|
||||
- name: Login to Docker
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
@ -52,11 +65,12 @@ jobs:
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and Push Server Image
|
||||
uses: docker/build-push-action@v2.9.0
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: server/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
amruthpillai/reactive-resume:server-latest
|
||||
amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
|
||||
@ -73,6 +87,12 @@ jobs:
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1.6.0
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
@ -81,11 +101,12 @@ jobs:
|
||||
password: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Build and Push Client Image
|
||||
uses: docker/build-push-action@v2.9.0
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: client/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
ghcr.io/amruthpillai/reactive-resume:client-latest
|
||||
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
|
||||
@ -102,6 +123,12 @@ jobs:
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1.6.0
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
@ -110,11 +137,12 @@ jobs:
|
||||
password: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Build and Push Server Image
|
||||
uses: docker/build-push-action@v2.9.0
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: server/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
ghcr.io/amruthpillai/reactive-resume:server-latest
|
||||
ghcr.io/amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
|
||||
|
||||
29
CHANGELOG.md
@ -2,6 +2,35 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [3.3.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.0...v3.3.1) (2022-04-08)
|
||||
|
||||
## [3.3.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.11...v3.3.0) (2022-04-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **upgrade:** changes to code to support new template ([1df7810](https://github.com/AmruthPillai/Reactive-Resume/commit/1df78100ca0667ce9b7834cf2c25384eb21c67c2))
|
||||
|
||||
### What's Changed
|
||||
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/791
|
||||
* Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app by @dependabot in https://github.com/AmruthPillai/Reactive-Resume/pull/812
|
||||
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/806
|
||||
* A new template - Leafish by @klejejs in https://github.com/AmruthPillai/Reactive-Resume/pull/811
|
||||
* Automatic multi-platform Docker image build by @schklom in https://github.com/AmruthPillai/Reactive-Resume/pull/817
|
||||
|
||||
### New Contributors
|
||||
* @klejejs made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/811
|
||||
* @schklom made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/817
|
||||
|
||||
### [3.2.11](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.10...v3.2.11) (2022-03-28)
|
||||
|
||||
### [3.2.10](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.9...v3.2.10) (2022-03-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **i18n:** add portuguese (pt) language to i18n locales ([7f1c82c](https://github.com/AmruthPillai/Reactive-Resume/commit/7f1c82cd9185ebb44486a16132eb44d5c2fb747a))
|
||||
|
||||
### [3.2.9](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.8...v3.2.9) (2022-03-21)
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<img src="https://i.imgur.com/pc8Ingg.png" alt="Reactive Resume" width="256px" height="256px" />
|
||||
<img src="https://github.com/AmruthPillai/Reactive-Resume/blob/main/docs/static/logo.svg" alt="Reactive Resume" width="256px" height="256px" />
|
||||
|
||||
# Reactive Resume
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
[](https://github.com/AmruthPillai/Reactive-Resume/blob/main/LICENSE)
|
||||
[](https://translate.rxresu.me)
|
||||
[](https://hub.docker.com/r/amruthpillai/reactive-resume)
|
||||

|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2FAmruthPillai%2FReactive-Resume?ref=badge_shield)
|
||||
|
||||
## [Go to App](https://rxresu.me) | [Docs](https://docs.rxresu.me)
|
||||
@ -49,6 +50,7 @@ You have complete control over what goes into your resume, how it looks, what co
|
||||
- Kannada (ಕನ್ನಡ)
|
||||
- Malayalam (മലയാളം)
|
||||
- Polish (Polski)
|
||||
- Portuguese (Português)
|
||||
- Russian (русский)
|
||||
- Spanish (Español)
|
||||
- Tamil (தமிழ்)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '7.1.2' apply false
|
||||
id 'com.android.library' version '7.1.2' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.20' apply false
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM node:16-alpine as dependencies
|
||||
FROM node:17-alpine as dependencies
|
||||
|
||||
RUN apk add --no-cache curl g++ make python3 \
|
||||
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
@ -11,7 +11,7 @@ COPY ./client/package.json ./client/package.json
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM node:16-alpine as builder
|
||||
FROM node:17-alpine as builder
|
||||
|
||||
RUN apk add --no-cache curl g++ make python3 \
|
||||
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
@ -27,7 +27,7 @@ COPY --from=dependencies /app/client/node_modules ./client/node_modules
|
||||
RUN pnpm run build:schema
|
||||
RUN pnpm run build:client
|
||||
|
||||
FROM node:16-alpine as production
|
||||
FROM node:17-alpine as production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@ -49,4 +49,7 @@ EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=20s --retries=3 --start-period=15s \
|
||||
CMD curl -fSs 127.0.0.1:3000 || exit 1
|
||||
|
||||
CMD [ "pnpm", "run", "start:client" ]
|
||||
@ -1,10 +1,16 @@
|
||||
.content {
|
||||
@apply rounded p-6 text-sm shadow lg:w-1/2 xl:w-2/5;
|
||||
@apply rounded px-6 text-sm shadow lg:w-1/2 xl:w-2/5;
|
||||
@apply absolute inset-4 sm:inset-x-4 sm:inset-y-auto lg:inset-auto;
|
||||
@apply overflow-scroll bg-neutral-50 dark:bg-neutral-900 lg:overflow-auto;
|
||||
@apply max-h-[90vh] min-h-fit;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply sticky top-0 left-0 right-0 z-50 pt-6 bg-neutral-50 dark:bg-neutral-900;
|
||||
@apply flex items-center justify-between;
|
||||
@apply w-full border-b pb-5 dark:border-white/10;
|
||||
|
||||
@ -27,6 +33,7 @@
|
||||
}
|
||||
|
||||
.footer {
|
||||
@apply sticky bottom-0 left-0 right-0 z-50 pb-6 bg-neutral-50 dark:bg-neutral-900;
|
||||
@apply flex items-center justify-end gap-x-4;
|
||||
@apply w-full border-t pt-5 dark:border-white/10;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ export const languages: Language[] = [
|
||||
{ code: 'ml', name: 'Malayalam', localName: 'മലയാളം' },
|
||||
{ code: 'nl', name: 'Dutch', localName: 'Nederlands' },
|
||||
{ code: 'pl', name: 'Polish', localName: 'Polski' },
|
||||
{ code: 'pt', name: 'Portuguese', localName: 'Português' },
|
||||
{ code: 'ru', name: 'Russian', localName: 'русский' },
|
||||
{ code: 'ta', name: 'Tamil', localName: 'தமிழ்' },
|
||||
{ code: 'tr', name: 'Turkish', localName: 'Türkçe' },
|
||||
|
||||
@ -17,6 +17,7 @@ const i18nConfig = {
|
||||
'ml',
|
||||
'nl',
|
||||
'pl',
|
||||
'pt',
|
||||
'ru',
|
||||
'ta',
|
||||
'tr',
|
||||
|
||||
@ -9,15 +9,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@beam-australia/react-env": "^3.1.1",
|
||||
"@emotion/css": "^11.7.1",
|
||||
"@emotion/react": "^11.8.2",
|
||||
"@emotion/css": "^11.9.0",
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
"@hookform/resolvers": "2.8.8",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@mui/icons-material": "^5.5.1",
|
||||
"@mui/lab": "^5.0.0-alpha.73",
|
||||
"@mui/material": "^5.5.1",
|
||||
"@reduxjs/toolkit": "^1.8.0",
|
||||
"@monaco-editor/react": "^4.4.1",
|
||||
"@mui/icons-material": "^5.6.0",
|
||||
"@mui/lab": "^5.0.0-alpha.76",
|
||||
"@mui/material": "^5.6.0",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"axios": "^0.26.1",
|
||||
"clsx": "^1.1.1",
|
||||
"dayjs": "^1.11.0",
|
||||
@ -26,23 +26,23 @@
|
||||
"lodash": "^4.17.21",
|
||||
"md5-hex": "^4.0.0",
|
||||
"monaco-editor": "^0.33.0",
|
||||
"nanoid": "^3.3.1",
|
||||
"next": "12.1.0",
|
||||
"next-i18next": "^10.5.0",
|
||||
"react": ">=17",
|
||||
"nanoid": "^3.3.2",
|
||||
"next": "12.1.4",
|
||||
"next-i18next": "^11.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-colorful": "^5.5.1",
|
||||
"react-dnd": "^15.1.1",
|
||||
"react-dnd": "^15.1.2",
|
||||
"react-dnd-html5-backend": "^15.1.2",
|
||||
"react-dom": ">=17",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-google-login": "^5.2.2",
|
||||
"react-hook-form": "^7.28.0",
|
||||
"react-hook-form": "^7.29.0",
|
||||
"react-hot-toast": "2.2.0",
|
||||
"react-hotkeys-hook": "^3.4.4",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-markdown": "^8.0.1",
|
||||
"react-query": "^3.34.16",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-markdown": "^8.0.2",
|
||||
"react-query": "^3.34.19",
|
||||
"react-redux": "^7.2.8",
|
||||
"react-zoom-pan-pinch": "^2.1.3",
|
||||
"redux": "^4.1.2",
|
||||
"redux-persist": "^6.0.0",
|
||||
@ -53,25 +53,26 @@
|
||||
"webfontloader": "^1.6.28"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.7",
|
||||
"@babel/core": "^7.17.9",
|
||||
"@reactive-resume/schema": "workspace:*",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@types/downloadjs": "^1.4.3",
|
||||
"@types/lodash": "^4.14.180",
|
||||
"@types/node": "17.0.21",
|
||||
"@types/react": "17.0.40",
|
||||
"@types/lodash": "^4.14.181",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.0",
|
||||
"@types/react-beautiful-dnd": "^13.1.2",
|
||||
"@types/react-redux": "^7.1.23",
|
||||
"@types/tailwindcss": "^3.0.9",
|
||||
"@types/tailwindcss": "^3.0.10",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/webfontloader": "^1.6.34",
|
||||
"autoprefixer": "^10.4.3",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-next": "12.1.0",
|
||||
"next-sitemap": "^2.5.10",
|
||||
"postcss": "^8.4.11",
|
||||
"prettier": "^2.6.0",
|
||||
"sass": "^1.49.9",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"csstype": "^3.0.11",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-config-next": "12.1.4",
|
||||
"next-sitemap": "^2.5.19",
|
||||
"postcss": "^8.4.12",
|
||||
"prettier": "^2.6.2",
|
||||
"sass": "^1.50.0",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "<4.6.0"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 265 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 314 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 319 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 329 KiB After Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 253 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 255 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 83 KiB |
BIN
client/public/images/templates/leafish.jpg
Normal file
|
After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 103 KiB |
358
client/public/locales/pt/builder.json
Normal file
@ -0,0 +1,358 @@
|
||||
{
|
||||
"common": {
|
||||
"actions": {
|
||||
"add": "Adicionar {{token}}",
|
||||
"delete": "Remover {{token}}",
|
||||
"edit": "Editar {{token}}"
|
||||
},
|
||||
"columns": {
|
||||
"heading": "Colunas",
|
||||
"tooltip": "Alterar o número de colunas"
|
||||
},
|
||||
"form": {
|
||||
"date": {
|
||||
"label": "Data"
|
||||
},
|
||||
"description": {
|
||||
"label": "Descrição"
|
||||
},
|
||||
"email": {
|
||||
"label": "Endereço de e-mail"
|
||||
},
|
||||
"end-date": {
|
||||
"help-text": "Deixe este campo em branco se for até o presente",
|
||||
"label": "Data de Término"
|
||||
},
|
||||
"keywords": {
|
||||
"label": "Palavras-chave"
|
||||
},
|
||||
"level": {
|
||||
"label": "Nível"
|
||||
},
|
||||
"levelNum": {
|
||||
"label": "Nível (Número)"
|
||||
},
|
||||
"name": {
|
||||
"label": "Nome"
|
||||
},
|
||||
"phone": {
|
||||
"label": "Número de telefone"
|
||||
},
|
||||
"position": {
|
||||
"label": "Cargo"
|
||||
},
|
||||
"start-date": {
|
||||
"label": "Data de Início"
|
||||
},
|
||||
"subtitle": {
|
||||
"label": "Subtítulo"
|
||||
},
|
||||
"summary": {
|
||||
"label": "Resumo"
|
||||
},
|
||||
"title": {
|
||||
"label": "Título"
|
||||
},
|
||||
"url": {
|
||||
"label": "Site"
|
||||
}
|
||||
},
|
||||
"glossary": {
|
||||
"page": "Página"
|
||||
},
|
||||
"list": {
|
||||
"actions": {
|
||||
"delete": "Excluir",
|
||||
"duplicate": "Duplicar",
|
||||
"edit": "Editar"
|
||||
},
|
||||
"empty-text": "Essa lista está vazia."
|
||||
},
|
||||
"tooltip": {
|
||||
"delete-item": "Tem certeza de que deseja excluir este item? Esta ação é irreversível.",
|
||||
"delete-section": "Excluir Seção",
|
||||
"rename-section": "Renomear Seção",
|
||||
"toggle-visibility": "Alternar Visibilidade"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"tooltip": {
|
||||
"center-artboard": "Prancheta central",
|
||||
"copy-link": "Copiar link do currículo",
|
||||
"export-pdf": "Exportar PDF",
|
||||
"toggle-orientation": "Alternar orientação da página",
|
||||
"toggle-page-break-line": "Alternar linha de quebra de página",
|
||||
"toggle-sidebars": "Alternar barra lateral",
|
||||
"zoom-in": "Mais Zoom",
|
||||
"zoom-out": "Menos Zoom"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"menu": {
|
||||
"delete": "Deletar",
|
||||
"duplicate": "Duplicar",
|
||||
"rename": "Renomear",
|
||||
"share-link": "Compartilhar Link",
|
||||
"tooltips": {
|
||||
"delete": "Tem certeza de que deseja excluir este currículo? Esta ação é irreversível.",
|
||||
"share-link": "Você precisa alterar a visibilidade do seu currículo para público para torná-lo visível para outras pessoas."
|
||||
}
|
||||
}
|
||||
},
|
||||
"leftSidebar": {
|
||||
"sections": {
|
||||
"awards": {
|
||||
"form": {
|
||||
"awarder": {
|
||||
"label": "Concedente"
|
||||
}
|
||||
}
|
||||
},
|
||||
"basics": {
|
||||
"actions": {
|
||||
"photo-filters": "Filtros da foto"
|
||||
},
|
||||
"heading": "Informações básicas",
|
||||
"headline": {
|
||||
"label": "Título"
|
||||
},
|
||||
"name": {
|
||||
"label": "Nome Completo"
|
||||
},
|
||||
"photo-filters": {
|
||||
"effects": {
|
||||
"border": {
|
||||
"label": "Borda"
|
||||
},
|
||||
"grayscale": {
|
||||
"label": "Escala de cinza"
|
||||
},
|
||||
"heading": "Efeitos"
|
||||
},
|
||||
"shape": {
|
||||
"heading": "Forma"
|
||||
},
|
||||
"size": {
|
||||
"heading": "Tamanho (em px)"
|
||||
}
|
||||
},
|
||||
"photo-upload": {
|
||||
"tooltip": {
|
||||
"remove": "Excluir Foto",
|
||||
"upload": "Enviar Foto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certifications": {
|
||||
"form": {
|
||||
"issuer": {
|
||||
"label": "Emissor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"education": {
|
||||
"form": {
|
||||
"area-study": {
|
||||
"label": "Área de estudo"
|
||||
},
|
||||
"courses": {
|
||||
"label": "Cursos"
|
||||
},
|
||||
"degree": {
|
||||
"label": "Grau"
|
||||
},
|
||||
"grade": {
|
||||
"label": "Nota"
|
||||
},
|
||||
"institution": {
|
||||
"label": "Instituição"
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"address": {
|
||||
"label": "Endereço"
|
||||
},
|
||||
"city": {
|
||||
"label": "Cidade"
|
||||
},
|
||||
"country": {
|
||||
"label": "País"
|
||||
},
|
||||
"heading": "Localização",
|
||||
"postal-code": {
|
||||
"label": "Código Postal"
|
||||
},
|
||||
"region": {
|
||||
"label": "Região"
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"form": {
|
||||
"network": {
|
||||
"label": "Rede Social"
|
||||
},
|
||||
"username": {
|
||||
"label": "Nome de Usuário"
|
||||
}
|
||||
},
|
||||
"heading": "Perfis",
|
||||
"heading_one": "Perfil"
|
||||
},
|
||||
"publications": {
|
||||
"form": {
|
||||
"publisher": {
|
||||
"label": "Editor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"references": {
|
||||
"form": {
|
||||
"relationship": {
|
||||
"label": "Relação"
|
||||
}
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"heading": "Seção"
|
||||
},
|
||||
"volunteer": {
|
||||
"form": {
|
||||
"organization": {
|
||||
"label": "Organização"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rightSidebar": {
|
||||
"sections": {
|
||||
"css": {
|
||||
"heading": "CSS Personalizado"
|
||||
},
|
||||
"export": {
|
||||
"heading": "Exportar",
|
||||
"json": {
|
||||
"primary": "JSON",
|
||||
"secondary": "Baixe uma versão JSON do seu currículo que poderá ser importada de volta ao Reactive Resume."
|
||||
},
|
||||
"pdf": {
|
||||
"loading": {
|
||||
"primary": "Gerando PDF",
|
||||
"secondary": "Por favor aguarde enquanto o seu PDF é gerado, isso pode levar até 15 segundos."
|
||||
},
|
||||
"normal": {
|
||||
"primary": "PDF",
|
||||
"secondary": "Baixe um PDF do seu currículo que você pode imprimir e enviar para o emprego dos seus sonhos. Este arquivo não pode ser importado de volta para edição posterior."
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"heading": "Layout",
|
||||
"tooltip": {
|
||||
"reset-layout": "Redefinir Layout"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"bugs-features": {
|
||||
"body": "Alguma coisa te impede de fazer um currículo? Ou você tem uma ideia incrível para adicionar? Crie uma issue no GitHub para começar.",
|
||||
"button": "GitHub Issues",
|
||||
"heading": "Bugs? Sugestões de recursos?"
|
||||
},
|
||||
"donate": {
|
||||
"body": "Se você gostou de usar o Reactive Resume, considere doar o máximo possível para manter o aplicativo em funcionamento, sem anúncios e gratuito para sempre.",
|
||||
"button": "Pague-me um café",
|
||||
"heading": "Faça uma doação ao Reactive Resume"
|
||||
},
|
||||
"github": "Código Fonte",
|
||||
"heading": "Links"
|
||||
},
|
||||
"settings": {
|
||||
"global": {
|
||||
"date": {
|
||||
"primary": "Data",
|
||||
"secondary": "Formato de data usado em todo o aplicativo"
|
||||
},
|
||||
"heading": "Global",
|
||||
"language": {
|
||||
"primary": "Idioma",
|
||||
"secondary": "Idioma de exibição usado em todo o aplicativo"
|
||||
},
|
||||
"theme": {
|
||||
"primary": "Tema"
|
||||
}
|
||||
},
|
||||
"heading": "Configurações",
|
||||
"page": {
|
||||
"break-line": {
|
||||
"primary": "Linha de quebra",
|
||||
"secondary": "Mostrar uma linha em todas as páginas para marcar a altura de uma página A4"
|
||||
},
|
||||
"heading": "Página",
|
||||
"orientation": {
|
||||
"disabled": "Não tem efeito quando há somente uma página",
|
||||
"primary": "Orientação",
|
||||
"secondary": "Se as páginas devem ser exibidas horizontalmente ou verticalmente"
|
||||
}
|
||||
},
|
||||
"resume": {
|
||||
"heading": "Currículo",
|
||||
"reset": {
|
||||
"primary": "Limpar Tudo",
|
||||
"secondary": "Cometeu muitos erros? Clique aqui para redefinir todas as alterações e começar do zero. Tenha cuidado, esta ação não pode ser revertida."
|
||||
},
|
||||
"sample": {
|
||||
"primary": "Carregar dados de exemplo",
|
||||
"secondary": "Não sabe por onde começar? Clique aqui para carregar alguns dados de exemplo para ver como é um currículo completo."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sharing": {
|
||||
"heading": "Compartilhamento",
|
||||
"short-url": {
|
||||
"label": "Prefiro um URL curto"
|
||||
},
|
||||
"visibility": {
|
||||
"subtitle": "Permitir que qualquer um com um link veja seu currículo",
|
||||
"title": "Público"
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"heading": "Modelos"
|
||||
},
|
||||
"theme": {
|
||||
"form": {
|
||||
"background": {
|
||||
"label": "Plano de fundo"
|
||||
},
|
||||
"primary": {
|
||||
"label": "Primário"
|
||||
},
|
||||
"text": {
|
||||
"label": "Texto"
|
||||
}
|
||||
},
|
||||
"heading": "Tema"
|
||||
},
|
||||
"typography": {
|
||||
"form": {
|
||||
"font-family": {
|
||||
"label": "Família da fonte"
|
||||
},
|
||||
"font-size": {
|
||||
"label": "Tamanho da fonte"
|
||||
}
|
||||
},
|
||||
"heading": "Tipografia",
|
||||
"widgets": {
|
||||
"body": {
|
||||
"label": "Corpo"
|
||||
},
|
||||
"headings": {
|
||||
"label": "Cabeçalho"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,10 +10,10 @@
|
||||
"license": "Pela comunidade, para a comunidade."
|
||||
},
|
||||
"markdown": {
|
||||
"help-text": "Esta secção suporta formatação <1>markdown</1>."
|
||||
"help-text": "Esta seção suporta formatação <1>markdown</1>."
|
||||
},
|
||||
"date": {
|
||||
"present": "Presente"
|
||||
"present": "presente"
|
||||
},
|
||||
"subtitle": "Gerador de currículos gratuito e de código aberto.",
|
||||
"title": "Reactive Resume",
|
||||
|
||||
25
client/public/locales/pt/dashboard.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"create-resume": {
|
||||
"subtitle": "Começar do zero",
|
||||
"title": "Criar Novo Currículo"
|
||||
},
|
||||
"import-external": {
|
||||
"subtitle": "LinkedIn, currículo em JSON, Reactive Resume",
|
||||
"title": "Importar de fontes externas"
|
||||
},
|
||||
"resume": {
|
||||
"menu": {
|
||||
"delete": "Deletar",
|
||||
"duplicate": "Duplicar",
|
||||
"open": "Abrir",
|
||||
"rename": "Renomear",
|
||||
"share-link": "Compartilhar Link",
|
||||
"tooltips": {
|
||||
"delete": "Tem certeza de que deseja excluir este currículo? Esta ação é irreversível.",
|
||||
"share-link": "Você precisa alterar a visibilidade do seu currículo para público para torná-lo visível para outras pessoas."
|
||||
}
|
||||
},
|
||||
"timestamp": "Última atualização há {{timestamp}}"
|
||||
},
|
||||
"title": "Painel de Controle"
|
||||
}
|
||||
41
client/public/locales/pt/landing.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"actions": {
|
||||
"app": "Rodar aplicativo",
|
||||
"login": "Entrar",
|
||||
"logout": "Encerrar",
|
||||
"register": "Inscrição"
|
||||
},
|
||||
"features": {
|
||||
"heading": "Características",
|
||||
"list": {
|
||||
"ads": "Sem publicidade",
|
||||
"export": "Exporte seu currículo para o formato JSON ou PDF",
|
||||
"free": "Gratuito, para sempre",
|
||||
"import": "Importe dados do LinkedIn, ou de um currículo em JSON",
|
||||
"languages": "Disponível em vários idiomas",
|
||||
"more": "E outros recursos interessantes, <1>veja todos aqui</1>",
|
||||
"tracking": "Sem rastreamento de usuários"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"heading": "Links",
|
||||
"links": {
|
||||
"donate": "Fazer doação",
|
||||
"github": "Código Fonte",
|
||||
"privacy": "Política de privacidade",
|
||||
"service": "Termos de serviço"
|
||||
}
|
||||
},
|
||||
"screenshots": {
|
||||
"heading": "Imagens"
|
||||
},
|
||||
"testimonials": {
|
||||
"heading": "Depoimentos",
|
||||
"body": "Considero importante a sua opinião, positiva ou negativa, a respeito do Reactive Resume, bem como a sua experiência ao usá-lo.<br/>Confira algumas das mensagens enviadas por pessoas de todo o mundo.",
|
||||
"contact": "Envie a sua mensagem por <1>e-mail</1> ou pelo formulário disponível <3>aqui</3>."
|
||||
},
|
||||
"summary": {
|
||||
"body": "O Reactive Resume é um gerador de currículos, gratuito e de código aberto, desenvolvido para facilitar as tarefas tediosas de criação, atualização e divulgação de seu currículo. Este aplicativo possibilita a criação de múltiplos currículos, que podem ser compartilhados com recrutadores ou amigos com um link exclusivo ou impressos como PDF. Tudo isso de graça, sem anúncios, sem rastreamento, mantendo a integridade e privacidade dos seus dados.",
|
||||
"heading": "Resumo"
|
||||
}
|
||||
}
|
||||
136
client/public/locales/pt/modals.json
Normal file
@ -0,0 +1,136 @@
|
||||
{
|
||||
"auth": {
|
||||
"forgot-password": {
|
||||
"actions": {
|
||||
"send-email": "Enviar e-mail de redefinição de senha"
|
||||
},
|
||||
"body": "Basta inserir o endereço de e-mail associado à conta que você gostaria de recuperar.",
|
||||
"form": {
|
||||
"email": {
|
||||
"label": "Endereço de e-mail"
|
||||
}
|
||||
},
|
||||
"heading": "Esqueceu sua senha?",
|
||||
"help-text": "Se a conta existir, você receberá um e-mail com um link para redefinir sua senha."
|
||||
},
|
||||
"login": {
|
||||
"actions": {
|
||||
"login": "Entrar",
|
||||
"google": "Entrar com o Google"
|
||||
},
|
||||
"body": "Por favor, digite seu nome de usuário e senha associados à sua conta para fazer login e acessar, gerenciar e compartilhar seus currículos.",
|
||||
"form": {
|
||||
"password": {
|
||||
"label": "Senha"
|
||||
},
|
||||
"username": {
|
||||
"help-text": "Você também pode inserir seu endereço de e-mail",
|
||||
"label": "Nome de Usuário"
|
||||
}
|
||||
},
|
||||
"heading": "Acesse a sua conta",
|
||||
"recover-text": "Caso tenha esquecido sua senha, você pode <1>recuperar sua conta</1> aqui.",
|
||||
"register-text": "Se não tiver, você pode <1>criar uma conta</1> aqui."
|
||||
},
|
||||
"register": {
|
||||
"actions": {
|
||||
"register": "Registre-se",
|
||||
"google": "Registre-se com o Google"
|
||||
},
|
||||
"body": "Por favor, insira suas informações pessoais para criar uma conta.",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "Confirme a senha"
|
||||
},
|
||||
"email": {
|
||||
"label": "Endereço de e-mail"
|
||||
},
|
||||
"name": {
|
||||
"label": "Nome completo"
|
||||
},
|
||||
"password": {
|
||||
"label": "Senha"
|
||||
},
|
||||
"username": {
|
||||
"label": "Nome de usuário"
|
||||
}
|
||||
},
|
||||
"heading": "Criar uma conta",
|
||||
"loginText": "Se já tem uma conta, você pode <1>entrar aqui</1>."
|
||||
},
|
||||
"reset-password": {
|
||||
"actions": {
|
||||
"set-password": "Definir nova senha"
|
||||
},
|
||||
"body": "Digite uma nova senha para sua conta.",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "Confirme a senha"
|
||||
},
|
||||
"password": {
|
||||
"label": "Senha"
|
||||
}
|
||||
},
|
||||
"heading": "Redefinir sua senha"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"create-resume": {
|
||||
"actions": {
|
||||
"create-resume": "Criar Currículo"
|
||||
},
|
||||
"body": "Comece a construir seu currículo dando-lhe um nome. Pode ser em referência ao cargo para o qual você está se candidatando ou apenas ao seu lanche favorito.",
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "Nome"
|
||||
},
|
||||
"public": {
|
||||
"label": "É publicamente acessível?"
|
||||
},
|
||||
"slug": {
|
||||
"label": "Endereço amigável"
|
||||
}
|
||||
},
|
||||
"heading": "Criar um novo currículo"
|
||||
},
|
||||
"import-external": {
|
||||
"heading": "Importar de fontes externas",
|
||||
"json-resume": {
|
||||
"actions": {
|
||||
"upload-json": "Carregar JSON"
|
||||
},
|
||||
"body": "Se você possui um <1>currículo JSON válido</1>, poderá usá-lo para acelerar seu desenvolvimento no Reactive Resume. Clique no botão abaixo e carregue um arquivo JSON válido para começar.",
|
||||
"heading": "Importar de um currículo JSON"
|
||||
},
|
||||
"linkedin": {
|
||||
"actions": {
|
||||
"upload-archive": "Carregar arquivo ZIP"
|
||||
},
|
||||
"body": "Você pode economizar tempo exportando seus dados do LinkedIn e usando-os para preencher automaticamente os campos no Reactive Resume. Vá para a seção <1>Privacidade dos Dados</1> no LinkedIn e solicite um arquivo com seus dados. Assim que estiver disponível, faça upload do arquivo ZIP abaixo.",
|
||||
"heading": "Importar do LinkedIn"
|
||||
},
|
||||
"reactive-resume": {
|
||||
"actions": {
|
||||
"upload-json": "Carregar JSON",
|
||||
"upload-json-v2": "Carregar JSON do v2"
|
||||
},
|
||||
"body": "Se você possuir um JSON que foi exportado com a versão atual do Reactive Resume, poderá importá-lo de volta aqui para obter uma versão editável novamente.",
|
||||
"heading": "Importe do Reactive Resume"
|
||||
}
|
||||
},
|
||||
"rename-resume": {
|
||||
"actions": {
|
||||
"rename-resume": "Renomear currículo"
|
||||
},
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "Nome"
|
||||
},
|
||||
"slug": {
|
||||
"label": "Endereço amigável"
|
||||
}
|
||||
},
|
||||
"heading": "Renomear o seu currículo"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
client/templates/Leafish/Leafish.module.scss
Normal file
@ -0,0 +1,9 @@
|
||||
.page {}
|
||||
|
||||
.container {
|
||||
@apply grid grid-cols-2 gap-8 px-6 py-4;
|
||||
|
||||
.column {
|
||||
@apply col-span-1 flex flex-col;
|
||||
}
|
||||
}
|
||||
28
client/templates/Leafish/Leafish.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import { PageProps } from '@/utils/template';
|
||||
|
||||
import { getSectionById } from '../sectionMap';
|
||||
import styles from './Leafish.module.scss';
|
||||
import Masthead from './widgets/Masthead';
|
||||
import Section from './widgets/Section';
|
||||
|
||||
const Leafish: React.FC<PageProps> = ({ page }) => {
|
||||
const isFirstPage = useMemo(() => page === 0, [page]);
|
||||
|
||||
const layout: string[][] = useAppSelector((state) => state.resume.metadata.layout[page]);
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
{isFirstPage && <Masthead />}
|
||||
|
||||
<div className={styles.container}>
|
||||
<div className={styles.column}>{layout[0].map((key) => getSectionById(key, Section))}</div>
|
||||
<div className={styles.column}>{layout[1].map((key) => getSectionById(key, Section))}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Leafish;
|
||||
19
client/templates/Leafish/widgets/Heading.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { Theme } from '@reactive-resume/schema';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
|
||||
const Heading: React.FC = ({ children }) => {
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
|
||||
return (
|
||||
<h2
|
||||
className="pb-1 mb-2 font-bold uppercase opacity-75"
|
||||
style={{ borderBottomWidth: '3px', borderColor: theme.primary, color: theme.primary, display: 'inline-block' }}
|
||||
>
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
};
|
||||
|
||||
export default Heading;
|
||||
75
client/templates/Leafish/widgets/Masthead.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import { Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { alpha } from '@mui/material';
|
||||
import { Theme } from '@reactive-resume/schema';
|
||||
import get from 'lodash/get';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import DataDisplay from '@/templates/shared/DataDisplay';
|
||||
import getProfileIcon from '@/utils/getProfileIcon';
|
||||
import { addHttp, formatLocation, getPhotoClassNames } from '@/utils/template';
|
||||
|
||||
const Masthead: React.FC = () => {
|
||||
const { name, photo, headline, summary, email, phone, website, location, profiles } = useAppSelector(
|
||||
(state) => state.resume.basics
|
||||
);
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className="flex items-center gap-4 p-6"
|
||||
id="Masterhead_main"
|
||||
style={{ backgroundColor: alpha(theme.primary, 0.2) }}
|
||||
>
|
||||
<div className="grid flex-1 gap-1">
|
||||
<h1 id="Masterhead_name">{name}</h1>
|
||||
<p style={{ color: theme.primary }} id="Masterhead_headline">
|
||||
{headline}
|
||||
</p>
|
||||
<p className="opacity-75" id="Masterhead_summary">
|
||||
{summary}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{photo.visible && !isEmpty(photo.url) && (
|
||||
<img
|
||||
alt={name}
|
||||
src={photo.url}
|
||||
width={photo.filters.size}
|
||||
height={photo.filters.size}
|
||||
className={getPhotoClassNames(photo.filters)}
|
||||
id="Masterhead_photo"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="grid gap-y-2 px-8 py-4"
|
||||
id="Masterhead_data"
|
||||
style={{ backgroundColor: alpha(theme.primary, 0.4), gridTemplateColumns: `repeat(2, minmax(0, 1fr))` }}
|
||||
>
|
||||
<DataDisplay icon={<Email />} link={`mailto:${email}`}>
|
||||
{email}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Phone />} link={`tel:${phone}`}>
|
||||
{phone}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Public />} link={addHttp(website)}>
|
||||
{website}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Room />}>{formatLocation(location)}</DataDisplay>
|
||||
|
||||
{profiles.map(({ id, username, network, url }) => (
|
||||
<DataDisplay key={id} icon={getProfileIcon(network)} link={url && addHttp(url)}>
|
||||
{username}
|
||||
</DataDisplay>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Masthead;
|
||||
127
client/templates/Leafish/widgets/Section.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
import { Email, Link, Phone } from '@mui/icons-material';
|
||||
import { ListItem, Section as SectionType } from '@reactive-resume/schema';
|
||||
import get from 'lodash/get';
|
||||
import isArray from 'lodash/isArray';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import Markdown from '@/components/shared/Markdown';
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import { SectionProps } from '@/templates/sectionMap';
|
||||
import DataDisplay from '@/templates/shared/DataDisplay';
|
||||
import { formatDateString } from '@/utils/date';
|
||||
import { parseListItemPath } from '@/utils/template';
|
||||
|
||||
import Heading from './Heading';
|
||||
|
||||
const Section: React.FC<SectionProps> = ({
|
||||
path,
|
||||
titlePath = 'title',
|
||||
subtitlePath = 'subtitle',
|
||||
headlinePath = 'headline',
|
||||
keywordsPath = 'keywords',
|
||||
}) => {
|
||||
const section: SectionType = useAppSelector((state) => get(state.resume, path, {}));
|
||||
const dateFormat: string = useAppSelector((state) => get(state.resume, 'metadata.date.format'));
|
||||
const primaryColor: string = useAppSelector((state) => get(state.resume, 'metadata.theme.primary'));
|
||||
|
||||
if (!section.visible) return null;
|
||||
|
||||
if (isArray(section.items) && isEmpty(section.items)) return null;
|
||||
|
||||
return (
|
||||
<section className="mb-4">
|
||||
<Heading>{section.name}</Heading>
|
||||
|
||||
<div
|
||||
className="grid items-start gap-4"
|
||||
style={{ gridTemplateColumns: `repeat(${section.columns}, minmax(0, 1fr))` }}
|
||||
id={`Section_${section.id}`}
|
||||
>
|
||||
{section.items.map((item: ListItem) => {
|
||||
const id = item.id,
|
||||
title = parseListItemPath(item, titlePath),
|
||||
subtitle = parseListItemPath(item, subtitlePath),
|
||||
headline = parseListItemPath(item, headlinePath),
|
||||
keywords: string[] = get(item, keywordsPath),
|
||||
url: string = get(item, 'url'),
|
||||
summary: string = get(item, 'summary'),
|
||||
level: string = get(item, 'level'),
|
||||
levelNum: number = get(item, 'levelNum'),
|
||||
phone: string = get(item, 'phone'),
|
||||
email: string = get(item, 'email'),
|
||||
date = formatDateString(get(item, 'date'), dateFormat);
|
||||
|
||||
return (
|
||||
<div key={id} id={id} className={`grid gap-1 mb-2 Section_${section.id}_inner`}>
|
||||
<div>
|
||||
{title && <div className="font-bold Section_title">{title}</div>}
|
||||
{subtitle && <div className="Section_subtitle">{subtitle}</div>}
|
||||
{date && (
|
||||
<div className="italic text-xs Section_date" style={{ color: primaryColor }}>
|
||||
({date})
|
||||
</div>
|
||||
)}
|
||||
{headline && <div className="opacity-50 Section_headline">{headline}</div>}
|
||||
</div>
|
||||
|
||||
{(level || levelNum > 0) && (
|
||||
<div className="grid gap-1">
|
||||
{level && <span className="opacity-75">{level}</span>}
|
||||
{levelNum > 0 && (
|
||||
<div className="flex">
|
||||
{Array.from(Array(5).keys()).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="mr-1 h-3 w-3 rounded-full border-2"
|
||||
style={{
|
||||
borderColor: primaryColor,
|
||||
backgroundColor: levelNum / (10 / 5) > index ? primaryColor : '',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{summary && (
|
||||
<div>
|
||||
<div className="italic text-xs" style={{ color: primaryColor }}>
|
||||
Overview
|
||||
</div>
|
||||
<Markdown className={`marker:text-[${primaryColor}]`}>{summary}</Markdown>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{url && (
|
||||
<DataDisplay icon={<Link />} link={url} className="text-xs">
|
||||
{url}
|
||||
</DataDisplay>
|
||||
)}
|
||||
|
||||
{keywords && <div>{keywords.join(', ')}</div>}
|
||||
|
||||
{(phone || email) && (
|
||||
<div className="grid gap-1">
|
||||
{phone && (
|
||||
<DataDisplay icon={<Phone />} link={`tel:${phone}`}>
|
||||
{phone}
|
||||
</DataDisplay>
|
||||
)}
|
||||
|
||||
{email && (
|
||||
<DataDisplay icon={<Email />} link={`mailto:${email}`}>
|
||||
{email}
|
||||
</DataDisplay>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Section;
|
||||
@ -4,6 +4,7 @@ import Castform from './Castform/Castform';
|
||||
import Gengar from './Gengar/Gengar';
|
||||
import Glalie from './Glalie/Glalie';
|
||||
import Kakuna from './Kakuna/Kakuna';
|
||||
import Leafish from './Leafish/Leafish';
|
||||
import Onyx from './Onyx/Onyx';
|
||||
import Pikachu from './Pikachu/Pikachu';
|
||||
|
||||
@ -51,6 +52,12 @@ const templateMap: Record<string, TemplateMeta> = {
|
||||
preview: '/images/templates/glalie.jpg',
|
||||
component: Glalie,
|
||||
},
|
||||
leafish: {
|
||||
id: 'leafish',
|
||||
name: 'Leafish',
|
||||
preview: '/images/templates/leafish.jpg',
|
||||
component: Leafish,
|
||||
},
|
||||
};
|
||||
|
||||
export default templateMap;
|
||||
|
||||
@ -23,6 +23,7 @@ const DateWrapper: React.FC = ({ children }) => {
|
||||
require('dayjs/locale/ml');
|
||||
require('dayjs/locale/nl');
|
||||
require('dayjs/locale/pl');
|
||||
require('dayjs/locale/pt');
|
||||
require('dayjs/locale/ru');
|
||||
require('dayjs/locale/ta');
|
||||
require('dayjs/locale/tr');
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
container_name: postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./scripts/database/initialize.sql:/docker-entrypoint-initdb.d/initialize.sql
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
|
||||
traefik:
|
||||
image: traefik
|
||||
container_name: traefik
|
||||
command:
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
ports:
|
||||
- 80:80
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
server:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: server/Dockerfile
|
||||
container_name: server
|
||||
env_file: .env
|
||||
environment:
|
||||
- PUBLIC_URL=http://localhost
|
||||
- POSTGRES_HOST=postgres
|
||||
- POSTGRES_DATABASE=reactive_resume
|
||||
depends_on:
|
||||
- traefik
|
||||
- postgres
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.server.entrypoints=web
|
||||
- traefik.http.routers.server.rule=Host(`localhost`) && PathPrefix(`/api/`)
|
||||
- traefik.http.routers.server.middlewares=server-stripprefix
|
||||
- traefik.http.middlewares.server-stripprefix.stripprefix.prefixes=/api
|
||||
- traefik.http.middlewares.server-stripprefix.stripprefix.forceslash=true
|
||||
|
||||
client:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: client/Dockerfile
|
||||
container_name: client
|
||||
env_file: .env
|
||||
environment:
|
||||
- PUBLIC_SERVER_URL=http://localhost/api
|
||||
depends_on:
|
||||
- traefik
|
||||
- server
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.client.rule=Host(`localhost`)
|
||||
- traefik.http.routers.client.entrypoints=web
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
@ -1,17 +1,57 @@
|
||||
version: '3'
|
||||
|
||||
x-env-shared: &env-shared
|
||||
environment:
|
||||
- TZ=UTC
|
||||
- PUBLIC_URL=http://localhost
|
||||
- PUBLIC_SERVER_URL=http://localhost/api
|
||||
- PUBLIC_GOOGLE_CLIENT_ID=
|
||||
|
||||
x-env-database: &env-database
|
||||
environment:
|
||||
- POSTGRES_DB=postgres
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
|
||||
x-env-server: &env-server
|
||||
environment:
|
||||
- SECRET_KEY=
|
||||
- POSTGRES_HOST=postgres
|
||||
- POSTGRES_PORT=5432
|
||||
- POSTGRES_SSL_CERT=
|
||||
- JWT_SECRET=
|
||||
- JWT_EXPIRY_TIME=604800
|
||||
- PUBLIC_GOOGLE_CLIENT_ID=
|
||||
- GOOGLE_CLIENT_SECRET=
|
||||
- GOOGLE_API_KEY=
|
||||
- SENDGRID_API_KEY=
|
||||
- SENDGRID_FORGOT_PASSWORD_TEMPLATE_ID=
|
||||
- SENDGRID_FROM_NAME=
|
||||
- SENDGRID_FROM_EMAIL=
|
||||
|
||||
x-env-flags: &env-flags
|
||||
environment:
|
||||
- PUBLIC_FLAG_DISABLE_SIGNUPS=false
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
image: postgres:14.2-alpine
|
||||
container_name: postgres
|
||||
<<: *env-database
|
||||
ports:
|
||||
- 5432:5432
|
||||
env_file: .env
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
|
||||
start_period: 15s
|
||||
interval: 30s
|
||||
timeout: 30s
|
||||
retries: 3
|
||||
restart: always
|
||||
|
||||
traefik:
|
||||
image: traefik
|
||||
image: traefik:rocamadour
|
||||
container_name: traefik
|
||||
command:
|
||||
- --providers.docker=true
|
||||
@ -25,31 +65,34 @@ services:
|
||||
server:
|
||||
image: amruthpillai/reactive-resume:server-latest
|
||||
container_name: server
|
||||
env_file: .env
|
||||
environment:
|
||||
- POSTGRES_HOST=postgres
|
||||
<<: *env-shared
|
||||
<<: *env-server
|
||||
<<: *env-database
|
||||
depends_on:
|
||||
- traefik
|
||||
- postgres
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.server.entrypoints=web
|
||||
- traefik.http.routers.server.rule=Host(`<SERVER-IP>`) && PathPrefix(`/api/`)
|
||||
- traefik.http.routers.server.rule=Host(`localhost`) && PathPrefix(`/api/`)
|
||||
- traefik.http.routers.server.middlewares=server-stripprefix
|
||||
- traefik.http.middlewares.server-stripprefix.stripprefix.prefixes=/api
|
||||
- traefik.http.middlewares.server-stripprefix.stripprefix.forceslash=true
|
||||
restart: always
|
||||
|
||||
client:
|
||||
image: amruthpillai/reactive-resume:client-latest
|
||||
container_name: client
|
||||
env_file: .env
|
||||
<<: *env-shared
|
||||
<<: *env-flags
|
||||
depends_on:
|
||||
- traefik
|
||||
- server
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.client.rule=Host(`<SERVER-IP>`)
|
||||
- traefik.http.routers.client.rule=Host(`localhost`)
|
||||
- traefik.http.routers.client.entrypoints=web
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
|
||||
@ -57,6 +57,7 @@ You have complete control over what goes into your resume, how it looks, what co
|
||||
- Kannada (ಕನ್ನಡ)
|
||||
- Malayalam (മലയാളം)
|
||||
- Polish (Polski)
|
||||
- Portuguese (Português)
|
||||
- Russian (русский)
|
||||
- Spanish (Español)
|
||||
- Tamil (தமிழ்)
|
||||
|
||||
@ -65,7 +65,13 @@ This URL is used when export PDF functionality is used within the app and has to
|
||||
**Default Value:** `5432`
|
||||
**Description:** Port of the PostgreSQL Server
|
||||
|
||||
### `POSTGRES_USERNAME`
|
||||
### `POSTGRES_DB`
|
||||
|
||||
**Required**: `yes`
|
||||
**Default Value:** `postgres`
|
||||
**Description:** Name of the Database in PostgreSQL Server
|
||||
|
||||
### `POSTGRES_USER`
|
||||
|
||||
**Required**: `yes`
|
||||
**Default Value:** `postgres`
|
||||
@ -77,12 +83,6 @@ This URL is used when export PDF functionality is used within the app and has to
|
||||
**Default Value:** `postgres`
|
||||
**Description:** Password of the PostgreSQL Server
|
||||
|
||||
### `POSTGRES_DATABASE`
|
||||
|
||||
**Required**: `yes`
|
||||
**Default Value:** `reactive_resume`
|
||||
**Description:** Name of the Database in PostgreSQL Server
|
||||
|
||||
### `POSTGRES_SSL_CERT`
|
||||
|
||||
**Required**: `no`
|
||||
|
||||
@ -15,13 +15,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@algolia/client-search": "^4.13.0",
|
||||
"@docusaurus/core": "2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.17",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@docusaurus/core": "2.0.0-beta.18",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.18",
|
||||
"@mdx-js/react": "^2.1.1",
|
||||
"clsx": "^1.1.1",
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@ -36,6 +36,6 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "17.0.40"
|
||||
"@types/react": "^17.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
16
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "reactive-resume",
|
||||
"version": "3.2.9",
|
||||
"version": "3.3.1",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"schema",
|
||||
@ -34,22 +34,22 @@
|
||||
"start": "env-cmd --silent concurrently --kill-others \"pnpm run start:*\""
|
||||
},
|
||||
"dependencies": {
|
||||
"concurrently": "^7.0.0",
|
||||
"concurrently": "^7.1.0",
|
||||
"env-cmd": "^10.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.15.0",
|
||||
"@typescript-eslint/parser": "^5.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"prettier": "^2.6.0",
|
||||
"prettier": "^2.6.2",
|
||||
"standard-version": "^9.3.2",
|
||||
"typescript": "^4.5.5"
|
||||
"typescript": "<4.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
4428
pnpm-lock.yaml
generated
@ -9,7 +9,7 @@
|
||||
"lint": "eslint --fix --ext .ts ./src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.11.0",
|
||||
"eslint": "^8.12.0",
|
||||
"typescript": "<4.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
create database reactive_resume;
|
||||
grant all privileges on database reactive_resume to postgres;
|
||||
@ -1,4 +1,4 @@
|
||||
FROM node:16-alpine as dependencies
|
||||
FROM node:17-alpine as dependencies
|
||||
|
||||
RUN apk add --no-cache g++ curl make python3 \
|
||||
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
@ -11,7 +11,7 @@ COPY ./server/package.json ./server/package.json
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM node:16-alpine as builder
|
||||
FROM node:17-alpine as builder
|
||||
|
||||
RUN apk add --no-cache g++ curl make python3 \
|
||||
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
@ -47,4 +47,7 @@ EXPOSE 3100
|
||||
|
||||
ENV PORT 3100
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=20s --retries=3 --start-period=15s \
|
||||
CMD curl -fSs localhost:3100/health || exit 1
|
||||
|
||||
CMD [ "pnpm", "run", "start:server" ]
|
||||
@ -11,60 +11,60 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/axios": "^0.0.7",
|
||||
"@nestjs/common": "^8.4.1",
|
||||
"@nestjs/config": "^1.2.0",
|
||||
"@nestjs/core": "^8.4.1",
|
||||
"@nestjs/common": "^8.4.4",
|
||||
"@nestjs/config": "^2.0.0",
|
||||
"@nestjs/core": "^8.4.4",
|
||||
"@nestjs/jwt": "^8.0.0",
|
||||
"@nestjs/mapped-types": "^1.0.1",
|
||||
"@nestjs/passport": "^8.2.1",
|
||||
"@nestjs/platform-express": "^8.4.1",
|
||||
"@nestjs/schedule": "^1.0.2",
|
||||
"@nestjs/platform-express": "^8.4.4",
|
||||
"@nestjs/schedule": "^1.1.0",
|
||||
"@nestjs/serve-static": "^2.2.2",
|
||||
"@nestjs/terminus": "^8.0.4",
|
||||
"@nestjs/terminus": "^8.0.6",
|
||||
"@nestjs/typeorm": "^8.0.3",
|
||||
"@sendgrid/mail": "^7.6.2",
|
||||
"@types/passport": "^1.0.7",
|
||||
"bcrypt": "^5.0.1",
|
||||
"cache-manager": "^3.6.0",
|
||||
"cache-manager": "^3.6.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.13.2",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"csvtojson": "^2.0.10",
|
||||
"dayjs": "^1.11.0",
|
||||
"googleapis": "^97.0.0",
|
||||
"googleapis": "^100.0.0",
|
||||
"joi": "^17.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"multer": "^1.4.4",
|
||||
"nanoid": "^3.3.1",
|
||||
"nanoid": "^3.3.2",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"passport": "^0.5.2",
|
||||
"passport-jwt": "^4.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"pg": "^8.7.3",
|
||||
"playwright-chromium": "^1.20.0",
|
||||
"playwright-chromium": "^1.20.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.5.5",
|
||||
"typeorm": "^0.2.45",
|
||||
"typeorm": "^0.2.34",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.2.3",
|
||||
"@nestjs/schematics": "^8.0.8",
|
||||
"@nestjs/cli": "^8.2.5",
|
||||
"@nestjs/schematics": "^8.0.10",
|
||||
"@reactive-resume/schema": "workspace:*",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^17.0.21",
|
||||
"eslint": "^8.11.0",
|
||||
"prettier": "^2.6.0",
|
||||
"@types/node": "^17.0.23",
|
||||
"eslint": "^8.12.0",
|
||||
"prettier": "^2.6.2",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ts-loader": "^9.2.8",
|
||||
"ts-node": "^10.7.0",
|
||||
"tsconfig-paths": "^3.14.0",
|
||||
"tsconfig-paths": "^3.14.1",
|
||||
"typescript": "<4.6.0",
|
||||
"webpack": "^5.70.0"
|
||||
"webpack": "^5.72.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { ConfigService } from '@nestjs/config';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { randomInt } from 'crypto';
|
||||
import { google } from 'googleapis';
|
||||
|
||||
import { PostgresErrorCode } from '@/database/errorCodes.enum';
|
||||
@ -23,7 +24,7 @@ export class AuthService {
|
||||
) {}
|
||||
|
||||
async register(registerDto: RegisterDto) {
|
||||
const hashedPassword = await bcrypt.hash(registerDto.password, 10);
|
||||
const hashedPassword = await bcrypt.hash(registerDto.password, randomInt(8, 12));
|
||||
|
||||
try {
|
||||
const createdUser = await this.usersService.create({
|
||||
@ -74,7 +75,7 @@ export class AuthService {
|
||||
|
||||
async resetPassword(resetPasswordDto: ResetPasswordDto) {
|
||||
const user = await this.usersService.findByResetToken(resetPasswordDto.resetToken);
|
||||
const hashedPassword = await bcrypt.hash(resetPasswordDto.password, 10);
|
||||
const hashedPassword = await bcrypt.hash(resetPasswordDto.password, randomInt(8, 12));
|
||||
|
||||
await this.usersService.update(user.id, {
|
||||
password: hashedPassword,
|
||||
|
||||
@ -21,9 +21,9 @@ const validationSchema = Joi.object({
|
||||
// Database
|
||||
POSTGRES_HOST: Joi.string().required(),
|
||||
POSTGRES_PORT: Joi.number().default(5432),
|
||||
POSTGRES_USERNAME: Joi.string().required(),
|
||||
POSTGRES_DB: Joi.string().required(),
|
||||
POSTGRES_USER: Joi.string().required(),
|
||||
POSTGRES_PASSWORD: Joi.string().required(),
|
||||
POSTGRES_DATABASE: Joi.string().required(),
|
||||
POSTGRES_SSL_CERT: Joi.string().allow(''),
|
||||
|
||||
// Auth
|
||||
|
||||
@ -3,8 +3,8 @@ import { registerAs } from '@nestjs/config';
|
||||
export default registerAs('postgres', () => ({
|
||||
host: process.env.POSTGRES_HOST,
|
||||
port: parseInt(process.env.POSTGRES_PORT, 10) || 5432,
|
||||
username: process.env.POSTGRES_USERNAME,
|
||||
database: process.env.POSTGRES_DB,
|
||||
username: process.env.POSTGRES_USER,
|
||||
password: process.env.POSTGRES_PASSWORD,
|
||||
database: process.env.POSTGRES_DATABASE,
|
||||
certificate: process.env.POSTGRES_SSL_CERT,
|
||||
}));
|
||||
|
||||