mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-10 04:22:27 +10:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9580fe716 | |||
| 3545f7939f | |||
| 9caad3bc0b | |||
| 5bdb92b1cf | |||
| 87d381fe8e | |||
| ccfb4d3cb0 | |||
| 763074a86c | |||
| 0f46895711 | |||
| aa736af0f5 | |||
| 1d9056f935 | |||
| 9cadd603f3 | |||
| b7b62d7bd0 | |||
| 820e6c90d3 | |||
| ea642d1b60 | |||
| ec006779a8 | |||
| 515be23c44 | |||
| c11aec8b44 | |||
| 3c2147e72c | |||
| 15a35e6243 | |||
| d53a5a492c | |||
| 0810e5ae6a | |||
| 881b183db5 | |||
| 15cea02872 | |||
| c195561df0 | |||
| fc725cfc0c | |||
| 9f54516e8c | |||
| 68a4cd9635 | |||
| ff01802f2f | |||
| bb900bc2e1 | |||
| 459f82b66b | |||
| 4b382243e4 | |||
| af074085d1 | |||
| 0c8c872668 | |||
| ddb29bb40d | |||
| aecb627ab7 | |||
| b8cd53cb59 | |||
| e61f6153c3 | |||
| 386e8ab902 | |||
| 5e8f02e3ca | |||
| f219562e72 | |||
| 29d94dfc14 | |||
| 622f5fc28c | |||
| 647f01e25c | |||
| 5a79c0e5c2 | |||
| 2a4c298572 | |||
| 1e59f73f79 | |||
| feb911aea0 | |||
| d0863d68c6 | |||
| 447d9b3ca1 | |||
| 86e66eb6a0 | |||
| b2c9515a63 | |||
| db04c5caee | |||
| 33526d5d13 | |||
| fc77b548d8 | |||
| bf7a168f2e | |||
| 17b1551bab | |||
| 8864243558 | |||
| 37aab7a16f | |||
| 86e1bdf7ea | |||
| 4547fd213d | |||
| 5aacec40cc | |||
| 1df78100ca | |||
| 9cd36fcb9b | |||
| 24b32eb917 | |||
| dec0e41fec | |||
| 42700ad2b2 | |||
| df51d79f6b | |||
| be1673a6a7 | |||
| 648f182e76 | |||
| 3aa56f0886 | |||
| b795534da7 | |||
| c67e2ac9f8 | |||
| beb418bd5d | |||
| 2b3d9533b0 | |||
| b061f139bd | |||
| ac569324cf | |||
| 357d197bb3 |
@ -1,4 +1,4 @@
|
||||
ARG VARIANT="16-bullseye"
|
||||
ARG VARIANT="lts-bullseye"
|
||||
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||
|
||||
|
||||
23
.env.example
23
.env.example
@ -1,26 +1,33 @@
|
||||
# Shared
|
||||
# Server + Client
|
||||
TZ=UTC
|
||||
PUBLIC_URL=http://localhost
|
||||
PUBLIC_SERVER_URL=http://localhost/api
|
||||
PUBLIC_URL=http://localhost:3000
|
||||
PUBLIC_SERVER_URL=http://localhost:3000/api
|
||||
PUBLIC_GOOGLE_CLIENT_ID=
|
||||
|
||||
# Server + Database
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
|
||||
# Server
|
||||
SECRET_KEY=
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
POSTGRES_DATABASE=postgres
|
||||
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=
|
||||
STORAGE_BUCKET=
|
||||
STORAGE_REGION=
|
||||
STORAGE_ENDPOINT=
|
||||
STORAGE_URL_PREFIX=
|
||||
STORAGE_ACCESS_KEY=
|
||||
STORAGE_SECRET_KEY=
|
||||
|
||||
# Flags
|
||||
# Flags (Client)
|
||||
PUBLIC_FLAG_DISABLE_SIGNUPS=false
|
||||
16
.github/workflows/close-stale.yml
vendored
16
.github/workflows/close-stale.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5.0.0
|
||||
with:
|
||||
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity. Remove the stale label or comment on this PR, otherwise it would be closed in 5 days.'
|
||||
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity. Remove the stale label or comment on this issue, otherwise it would be closed in 5 days.'
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
98
.github/workflows/docker-build-push.yml
vendored
98
.github/workflows/docker-build-push.yml
vendored
@ -5,116 +5,90 @@ on:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
docker_client:
|
||||
name: Docker (Client)
|
||||
client:
|
||||
name: Client
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3.0.0
|
||||
uses: actions/checkout@v3.0.2
|
||||
|
||||
- id: version
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: 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:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: $GITHUB_REPOSITORY_OWNER
|
||||
password: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Build and Push Client Image
|
||||
uses: docker/build-push-action@v2.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 }}
|
||||
ghcr.io/amruthpillai/reactive-resume:client-latest
|
||||
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
|
||||
|
||||
docker_server:
|
||||
name: Docker (Server)
|
||||
server:
|
||||
name: Server
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3.0.0
|
||||
uses: actions/checkout@v3.0.2
|
||||
|
||||
- id: version
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: 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:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: $GITHUB_REPOSITORY_OWNER
|
||||
password: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Build and Push Server Image
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: server/Dockerfile
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
amruthpillai/reactive-resume:server-latest
|
||||
amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
|
||||
|
||||
github_client:
|
||||
name: GitHub (Client)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3.0.0
|
||||
|
||||
- id: version
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: $GITHUB_REPOSITORY_OWNER
|
||||
password: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Build and Push Client Image
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: client/Dockerfile
|
||||
tags: |
|
||||
ghcr.io/amruthpillai/reactive-resume:client-latest
|
||||
ghcr.io/amruthpillai/reactive-resume:client-${{ steps.version.outputs.tag }}
|
||||
|
||||
github_server:
|
||||
name: GitHub (Server)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3.0.0
|
||||
|
||||
- id: version
|
||||
name: Get Version
|
||||
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1.14.1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: $GITHUB_REPOSITORY_OWNER
|
||||
password: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Build and Push Server Image
|
||||
uses: docker/build-push-action@v2.10.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: server/Dockerfile
|
||||
tags: |
|
||||
ghcr.io/amruthpillai/reactive-resume:server-latest
|
||||
ghcr.io/amruthpillai/reactive-resume:server-${{ steps.version.outputs.tag }}
|
||||
|
||||
50
CHANGELOG.md
50
CHANGELOG.md
@ -2,6 +2,56 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [3.4.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.1...v3.4.2) (2022-04-30)
|
||||
|
||||
### [3.4.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.4.0...v3.4.1) (2022-04-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **typeorm:** update typeorm to latest 0.2.x for secpatch ([5bdb92b](https://github.com/AmruthPillai/Reactive-Resume/commit/5bdb92b1cff9e56879f9bbf31801d6554a00a8d5))
|
||||
|
||||
### [3.4.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.3...v3.4.0) (2022-04-30)
|
||||
|
||||
### [3.3.4](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.3...v3.3.4) (2022-04-09)
|
||||
|
||||
### [3.3.3](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.2...v3.3.3) (2022-04-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **profile:** add XING profile icon ([1e59f73](https://github.com/AmruthPillai/Reactive-Resume/commit/1e59f73f79a91d0264c0d2108906ee89d4eb27f8)), closes [#821](https://github.com/AmruthPillai/Reactive-Resume/issues/821)
|
||||
* **s3:** implement non-ephemeral storage through S3/DO Spaces ([feb911a](https://github.com/AmruthPillai/Reactive-Resume/commit/feb911aea06bacf58ea933d2803a2a89fe36e57b))
|
||||
|
||||
### [3.3.2](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.1...v3.3.2) (2022-04-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **types/react:** downgrade to <18 ([fc77b54](https://github.com/AmruthPillai/Reactive-Resume/commit/fc77b548d8d61530b2d158ff83f088bed12d5080))
|
||||
|
||||
### [3.3.1](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.3.0...v3.3.1) (2022-04-08)
|
||||
|
||||
## [3.3.0](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.11...v3.3.0) (2022-04-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **upgrade:** changes to code to support new template ([1df7810](https://github.com/AmruthPillai/Reactive-Resume/commit/1df78100ca0667ce9b7834cf2c25384eb21c67c2))
|
||||
|
||||
### What's Changed
|
||||
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/791
|
||||
* Bump org.jetbrains.kotlin.android from 1.6.10 to 1.6.20 in /app by @dependabot in https://github.com/AmruthPillai/Reactive-Resume/pull/812
|
||||
* New Crowdin updates by @AmruthPillai in https://github.com/AmruthPillai/Reactive-Resume/pull/806
|
||||
* A new template - Leafish by @klejejs in https://github.com/AmruthPillai/Reactive-Resume/pull/811
|
||||
* Automatic multi-platform Docker image build by @schklom in https://github.com/AmruthPillai/Reactive-Resume/pull/817
|
||||
|
||||
### New Contributors
|
||||
* @klejejs made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/811
|
||||
* @schklom made their first contribution in https://github.com/AmruthPillai/Reactive-Resume/pull/817
|
||||
|
||||
### [3.2.11](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.10...v3.2.11) (2022-03-28)
|
||||
|
||||
### [3.2.10](https://github.com/AmruthPillai/Reactive-Resume/compare/v3.2.9...v3.2.10) (2022-03-24)
|
||||
|
||||
|
||||
|
||||
23
README.md
23
README.md
@ -15,6 +15,23 @@ Reactive Resume is a free and open source resume builder that’s built to make
|
||||
|
||||
You have complete control over what goes into your resume, how it looks, what colors, what templates, even the layout in which sections placed. Want a dark mode resume? It’s as easy as editing 3 values and you’re done. You don’t need to wait to see your changes either. Everything you type, everything you change, appears immediately on your resume and gets updated in real time.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Reactive Resume](#reactive-resume)
|
||||
- [Go to App | [Docs](https://docs.rxresu.me)](#go-to-app--docs)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Features](#features)
|
||||
- [Languages](#languages)
|
||||
- [Tutorial](#tutorial)
|
||||
- [Build from Source](#build-from-source)
|
||||
- [Contributing](#contributing)
|
||||
- [Report Bugs and Feature Requests](#report-bugs-and-feature-requests)
|
||||
- [Donations](#donations)
|
||||
- [💸 PayPal](#-paypal)
|
||||
- [Infrastructure](#infrastructure)
|
||||
- [Contributors Wall](#contributors-wall)
|
||||
- [License](#license)
|
||||
|
||||
## Features
|
||||
|
||||
- Free, forever
|
||||
@ -40,19 +57,23 @@ You have complete control over what goes into your resume, how it looks, what co
|
||||
- Arabic (اَلْعَرَبِيَّةُ)
|
||||
- Bengali (বাংলা)
|
||||
- Chinese (中文)
|
||||
- Czech (čeština)
|
||||
- Danish (Dansk)
|
||||
- Dutch (Nederlands)
|
||||
- English
|
||||
- French (Français)
|
||||
- German (Deutsch)
|
||||
- Greek (Ελληνικά)
|
||||
- Hindi (हिन्दी)
|
||||
- Italian (Italiano)
|
||||
- Kannada (ಕನ್ನಡ)
|
||||
- Malayalam (മലയാളം)
|
||||
- Odia (ଓଡ଼ିଆ)
|
||||
- Polish (Polski)
|
||||
- Portuguese (Português)
|
||||
- Russian (русский)
|
||||
- Spanish (Español)
|
||||
- Swedish (Svenska)
|
||||
- Tamil (தமிழ்)
|
||||
- Turkish (Türkçe)
|
||||
- Vietnamese (Tiếng Việt)
|
||||
@ -79,7 +100,7 @@ This project makes use of [conventional commits](https://www.conventionalcommits
|
||||
|
||||
NOTE: Be sure to merge the latest from `main` before making a pull request!
|
||||
|
||||
## Bugs? Feature Requests?
|
||||
## Report Bugs and Feature Requests
|
||||
|
||||
Use the [GitHub Issues](https://github.com/AmruthPillai/Reactive-Resume/issues/new/choose) platform to notify me about bugs or new features that you would like to see in Reactive Resume. Please check before creating new issues as there might already be one.
|
||||
|
||||
|
||||
13
SECURITY.md
Normal file
13
SECURITY.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 3.x.x | :white_check_mark: |
|
||||
| 2.x.x | :x: |
|
||||
| 1.x.x | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Create an issue on GitHub or send me an email through the contact form on my website at https://amruthpillai.com/
|
||||
@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '7.1.2' apply false
|
||||
id 'com.android.library' version '7.1.2' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"ignorePatterns": [".next", "__ENV.js"],
|
||||
"rules": {
|
||||
"@next/next/no-img-element": "off",
|
||||
"@next/next/no-sync-scripts": "off"
|
||||
"@next/next/no-sync-scripts": "off",
|
||||
"@next/next/no-html-link-for-pages": [2, "client/pages"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM node:17-alpine as dependencies
|
||||
FROM node:lts-alpine as dependencies
|
||||
|
||||
RUN apk add --no-cache curl g++ make python3 \
|
||||
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
@ -11,7 +11,7 @@ COPY ./client/package.json ./client/package.json
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM node:17-alpine as builder
|
||||
FROM node:lts-alpine as builder
|
||||
|
||||
RUN apk add --no-cache curl g++ make python3 \
|
||||
&& curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
||||
@ -27,7 +27,7 @@ COPY --from=dependencies /app/client/node_modules ./client/node_modules
|
||||
RUN pnpm run build:schema
|
||||
RUN pnpm run build:client
|
||||
|
||||
FROM node:17-alpine as production
|
||||
FROM node:lts-alpine as production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||
const url = getResumeUrl(resume, { withHost: true });
|
||||
await navigator.clipboard.writeText(url);
|
||||
|
||||
toast.success(t('common.toast.success.resume-link-copied'));
|
||||
toast.success(t<string>('common.toast.success.resume-link-copied'));
|
||||
};
|
||||
|
||||
const handleExportPDF = async () => {
|
||||
@ -75,19 +75,19 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||
})}
|
||||
>
|
||||
<div className={styles.controller}>
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-in') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-in')}>
|
||||
<ButtonBase onClick={() => zoomIn(0.25)}>
|
||||
<ZoomIn fontSize="medium" />
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-out') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-out')}>
|
||||
<ButtonBase onClick={() => zoomOut(0.25)}>
|
||||
<ZoomOut fontSize="medium" />
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.center-artboard') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.center-artboard')}>
|
||||
<ButtonBase onClick={() => centerView(0.95)}>
|
||||
<FilterCenterFocus fontSize="medium" />
|
||||
</ButtonBase>
|
||||
@ -98,7 +98,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||
{isDesktop && (
|
||||
<>
|
||||
{pages.length > 1 && (
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-orientation') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-orientation')}>
|
||||
<ButtonBase onClick={handleTogglePageOrientation}>
|
||||
{orientation === 'vertical' ? (
|
||||
<AlignHorizontalCenter fontSize="medium" />
|
||||
@ -109,13 +109,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-page-break-line') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-page-break-line')}>
|
||||
<ButtonBase onClick={handleTogglePageBreakLine}>
|
||||
<InsertPageBreak fontSize="medium" />
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-sidebars') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-sidebars')}>
|
||||
<ButtonBase onClick={handleToggleSidebar}>
|
||||
<ViewSidebar fontSize="medium" />
|
||||
</ButtonBase>
|
||||
@ -125,13 +125,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||
</>
|
||||
)}
|
||||
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.copy-link') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.copy-link')}>
|
||||
<ButtonBase onClick={handleCopyLink}>
|
||||
<Link fontSize="medium" />
|
||||
</ButtonBase>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.export-pdf') as string}>
|
||||
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.export-pdf')}>
|
||||
<ButtonBase onClick={handleExportPDF} disabled={isLoading}>
|
||||
<Download fontSize="medium" />
|
||||
</ButtonBase>
|
||||
|
||||
@ -133,7 +133,7 @@ const Header = () => {
|
||||
const url = getResumeUrl(resume, { withHost: true });
|
||||
await navigator.clipboard.writeText(url);
|
||||
|
||||
toast.success(t('common.toast.success.resume-link-copied'));
|
||||
toast.success(t<string>('common.toast.success.resume-link-copied'));
|
||||
};
|
||||
|
||||
return (
|
||||
@ -166,14 +166,14 @@ const Header = () => {
|
||||
<ListItemIcon>
|
||||
<DriveFileRenameOutline className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.header.menu.rename')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.header.menu.rename')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem onClick={handleDuplicate}>
|
||||
<ListItemIcon>
|
||||
<CopyAll className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.header.menu.duplicate')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.header.menu.duplicate')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
{resume.public ? (
|
||||
@ -181,27 +181,27 @@ const Header = () => {
|
||||
<ListItemIcon>
|
||||
<LinkIcon className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.header.menu.share-link')}</ListItemText>
|
||||
</MenuItem>
|
||||
) : (
|
||||
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.share-link') as string}>
|
||||
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.share-link')}>
|
||||
<div>
|
||||
<MenuItem>
|
||||
<ListItemIcon>
|
||||
<LinkIcon className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.header.menu.share-link')}</ListItemText>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.delete') as string}>
|
||||
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.delete')}>
|
||||
<MenuItem onClick={handleDelete}>
|
||||
<ListItemIcon>
|
||||
<Delete className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.header.menu.delete')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.header.menu.delete')}</ListItemText>
|
||||
</MenuItem>
|
||||
</Tooltip>
|
||||
</Menu>
|
||||
|
||||
@ -48,9 +48,7 @@ const Page: React.FC<Props> = ({ page, showPageNumbers = false }) => {
|
||||
</div>
|
||||
|
||||
{showPageNumbers && (
|
||||
<h4 className={styles.pageNumber}>
|
||||
{t('builder.common.glossary.page')} {page + 1}
|
||||
</h4>
|
||||
<h4 className={styles.pageNumber}>{`${t<string>('builder.common.glossary.page')} ${page + 1}`}</h4>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -81,14 +81,14 @@ const LeftSidebar = () => {
|
||||
arrow
|
||||
key={id}
|
||||
placement="right"
|
||||
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`))}
|
||||
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`)) as string}
|
||||
>
|
||||
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
|
||||
</Tooltip>
|
||||
))}
|
||||
|
||||
{customSections.map(({ id }) => (
|
||||
<Tooltip key={id} title={get(sections, `${id}.name`, '')} placement="right" arrow>
|
||||
<Tooltip key={id} title={get(sections, `${id}.name`, '') as string} placement="right" arrow>
|
||||
<IconButton onClick={() => handleClick(id)}>
|
||||
<Star />
|
||||
</IconButton>
|
||||
@ -114,7 +114,9 @@ const LeftSidebar = () => {
|
||||
|
||||
<div className="py-6 text-right">
|
||||
<Button fullWidth variant="outlined" startIcon={<Add />} onClick={handleAddSection}>
|
||||
{t('builder.common.actions.add', { token: t('builder.leftSidebar.sections.section.heading') })}
|
||||
{t<string>('builder.common.actions.add', {
|
||||
token: t<string>('builder.leftSidebar.sections.section.heading'),
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@ -24,7 +24,7 @@ const Basics = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="sections.basics" name={t('builder.leftSidebar.sections.basics.heading')} />
|
||||
<Heading path="sections.basics" name={t<string>('builder.leftSidebar.sections.basics.heading')} />
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<div className="grid items-center gap-4 sm:col-span-2 sm:grid-cols-3">
|
||||
@ -33,10 +33,10 @@ const Basics = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2 w-full sm:col-span-2">
|
||||
<ResumeInput label={t('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
|
||||
<ResumeInput label={t<string>('builder.leftSidebar.sections.basics.name.label')} path="basics.name" />
|
||||
|
||||
<Button variant="outlined" startIcon={<PhotoFilter />} onClick={handleClick}>
|
||||
{t('builder.leftSidebar.sections.basics.actions.photo-filters')}
|
||||
{t<string>('builder.leftSidebar.sections.basics.actions.photo-filters')}
|
||||
</Button>
|
||||
|
||||
<Popover
|
||||
@ -57,20 +57,30 @@ const Basics = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ResumeInput label={t('builder.common.form.email.label')} path="basics.email" className="sm:col-span-2" />
|
||||
<ResumeInput label={t('builder.common.form.phone.label')} path="basics.phone" />
|
||||
<ResumeInput label={t('builder.common.form.url.label')} path="basics.website" />
|
||||
<ResumeInput
|
||||
type="date"
|
||||
label={t<string>('builder.leftSidebar.sections.basics.birthdate.label')}
|
||||
path="basics.birthdate"
|
||||
className="sm:col-span-2"
|
||||
/>
|
||||
<ResumeInput
|
||||
label={t<string>('builder.common.form.email.label')}
|
||||
path="basics.email"
|
||||
className="sm:col-span-2"
|
||||
/>
|
||||
<ResumeInput label={t<string>('builder.common.form.phone.label')} path="basics.phone" />
|
||||
<ResumeInput label={t<string>('builder.common.form.url.label')} path="basics.website" />
|
||||
|
||||
<Divider className="sm:col-span-2" />
|
||||
|
||||
<ResumeInput
|
||||
label={t('builder.leftSidebar.sections.basics.headline.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.basics.headline.label')}
|
||||
path="basics.headline"
|
||||
className="sm:col-span-2"
|
||||
/>
|
||||
<ResumeInput
|
||||
type="textarea"
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
path="basics.summary"
|
||||
className="sm:col-span-2"
|
||||
markdownSupported
|
||||
|
||||
@ -8,19 +8,28 @@ const Location = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="sections.location" name={t('builder.leftSidebar.sections.location.heading')} />
|
||||
<Heading path="sections.location" name={t<string>('builder.leftSidebar.sections.location.heading')} />
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<ResumeInput
|
||||
label={t('builder.leftSidebar.sections.location.address.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.location.address.label')}
|
||||
path="basics.location.address"
|
||||
className="sm:col-span-2"
|
||||
/>
|
||||
<ResumeInput label={t('builder.leftSidebar.sections.location.city.label')} path="basics.location.city" />
|
||||
<ResumeInput label={t('builder.leftSidebar.sections.location.region.label')} path="basics.location.region" />
|
||||
<ResumeInput label={t('builder.leftSidebar.sections.location.country.label')} path="basics.location.country" />
|
||||
<ResumeInput
|
||||
label={t('builder.leftSidebar.sections.location.postal-code.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.location.city.label')}
|
||||
path="basics.location.city"
|
||||
/>
|
||||
<ResumeInput
|
||||
label={t<string>('builder.leftSidebar.sections.location.region.label')}
|
||||
path="basics.location.region"
|
||||
/>
|
||||
<ResumeInput
|
||||
label={t<string>('builder.leftSidebar.sections.location.country.label')}
|
||||
path="basics.location.country"
|
||||
/>
|
||||
<ResumeInput
|
||||
label={t<string>('builder.leftSidebar.sections.location.postal-code.label')}
|
||||
path="basics.location.postalCode"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -32,7 +32,7 @@ const PhotoFilters = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2 p-5 dark:bg-neutral-800">
|
||||
<div>
|
||||
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.size.heading')}</h4>
|
||||
<h4 className="font-medium">{t<string>('builder.leftSidebar.sections.basics.photo-filters.size.heading')}</h4>
|
||||
|
||||
<div className="mx-2">
|
||||
<Slider
|
||||
@ -54,18 +54,20 @@ const PhotoFilters = () => {
|
||||
<Divider />
|
||||
|
||||
<div>
|
||||
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.effects.heading')}</h4>
|
||||
<h4 className="font-medium">
|
||||
{t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.heading')}
|
||||
</h4>
|
||||
|
||||
<div className="flex items-center">
|
||||
<FormControlLabel
|
||||
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label') as string}
|
||||
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.grayscale.label')}
|
||||
control={
|
||||
<Checkbox color="secondary" checked={grayscale} onChange={(_, value) => handleSetGrayscale(value)} />
|
||||
}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
label={t('builder.leftSidebar.sections.basics.photo-filters.effects.border.label') as string}
|
||||
label={t<string>('builder.leftSidebar.sections.basics.photo-filters.effects.border.label')}
|
||||
control={<Checkbox color="secondary" checked={border} onChange={(_, value) => handleSetBorder(value)} />}
|
||||
/>
|
||||
</div>
|
||||
@ -74,7 +76,7 @@ const PhotoFilters = () => {
|
||||
<Divider />
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<h4 className="font-medium">{t('builder.leftSidebar.sections.basics.photo-filters.shape.heading')}</h4>
|
||||
<h4 className="font-medium">{t<string>('builder.leftSidebar.sections.basics.photo-filters.shape.heading')}</h4>
|
||||
|
||||
<ToggleButtonGroup exclusive value={shape} onChange={(_, value) => handleChangeShape(value)}>
|
||||
<ToggleButton size="small" value="square" className="w-14">
|
||||
|
||||
@ -49,7 +49,7 @@ const PhotoUpload: React.FC = () => {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (file.size > FILE_UPLOAD_MAX_SIZE) {
|
||||
toast.error(t('common.toast.error.upload-photo-size'));
|
||||
toast.error(t<string>('common.toast.error.upload-photo-size'));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,8 +67,8 @@ const PhotoUpload: React.FC = () => {
|
||||
<Tooltip
|
||||
title={
|
||||
isEmpty(photo.url)
|
||||
? (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
|
||||
: (t('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
|
||||
? (t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload') as string)
|
||||
: (t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove') as string)
|
||||
}
|
||||
>
|
||||
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />
|
||||
|
||||
@ -28,7 +28,7 @@ const Profiles = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="sections.profiles" name={t('builder.leftSidebar.sections.profiles.heading')} />
|
||||
<Heading path="sections.profiles" name={t<string>('builder.leftSidebar.sections.profiles.heading')} />
|
||||
|
||||
<List
|
||||
path="basics.profiles"
|
||||
@ -40,8 +40,8 @@ const Profiles = () => {
|
||||
|
||||
<footer className="flex justify-end">
|
||||
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
|
||||
{t('builder.common.actions.add', {
|
||||
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
|
||||
{t<string>('builder.common.actions.add', {
|
||||
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
|
||||
})}
|
||||
</Button>
|
||||
</footer>
|
||||
|
||||
@ -74,7 +74,7 @@ const Section: React.FC<Props> = ({
|
||||
<SectionSettings path={path} />
|
||||
|
||||
<Button variant="outlined" startIcon={<Add />} onClick={handleAdd}>
|
||||
{t('builder.common.actions.add', { token: heading })}
|
||||
{t<string>('builder.common.actions.add', { token: heading })}
|
||||
</Button>
|
||||
</footer>
|
||||
</>
|
||||
|
||||
@ -32,7 +32,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Tooltip title={t('builder.common.columns.tooltip') as string}>
|
||||
<Tooltip title={t<string>('builder.common.columns.tooltip')}>
|
||||
<ButtonBase onClick={handleClick} sx={{ padding: 1, borderRadius: 1 }} className="opacity-50 hover:opacity-75">
|
||||
<ViewWeek /> <span className="ml-1.5 text-xs">{columns}</span>
|
||||
</ButtonBase>
|
||||
@ -48,7 +48,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
|
||||
}}
|
||||
>
|
||||
<div className="p-5 dark:bg-neutral-800">
|
||||
<h4 className="mb-2 font-medium">{t('builder.common.columns.heading')}</h4>
|
||||
<h4 className="mb-2 font-medium">{t<string>('builder.common.columns.heading')}</h4>
|
||||
|
||||
<ToggleButtonGroup exclusive value={columns} onChange={(_, value: number) => handleSetColumns(value)}>
|
||||
{[1, 2, 3, 4].map((index) => (
|
||||
|
||||
@ -25,7 +25,7 @@ const CustomCSS = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.css" name={t('builder.rightSidebar.sections.css.heading')} isHideable />
|
||||
<Heading path="metadata.css" name={t<string>('builder.rightSidebar.sections.css.heading')} isHideable />
|
||||
|
||||
<Editor
|
||||
height="200px"
|
||||
|
||||
@ -19,12 +19,12 @@ const Export = () => {
|
||||
|
||||
const pdfListItemText = {
|
||||
normal: {
|
||||
primary: t('builder.rightSidebar.sections.export.pdf.normal.primary'),
|
||||
secondary: t('builder.rightSidebar.sections.export.pdf.normal.secondary'),
|
||||
primary: t<string>('builder.rightSidebar.sections.export.pdf.normal.primary'),
|
||||
secondary: t<string>('builder.rightSidebar.sections.export.pdf.normal.secondary'),
|
||||
},
|
||||
loading: {
|
||||
primary: t('builder.rightSidebar.sections.export.pdf.loading.primary'),
|
||||
secondary: t('builder.rightSidebar.sections.export.pdf.loading.secondary'),
|
||||
primary: t<string>('builder.rightSidebar.sections.export.pdf.loading.primary'),
|
||||
secondary: t<string>('builder.rightSidebar.sections.export.pdf.loading.secondary'),
|
||||
},
|
||||
};
|
||||
|
||||
@ -53,7 +53,7 @@ const Export = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.export" name={t('builder.rightSidebar.sections.export.heading')} />
|
||||
<Heading path="metadata.export" name={t<string>('builder.rightSidebar.sections.export.heading')} />
|
||||
|
||||
<List sx={{ padding: 0 }}>
|
||||
<ListItem sx={{ padding: 0 }}>
|
||||
@ -61,8 +61,8 @@ const Export = () => {
|
||||
<Schema />
|
||||
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.export.json.primary')}
|
||||
secondary={t('builder.rightSidebar.sections.export.json.secondary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.export.json.primary')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.export.json.secondary')}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
|
||||
@ -60,9 +60,9 @@ const Layout = () => {
|
||||
<>
|
||||
<Heading
|
||||
path="metadata.layout"
|
||||
name={t('builder.rightSidebar.sections.layout.heading')}
|
||||
name={t<string>('builder.rightSidebar.sections.layout.heading')}
|
||||
action={
|
||||
<Tooltip title={t('builder.rightSidebar.sections.layout.tooltip.reset-layout') as string}>
|
||||
<Tooltip title={t<string>('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
|
||||
<IconButton onClick={handleResetLayout}>
|
||||
<Restore />
|
||||
</IconButton>
|
||||
@ -76,12 +76,16 @@ const Layout = () => {
|
||||
<div key={pageIndex} className={styles.page}>
|
||||
<div className="flex items-center justify-between pr-3">
|
||||
<p className={styles.heading}>
|
||||
{t('builder.common.glossary.page')} {pageIndex + 1}
|
||||
{t<string>('builder.common.glossary.page')} {pageIndex + 1}
|
||||
</p>
|
||||
|
||||
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
|
||||
<Tooltip
|
||||
title={t('builder.common.actions.delete', { token: t('builder.common.glossary.page') }) as string}
|
||||
title={
|
||||
t<string>('builder.common.actions.delete', {
|
||||
token: t<string>('builder.common.glossary.page'),
|
||||
}) as string
|
||||
}
|
||||
>
|
||||
<IconButton size="small" onClick={() => handleDeletePage(pageIndex)}>
|
||||
<Close fontSize="small" />
|
||||
@ -113,7 +117,7 @@ const Layout = () => {
|
||||
[styles.disabled]: !get(resumeSections, `${sectionId}.visible`, true),
|
||||
})}
|
||||
>
|
||||
{get(resumeSections, `${sectionId}.name`)}
|
||||
{get(resumeSections, `${sectionId}.name`, '') as string}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -132,7 +136,7 @@ const Layout = () => {
|
||||
|
||||
<div className="flex items-center justify-end">
|
||||
<Button variant="outlined" startIcon={<Add />} onClick={handleAddPage}>
|
||||
{t('builder.common.actions.add', { token: t('builder.common.glossary.page') })}
|
||||
{t<string>('builder.common.actions.add', { token: t<string>('builder.common.glossary.page') })}
|
||||
</Button>
|
||||
</div>
|
||||
</DragDropContext>
|
||||
|
||||
@ -12,39 +12,41 @@ const Links = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.links" name={t('builder.rightSidebar.sections.links.heading')} />
|
||||
<Heading path="metadata.links" name={t<string>('builder.rightSidebar.sections.links.heading')} />
|
||||
|
||||
<div className={styles.container}>
|
||||
<div className={styles.section}>
|
||||
<h2>
|
||||
<Savings fontSize="small" />
|
||||
{t('builder.rightSidebar.sections.links.donate.heading')}
|
||||
{t<string>('builder.rightSidebar.sections.links.donate.heading')}
|
||||
</h2>
|
||||
|
||||
<p>{t('builder.rightSidebar.sections.links.donate.body')}</p>
|
||||
<p>{t<string>('builder.rightSidebar.sections.links.donate.body')}</p>
|
||||
|
||||
<a href={DONATION_URL} target="_blank" rel="noreferrer">
|
||||
<Button startIcon={<Coffee />}>{t('builder.rightSidebar.sections.links.donate.button')}</Button>
|
||||
<Button startIcon={<Coffee />}>{t<string>('builder.rightSidebar.sections.links.donate.button')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className={styles.section}>
|
||||
<h2>
|
||||
<BugReport fontSize="small" />
|
||||
{t('builder.rightSidebar.sections.links.bugs-features.heading')}
|
||||
{t<string>('builder.rightSidebar.sections.links.bugs-features.heading')}
|
||||
</h2>
|
||||
|
||||
<p>{t('builder.rightSidebar.sections.links.bugs-features.body')}</p>
|
||||
<p>{t<string>('builder.rightSidebar.sections.links.bugs-features.body')}</p>
|
||||
|
||||
<a href={GITHUB_ISSUES_URL} target="_blank" rel="noreferrer">
|
||||
<Button startIcon={<GitHub />}>{t('builder.rightSidebar.sections.links.bugs-features.button')}</Button>
|
||||
<Button startIcon={<GitHub />}>
|
||||
{t<string>('builder.rightSidebar.sections.links.bugs-features.button')}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<Link />}>
|
||||
{t('builder.rightSidebar.sections.links.github')}
|
||||
{t<string>('builder.rightSidebar.sections.links.github')}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -85,13 +85,13 @@ const Settings = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.settings" name={t('builder.rightSidebar.sections.settings.heading')} />
|
||||
<Heading path="metadata.settings" name={t<string>('builder.rightSidebar.sections.settings.heading')} />
|
||||
|
||||
<List sx={{ padding: 0 }}>
|
||||
{/* Global Settings */}
|
||||
<>
|
||||
<ListSubheader className="rounded">
|
||||
{t('builder.rightSidebar.sections.settings.global.heading')}
|
||||
{t<string>('builder.rightSidebar.sections.settings.global.heading')}
|
||||
</ListSubheader>
|
||||
|
||||
<ListItem>
|
||||
@ -99,7 +99,7 @@ const Settings = () => {
|
||||
<Palette />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.settings.global.theme.primary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.global.theme.primary')}
|
||||
secondary={themeString}
|
||||
/>
|
||||
<ThemeSwitch checked={isDarkMode} onChange={(_, value: boolean) => handleSetTheme(value)} />
|
||||
@ -108,8 +108,8 @@ const Settings = () => {
|
||||
<ListItem className="flex-col">
|
||||
<ListItemText
|
||||
className="w-full"
|
||||
primary={t('builder.rightSidebar.sections.settings.global.date.primary')}
|
||||
secondary={t('builder.rightSidebar.sections.settings.global.date.secondary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.global.date.primary')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.settings.global.date.secondary')}
|
||||
/>
|
||||
<Autocomplete<string, false, boolean, false>
|
||||
disableClearable
|
||||
@ -124,8 +124,8 @@ const Settings = () => {
|
||||
<ListItem className="flex-col">
|
||||
<ListItemText
|
||||
className="w-full"
|
||||
primary={t('builder.rightSidebar.sections.settings.global.language.primary')}
|
||||
secondary={t('builder.rightSidebar.sections.settings.global.language.secondary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.global.language.primary')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.settings.global.language.secondary')}
|
||||
/>
|
||||
<Autocomplete<Language, false, boolean, false>
|
||||
disableClearable
|
||||
@ -148,15 +148,17 @@ const Settings = () => {
|
||||
|
||||
{/* Page Settings */}
|
||||
<>
|
||||
<ListSubheader className="rounded">{t('builder.rightSidebar.sections.settings.page.heading')}</ListSubheader>
|
||||
<ListSubheader className="rounded">
|
||||
{t<string>('builder.rightSidebar.sections.settings.page.heading')}
|
||||
</ListSubheader>
|
||||
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.settings.page.orientation.primary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.page.orientation.primary')}
|
||||
secondary={
|
||||
pages.length === 1
|
||||
? t('builder.rightSidebar.sections.settings.page.orientation.disabled')
|
||||
: t('builder.rightSidebar.sections.settings.page.orientation.secondary')
|
||||
? t<string>('builder.rightSidebar.sections.settings.page.orientation.disabled')
|
||||
: t<string>('builder.rightSidebar.sections.settings.page.orientation.secondary')
|
||||
}
|
||||
/>
|
||||
<Switch
|
||||
@ -169,8 +171,8 @@ const Settings = () => {
|
||||
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.settings.page.break-line.primary')}
|
||||
secondary={t('builder.rightSidebar.sections.settings.page.break-line.secondary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.page.break-line.primary')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.settings.page.break-line.secondary')}
|
||||
/>
|
||||
<Switch color="secondary" checked={breakLine} onChange={() => dispatch(togglePageBreakLine())} />
|
||||
</ListItem>
|
||||
@ -179,7 +181,7 @@ const Settings = () => {
|
||||
{/* Resume Settings */}
|
||||
<>
|
||||
<ListSubheader className="rounded">
|
||||
{t('builder.rightSidebar.sections.settings.resume.heading')}
|
||||
{t<string>('builder.rightSidebar.sections.settings.resume.heading')}
|
||||
</ListSubheader>
|
||||
|
||||
<ListItem>
|
||||
@ -188,8 +190,8 @@ const Settings = () => {
|
||||
<Anchor />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.settings.resume.sample.primary')}
|
||||
secondary={t('builder.rightSidebar.sections.settings.resume.sample.secondary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.resume.sample.primary')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.settings.resume.sample.secondary')}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
@ -200,8 +202,8 @@ const Settings = () => {
|
||||
<DeleteForever />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.settings.resume.reset.primary')}
|
||||
secondary={t('builder.rightSidebar.sections.settings.resume.reset.secondary')}
|
||||
primary={t<string>('builder.rightSidebar.sections.settings.resume.reset.primary')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.settings.resume.reset.secondary')}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
|
||||
@ -29,19 +29,19 @@ const Sharing = () => {
|
||||
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
toast.success(t('common.toast.success.resume-link-copied'));
|
||||
toast.success(t<string>('common.toast.success.resume-link-copied'));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.sharing" name={t('builder.rightSidebar.sections.sharing.heading')} />
|
||||
<Heading path="metadata.sharing" name={t<string>('builder.rightSidebar.sections.sharing.heading')} />
|
||||
|
||||
<List sx={{ padding: 0 }}>
|
||||
<ListItem className="flex flex-col" sx={{ padding: 0 }}>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<ListItemText
|
||||
primary={t('builder.rightSidebar.sections.sharing.visibility.title')}
|
||||
secondary={t('builder.rightSidebar.sections.sharing.visibility.subtitle')}
|
||||
primary={t<string>('builder.rightSidebar.sections.sharing.visibility.title')}
|
||||
secondary={t<string>('builder.rightSidebar.sections.sharing.visibility.subtitle')}
|
||||
/>
|
||||
<Switch color="secondary" checked={isPublic} onChange={(_, value) => handleSetVisibility(value)} />
|
||||
</div>
|
||||
@ -63,7 +63,7 @@ const Sharing = () => {
|
||||
|
||||
<div className="mt-1 flex w-full">
|
||||
<FormControlLabel
|
||||
label={t('builder.rightSidebar.sections.sharing.short-url.label') as string}
|
||||
label={t<string>('builder.rightSidebar.sections.sharing.short-url.label')}
|
||||
control={
|
||||
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ const Templates = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.templates" name={t('builder.rightSidebar.sections.templates.heading')} />
|
||||
<Heading path="metadata.templates" name={t<string>('builder.rightSidebar.sections.templates.heading')} />
|
||||
|
||||
<div className={styles.container}>
|
||||
{Object.values(templateMap).map((template) => (
|
||||
|
||||
@ -24,7 +24,7 @@ const Theme = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.theme" name={t('builder.rightSidebar.sections.theme.heading')} />
|
||||
<Heading path="metadata.theme" name={t<string>('builder.rightSidebar.sections.theme.heading')} />
|
||||
|
||||
<div className={styles.container}>
|
||||
<div className={styles.colorOptions}>
|
||||
@ -34,18 +34,18 @@ const Theme = () => {
|
||||
</div>
|
||||
|
||||
<ColorPicker
|
||||
label={t('builder.rightSidebar.sections.theme.form.primary.label')}
|
||||
label={t<string>('builder.rightSidebar.sections.theme.form.primary.label')}
|
||||
color={primary}
|
||||
className="col-span-2"
|
||||
onChange={(color) => handleChange('primary', color)}
|
||||
/>
|
||||
<ColorPicker
|
||||
label={t('builder.rightSidebar.sections.theme.form.background.label')}
|
||||
label={t<string>('builder.rightSidebar.sections.theme.form.background.label')}
|
||||
color={background}
|
||||
onChange={(color) => handleChange('background', color)}
|
||||
/>
|
||||
<ColorPicker
|
||||
label={t('builder.rightSidebar.sections.theme.form.text.label')}
|
||||
label={t<string>('builder.rightSidebar.sections.theme.form.text.label')}
|
||||
color={text}
|
||||
onChange={(color) => handleChange('text', color)}
|
||||
/>
|
||||
|
||||
@ -64,7 +64,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
|
||||
step={1}
|
||||
marks={[
|
||||
{ value: 12, label: '12px' },
|
||||
{ value: 24, label: t('builder.rightSidebar.sections.typography.form.font-size.label') },
|
||||
{ value: 24, label: t<string>('builder.rightSidebar.sections.typography.form.font-size.label') },
|
||||
{ value: 36, label: '36px' },
|
||||
]}
|
||||
valueLabelDisplay="auto"
|
||||
@ -82,7 +82,10 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
|
||||
value={fonts.find((font) => font.family === family[category])}
|
||||
onChange={(_, font: Font | null) => handleChange('family', font)}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
|
||||
<TextField
|
||||
{...params}
|
||||
label={t<string>('builder.rightSidebar.sections.typography.form.font-family.label')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@ -95,10 +98,13 @@ const Typography = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading path="metadata.typography" name={t('builder.rightSidebar.sections.typography.heading')} />
|
||||
<Heading path="metadata.typography" name={t<string>('builder.rightSidebar.sections.typography.heading')} />
|
||||
|
||||
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.headings.label')} category="heading" />
|
||||
<Widgets label={t('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
|
||||
<Widgets
|
||||
label={t<string>('builder.rightSidebar.sections.typography.widgets.headings.label')}
|
||||
category="heading"
|
||||
/>
|
||||
<Widgets label={t<string>('builder.rightSidebar.sections.typography.widgets.body.label')} category="body" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -94,7 +94,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
|
||||
const url = getResumeUrl(resume, { withHost: true });
|
||||
await navigator.clipboard.writeText(url);
|
||||
|
||||
toast.success(t('common.toast.success.resume-link-copied'));
|
||||
toast.success(t<string>('common.toast.success.resume-link-copied'));
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
@ -124,7 +124,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
|
||||
<footer>
|
||||
<div className={styles.meta}>
|
||||
<p>{resume.name}</p>
|
||||
<p>{t('dashboard.resume.timestamp', { timestamp: getRelativeTime(resume.updatedAt) })}</p>
|
||||
<p>{t<string>('dashboard.resume.timestamp', { timestamp: getRelativeTime(resume.updatedAt) })}</p>
|
||||
</div>
|
||||
|
||||
<ButtonBase className={styles.menu} onClick={handleOpenMenu}>
|
||||
@ -136,21 +136,21 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
|
||||
<ListItemIcon>
|
||||
<OpenInNew className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('dashboard.resume.menu.open')}</ListItemText>
|
||||
<ListItemText>{t<string>('dashboard.resume.menu.open')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem onClick={handleRename}>
|
||||
<ListItemIcon>
|
||||
<DriveFileRenameOutline className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('dashboard.resume.menu.rename')}</ListItemText>
|
||||
<ListItemText>{t<string>('dashboard.resume.menu.rename')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem onClick={handleDuplicate}>
|
||||
<ListItemIcon>
|
||||
<ContentCopy className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('dashboard.resume.menu.duplicate')}</ListItemText>
|
||||
<ListItemText>{t<string>('dashboard.resume.menu.duplicate')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
{resume.public ? (
|
||||
@ -158,27 +158,27 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
|
||||
<ListItemIcon>
|
||||
<LinkIcon className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
|
||||
<ListItemText>{t<string>('dashboard.resume.menu.share-link')}</ListItemText>
|
||||
</MenuItem>
|
||||
) : (
|
||||
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.share-link') as string}>
|
||||
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.share-link')}>
|
||||
<div>
|
||||
<MenuItem>
|
||||
<ListItemIcon>
|
||||
<LinkIcon className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
|
||||
<ListItemText>{t<string>('dashboard.resume.menu.share-link')}</ListItemText>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.delete') as string}>
|
||||
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.delete')}>
|
||||
<MenuItem onClick={handleDelete}>
|
||||
<ListItemIcon>
|
||||
<DeleteOutline className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('dashboard.resume.menu.delete')}</ListItemText>
|
||||
<ListItemText>{t<string>('dashboard.resume.menu.delete')}</ListItemText>
|
||||
</MenuItem>
|
||||
</Tooltip>
|
||||
</Menu>
|
||||
|
||||
@ -56,12 +56,12 @@ const Avatar: React.FC<Props> = ({ size = 64 }) => {
|
||||
<Menu anchorEl={anchorEl} onClose={handleClose} open={Boolean(anchorEl)}>
|
||||
<MenuItem>
|
||||
<div>
|
||||
<span className="text-xs opacity-50">{t('common.avatar.menu.greeting')}</span>
|
||||
<span className="text-xs opacity-50">{t<string>('common.avatar.menu.greeting')}</span>
|
||||
<p>{user?.name}</p>
|
||||
</div>
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
<MenuItem onClick={handleLogout}>{t('common.avatar.menu.logout')}</MenuItem>
|
||||
<MenuItem onClick={handleLogout}>{t<string>('common.avatar.menu.logout')}</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -5,11 +5,12 @@ import { useRouter } from 'next/router';
|
||||
import styles from './BaseModal.module.scss';
|
||||
|
||||
type Props = {
|
||||
icon?: React.ReactNode;
|
||||
isOpen: boolean;
|
||||
heading: string;
|
||||
handleClose: () => void;
|
||||
icon?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
footerChildren?: React.ReactNode;
|
||||
handleClose: () => void;
|
||||
};
|
||||
|
||||
const BaseModal: React.FC<Props> = ({ icon, isOpen, heading, children, handleClose, footerChildren }) => {
|
||||
|
||||
@ -10,7 +10,7 @@ const Footer: React.FC<Props> = ({ className }) => {
|
||||
|
||||
return (
|
||||
<div className={clsx('text-xs', className)}>
|
||||
<p>{t('common.footer.license')}</p>
|
||||
<p>{t<string>('common.footer.license')}</p>
|
||||
|
||||
<p>
|
||||
<Trans t={t} i18nKey="common.footer.credit">
|
||||
|
||||
@ -72,19 +72,19 @@ const Heading: React.FC<Props> = ({
|
||||
})}
|
||||
>
|
||||
{isEditable && (
|
||||
<Tooltip title={t('builder.common.tooltip.rename-section') as string}>
|
||||
<Tooltip title={t<string>('builder.common.tooltip.rename-section')}>
|
||||
<IconButton onClick={toggleEditMode}>{editMode ? <Check /> : <DriveFileRenameOutline />}</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{isHideable && (
|
||||
<Tooltip title={t('builder.common.tooltip.toggle-visibility') as string}>
|
||||
<Tooltip title={t<string>('builder.common.tooltip.toggle-visibility')}>
|
||||
<IconButton onClick={toggleVisibility}>{visibility ? <Visibility /> : <VisibilityOff />}</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{isDeletable && (
|
||||
<Tooltip title={t('builder.common.tooltip.delete-section') as string}>
|
||||
<Tooltip title={t<string>('builder.common.tooltip.delete-section')}>
|
||||
<IconButton onClick={handleDelete}>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
|
||||
@ -66,7 +66,7 @@ const List: React.FC<Props> = ({
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<div className={clsx(styles.container, className)}>
|
||||
{isEmpty(list) && <div className={styles.empty}>{t('builder.common.list.empty-text')}</div>}
|
||||
{isEmpty(list) && <div className={styles.empty}>{t<string>('builder.common.list.empty-text')}</div>}
|
||||
|
||||
{list.map((item, index) => {
|
||||
const title = get(item, titleKey, '');
|
||||
@ -76,6 +76,7 @@ const List: React.FC<Props> = ({
|
||||
return (
|
||||
<ListItem
|
||||
key={item.id}
|
||||
path={path}
|
||||
item={item}
|
||||
index={index}
|
||||
title={title}
|
||||
|
||||
@ -17,6 +17,7 @@ interface DragItem {
|
||||
|
||||
type Props = {
|
||||
item: ListItemType;
|
||||
path: string;
|
||||
index: number;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
@ -26,14 +27,14 @@ type Props = {
|
||||
onDuplicate?: (item: ListItemType) => void;
|
||||
};
|
||||
|
||||
const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
|
||||
const ListItem: React.FC<Props> = ({ item, path, index, title, subtitle, onMove, onEdit, onDelete, onDuplicate }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
|
||||
|
||||
const [{ handlerId }, drop] = useDrop<DragItem, any, any>({
|
||||
accept: 'ListItem',
|
||||
accept: path,
|
||||
collect(monitor) {
|
||||
return { handlerId: monitor.getHandlerId() };
|
||||
},
|
||||
@ -68,7 +69,7 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
|
||||
});
|
||||
|
||||
const [{ isDragging }, drag] = useDrag({
|
||||
type: 'ListItem',
|
||||
type: path,
|
||||
item: () => {
|
||||
return { id: item.id, index };
|
||||
},
|
||||
@ -125,25 +126,25 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
|
||||
<ListItemIcon>
|
||||
<DriveFileRenameOutline className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.common.list.actions.edit')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.common.list.actions.edit')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem onClick={() => handleDuplicate(item)}>
|
||||
<ListItemIcon>
|
||||
<FileCopy className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.common.list.actions.duplicate')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.common.list.actions.duplicate')}</ListItemText>
|
||||
</MenuItem>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Tooltip arrow placement="right" title={t('builder.common.tooltip.delete-item') as string}>
|
||||
<Tooltip arrow placement="right" title={t<string>('builder.common.tooltip.delete-item')}>
|
||||
<div>
|
||||
<MenuItem onClick={() => handleDelete(item)}>
|
||||
<ListItemIcon>
|
||||
<DeleteOutline className="scale-90" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t('builder.common.list.actions.delete')}</ListItemText>
|
||||
<ListItemText>{t<string>('builder.common.list.actions.delete')}</ListItemText>
|
||||
</MenuItem>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const NoSSR: React.FC = ({ children }) => <>{children}</>;
|
||||
|
||||
export default dynamic(() => Promise.resolve(NoSSR), { ssr: false });
|
||||
@ -1,4 +1,7 @@
|
||||
import { DatePicker } from '@mui/lab';
|
||||
import { TextField } from '@mui/material';
|
||||
import dayjs from 'dayjs';
|
||||
import { isEmpty } from 'lodash';
|
||||
import get from 'lodash/get';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
@ -8,7 +11,7 @@ import { setResumeState } from '@/store/resume/resumeSlice';
|
||||
import MarkdownSupported from './MarkdownSupported';
|
||||
|
||||
interface Props {
|
||||
type?: 'text' | 'textarea';
|
||||
type?: 'text' | 'textarea' | 'date';
|
||||
label: string;
|
||||
path: string;
|
||||
className?: string;
|
||||
@ -31,6 +34,11 @@ const ResumeInput: React.FC<Props> = ({ type = 'text', label, path, className, m
|
||||
dispatch(setResumeState({ path, value: event.target.value }));
|
||||
};
|
||||
|
||||
const onChangeValue = (value: string) => {
|
||||
setValue(value);
|
||||
dispatch(setResumeState({ path, value }));
|
||||
};
|
||||
|
||||
if (type === 'textarea') {
|
||||
return (
|
||||
<TextField
|
||||
@ -45,6 +53,22 @@ const ResumeInput: React.FC<Props> = ({ type = 'text', label, path, className, m
|
||||
);
|
||||
}
|
||||
|
||||
if (type === 'date') {
|
||||
return (
|
||||
<DatePicker
|
||||
openTo="year"
|
||||
label={label}
|
||||
value={value}
|
||||
views={['year', 'month', 'day']}
|
||||
renderInput={(params) => <TextField {...params} error={false} className={className} />}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && onChangeValue('');
|
||||
date && dayjs(date).isValid() && onChangeValue(date.toISOString());
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <TextField type={type} label={label} value={value} onChange={onChange} className={className} />;
|
||||
};
|
||||
|
||||
|
||||
@ -7,8 +7,10 @@ export type Language = {
|
||||
export const languages: Language[] = [
|
||||
{ code: 'ar', name: 'Arabic', localName: 'اَلْعَرَبِيَّةُ' },
|
||||
{ code: 'bn', name: 'Bengali', localName: 'বাংলা' },
|
||||
{ code: 'cs', name: 'Czech', localName: 'čeština' },
|
||||
{ code: 'da', name: 'Danish', localName: 'Dansk' },
|
||||
{ code: 'de', name: 'German', localName: 'Deutsch' },
|
||||
{ code: 'el', name: 'Greek', localName: 'Ελληνικά' },
|
||||
{ code: 'en', name: 'English' },
|
||||
{ code: 'es', name: 'Spanish', localName: 'Español' },
|
||||
{ code: 'fr', name: 'French', localName: 'Français' },
|
||||
@ -17,9 +19,11 @@ export const languages: Language[] = [
|
||||
{ code: 'kn', name: 'Kannada', localName: 'ಕನ್ನಡ' },
|
||||
{ code: 'ml', name: 'Malayalam', localName: 'മലയാളം' },
|
||||
{ code: 'nl', name: 'Dutch', localName: 'Nederlands' },
|
||||
{ code: 'or', name: 'Odia', localName: 'ଓଡ଼ିଆ' },
|
||||
{ code: 'pl', name: 'Polish', localName: 'Polski' },
|
||||
{ code: 'pt', name: 'Portuguese', localName: 'Português' },
|
||||
{ code: 'ru', name: 'Russian', localName: 'русский' },
|
||||
{ code: 'sv', name: 'Swedish', localName: 'Svenska' },
|
||||
{ code: 'ta', name: 'Tamil', localName: 'தமிழ்' },
|
||||
{ code: 'tr', name: 'Turkish', localName: 'Türkçe' },
|
||||
{ code: 'vi', name: 'Vietnamese', localName: 'Tiếng Việt' },
|
||||
|
||||
@ -54,16 +54,16 @@ const ForgotPasswordModal: React.FC = () => {
|
||||
<BaseModal
|
||||
icon={<Password />}
|
||||
isOpen={isOpen}
|
||||
heading={t('modals.auth.forgot-password.heading')}
|
||||
heading={t<string>('modals.auth.forgot-password.heading')}
|
||||
handleClose={handleClose}
|
||||
footerChildren={
|
||||
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
|
||||
{t('modals.auth.forgot-password.actions.send-email')}
|
||||
{t<string>('modals.auth.forgot-password.actions.send-email')}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<div className="grid gap-4">
|
||||
<p>{t('modals.auth.forgot-password.body')}</p>
|
||||
<p>{t<string>('modals.auth.forgot-password.body')}</p>
|
||||
|
||||
<form className="grid gap-4 xl:w-2/3">
|
||||
<Controller
|
||||
@ -72,7 +72,7 @@ const ForgotPasswordModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
autoFocus
|
||||
label={t('modals.auth.forgot-password.form.email.label')}
|
||||
label={t<string>('modals.auth.forgot-password.form.email.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -81,7 +81,7 @@ const ForgotPasswordModal: React.FC = () => {
|
||||
/>
|
||||
</form>
|
||||
|
||||
<p className="text-xs">{t('modals.auth.forgot-password.help-text')}</p>
|
||||
<p className="text-xs">{t<string>('modals.auth.forgot-password.help-text')}</p>
|
||||
</div>
|
||||
</BaseModal>
|
||||
</>
|
||||
|
||||
@ -6,7 +6,6 @@ import Joi from 'joi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Trans, useTranslation } from 'next-i18next';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { GoogleLoginResponse, GoogleLoginResponseOffline, useGoogleLogin } from 'react-google-login';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useIsMutating, useMutation } from 'react-query';
|
||||
@ -18,6 +17,8 @@ import { ServerError } from '@/services/axios';
|
||||
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
||||
import { setModalState } from '@/store/modal/modalSlice';
|
||||
|
||||
declare const google: any;
|
||||
|
||||
type FormData = {
|
||||
identifier: string;
|
||||
password: string;
|
||||
@ -56,15 +57,6 @@ const LoginModal: React.FC = () => {
|
||||
loginWithGoogle
|
||||
);
|
||||
|
||||
const { signIn } = useGoogleLogin({
|
||||
clientId: env('GOOGLE_CLIENT_ID'),
|
||||
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
|
||||
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
|
||||
|
||||
handleClose();
|
||||
},
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dispatch(setModalState({ modal: 'auth.login', state: { open: false } }));
|
||||
reset();
|
||||
@ -93,8 +85,18 @@ const LoginModal: React.FC = () => {
|
||||
dispatch(setModalState({ modal: 'auth.forgot', state: { open: true } }));
|
||||
};
|
||||
|
||||
const handleLoginWithGoogle = () => {
|
||||
signIn();
|
||||
const handleLoginWithGoogle = async () => {
|
||||
google.accounts.id.initialize({
|
||||
client_id: env('GOOGLE_CLIENT_ID'),
|
||||
callback: async (response: any) => {
|
||||
await loginWithGoogleMutation({ credential: response.credential });
|
||||
|
||||
handleClose();
|
||||
},
|
||||
auto_select: false,
|
||||
});
|
||||
|
||||
google.accounts.id.prompt();
|
||||
};
|
||||
|
||||
const PasswordVisibility = (): React.ReactElement => {
|
||||
@ -113,7 +115,7 @@ const LoginModal: React.FC = () => {
|
||||
<BaseModal
|
||||
icon={<Login />}
|
||||
isOpen={isOpen}
|
||||
heading={t('modals.auth.login.heading')}
|
||||
heading={t<string>('modals.auth.login.heading')}
|
||||
handleClose={handleClose}
|
||||
footerChildren={
|
||||
<div className="flex gap-4">
|
||||
@ -125,17 +127,17 @@ const LoginModal: React.FC = () => {
|
||||
startIcon={<Google />}
|
||||
onClick={handleLoginWithGoogle}
|
||||
>
|
||||
{t('modals.auth.login.actions.google')}
|
||||
{t<string>('modals.auth.login.actions.google')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
|
||||
{t('modals.auth.login.actions.login')}
|
||||
{t<string>('modals.auth.login.actions.login')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<p>{t('modals.auth.login.body')}</p>
|
||||
<p>{t<string>('modals.auth.login.body')}</p>
|
||||
|
||||
<form className="grid gap-4 xl:w-2/3">
|
||||
<Controller
|
||||
@ -144,9 +146,9 @@ const LoginModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
autoFocus
|
||||
label={t('modals.auth.login.form.username.label')}
|
||||
label={t<string>('modals.auth.login.form.username.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || t('modals.auth.login.form.username.help-text')}
|
||||
helperText={fieldState.error?.message || t<string>('modals.auth.login.form.username.help-text')}
|
||||
{...field}
|
||||
/>
|
||||
)}
|
||||
@ -158,7 +160,7 @@ const LoginModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
label={t('modals.auth.login.form.password.label')}
|
||||
label={t<string>('modals.auth.login.form.password.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
InputProps={{ endAdornment: <PasswordVisibility /> }}
|
||||
|
||||
@ -5,7 +5,6 @@ import { Button, TextField } from '@mui/material';
|
||||
import Joi from 'joi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Trans, useTranslation } from 'next-i18next';
|
||||
import { GoogleLoginResponse, GoogleLoginResponseOffline, useGoogleLogin } from 'react-google-login';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useMutation } from 'react-query';
|
||||
|
||||
@ -15,6 +14,8 @@ import { ServerError } from '@/services/axios';
|
||||
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
||||
import { setModalState } from '@/store/modal/modalSlice';
|
||||
|
||||
declare const google: any;
|
||||
|
||||
type FormData = {
|
||||
name: string;
|
||||
username: string;
|
||||
@ -63,15 +64,6 @@ const RegisterModal: React.FC = () => {
|
||||
loginWithGoogle
|
||||
);
|
||||
|
||||
const { signIn } = useGoogleLogin({
|
||||
clientId: env('GOOGLE_CLIENT_ID'),
|
||||
onSuccess: async (response: GoogleLoginResponse | GoogleLoginResponseOffline) => {
|
||||
await loginWithGoogleMutation({ accessToken: (response as GoogleLoginResponse).accessToken });
|
||||
|
||||
handleClose();
|
||||
},
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dispatch(setModalState({ modal: 'auth.register', state: { open: false } }));
|
||||
reset();
|
||||
@ -87,15 +79,25 @@ const RegisterModal: React.FC = () => {
|
||||
dispatch(setModalState({ modal: 'auth.login', state: { open: true } }));
|
||||
};
|
||||
|
||||
const handleLoginWithGoogle = () => {
|
||||
signIn();
|
||||
const handleLoginWithGoogle = async () => {
|
||||
google.accounts.id.initialize({
|
||||
client_id: env('GOOGLE_CLIENT_ID'),
|
||||
callback: async (response: any) => {
|
||||
await loginWithGoogleMutation({ credential: response.credential });
|
||||
|
||||
handleClose();
|
||||
},
|
||||
auto_select: false,
|
||||
});
|
||||
|
||||
google.accounts.id.prompt();
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseModal
|
||||
icon={<HowToReg />}
|
||||
isOpen={isOpen}
|
||||
heading={t('modals.auth.register.heading')}
|
||||
heading={t<string>('modals.auth.register.heading')}
|
||||
handleClose={handleClose}
|
||||
footerChildren={
|
||||
<div className="flex gap-4">
|
||||
@ -107,17 +109,17 @@ const RegisterModal: React.FC = () => {
|
||||
startIcon={<Google />}
|
||||
onClick={handleLoginWithGoogle}
|
||||
>
|
||||
{t('modals.auth.register.actions.google')}
|
||||
{t<string>('modals.auth.register.actions.google')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button type="submit" onClick={handleSubmit(onSubmit)} disabled={isLoading}>
|
||||
{t('modals.auth.register.actions.register')}
|
||||
{t<string>('modals.auth.register.actions.register')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<p>{t('modals.auth.register.body')}</p>
|
||||
<p>{t<string>('modals.auth.register.body')}</p>
|
||||
|
||||
<form className="grid gap-4 md:grid-cols-2">
|
||||
<Controller
|
||||
@ -126,7 +128,7 @@ const RegisterModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
autoFocus
|
||||
label={t('modals.auth.register.form.name.label')}
|
||||
label={t<string>('modals.auth.register.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -139,7 +141,7 @@ const RegisterModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('modals.auth.register.form.username.label')}
|
||||
label={t<string>('modals.auth.register.form.username.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -153,7 +155,7 @@ const RegisterModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
type="email"
|
||||
label={t('modals.auth.register.form.email.label')}
|
||||
label={t<string>('modals.auth.register.form.email.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
@ -168,7 +170,7 @@ const RegisterModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
type="password"
|
||||
label={t('modals.auth.register.form.password.label')}
|
||||
label={t<string>('modals.auth.register.form.password.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -182,7 +184,7 @@ const RegisterModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
type="password"
|
||||
label={t('modals.auth.register.form.confirm-password.label')}
|
||||
label={t<string>('modals.auth.register.form.confirm-password.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
|
||||
@ -65,15 +65,15 @@ const ResetPasswordModal: React.FC = () => {
|
||||
<BaseModal
|
||||
icon={<LockReset />}
|
||||
isOpen={isOpen}
|
||||
heading={t('modals.auth.reset-password.heading')}
|
||||
heading={t<string>('modals.auth.reset-password.heading')}
|
||||
handleClose={handleClose}
|
||||
footerChildren={
|
||||
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
|
||||
{t('modals.auth.reset-password.actions.set-password')}
|
||||
{t<string>('modals.auth.reset-password.actions.set-password')}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<p>{t('modals.auth.reset-password.body')}</p>
|
||||
<p>{t<string>('modals.auth.reset-password.body')}</p>
|
||||
|
||||
<form className="grid gap-4 md:grid-cols-2">
|
||||
<Controller
|
||||
@ -83,7 +83,7 @@ const ResetPasswordModal: React.FC = () => {
|
||||
<TextField
|
||||
autoFocus
|
||||
type="password"
|
||||
label={t('modals.auth.reset-password.form.password.label')}
|
||||
label={t<string>('modals.auth.reset-password.form.password.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -97,7 +97,7 @@ const ResetPasswordModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
type="password"
|
||||
label={t('modals.auth.reset-password.form.confirm-password.label')}
|
||||
label={t<string>('modals.auth.reset-password.form.confirm-password.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
|
||||
@ -50,8 +50,8 @@ const AwardModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -101,7 +101,7 @@ const AwardModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.title.label')}
|
||||
label={t<string>('builder.common.form.title.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -115,7 +115,7 @@ const AwardModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.leftSidebar.sections.awards.form.awarder.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.awards.form.awarder.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -130,7 +130,7 @@ const AwardModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.date.label')}
|
||||
label={t<string>('builder.common.form.date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -152,7 +152,7 @@ const AwardModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
@ -169,7 +169,7 @@ const AwardModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
|
||||
@ -50,8 +50,8 @@ const CertificateModal: React.FC = () => {
|
||||
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -101,7 +101,7 @@ const CertificateModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -115,7 +115,7 @@ const CertificateModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.leftSidebar.sections.certifications.form.issuer.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.certifications.form.issuer.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -130,7 +130,7 @@ const CertificateModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.date.label')}
|
||||
label={t<string>('builder.common.form.date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -152,7 +152,7 @@ const CertificateModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
@ -169,7 +169,7 @@ const CertificateModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
|
||||
@ -67,8 +67,8 @@ const CustomModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -118,7 +118,7 @@ const CustomModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.title.label')}
|
||||
label={t<string>('builder.common.form.title.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -131,7 +131,7 @@ const CustomModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.subtitle.label')}
|
||||
label={t<string>('builder.common.form.subtitle.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -146,7 +146,7 @@ const CustomModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.start-date.label')}
|
||||
label={t<string>('builder.common.form.start-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -170,7 +170,7 @@ const CustomModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.end-date.label')}
|
||||
label={t<string>('builder.common.form.end-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -192,7 +192,7 @@ const CustomModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
@ -207,7 +207,7 @@ const CustomModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.level.label')}
|
||||
label={t<string>('builder.common.form.level.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
@ -221,7 +221,7 @@ const CustomModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2">
|
||||
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
|
||||
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
|
||||
|
||||
<div className="px-10">
|
||||
<Slider
|
||||
@ -245,7 +245,7 @@ const CustomModal: React.FC = () => {
|
||||
defaultValue={0}
|
||||
color="secondary"
|
||||
valueLabelDisplay="auto"
|
||||
aria-label={t('builder.common.form.levelNum.label')}
|
||||
aria-label={t<string>('builder.common.form.levelNum.label')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -260,7 +260,7 @@ const CustomModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
@ -274,7 +274,7 @@ const CustomModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<ArrayInput
|
||||
label={t('builder.common.form.keywords.label')}
|
||||
label={t<string>('builder.common.form.keywords.label')}
|
||||
value={field.value as string[]}
|
||||
onChange={field.onChange}
|
||||
errors={fieldState.error}
|
||||
|
||||
@ -63,8 +63,8 @@ const EducationModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -114,7 +114,7 @@ const EducationModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.leftSidebar.sections.education.form.institution.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.education.form.institution.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -128,7 +128,7 @@ const EducationModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.leftSidebar.sections.education.form.degree.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.education.form.degree.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -141,7 +141,7 @@ const EducationModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.leftSidebar.sections.education.form.area-study.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.education.form.area-study.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -154,7 +154,7 @@ const EducationModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.leftSidebar.sections.education.form.grade.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.education.form.grade.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -169,7 +169,7 @@ const EducationModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.start-date.label')}
|
||||
label={t<string>('builder.common.form.start-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -193,7 +193,7 @@ const EducationModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.end-date.label')}
|
||||
label={t<string>('builder.common.form.end-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -203,7 +203,7 @@ const EducationModal: React.FC = () => {
|
||||
<TextField
|
||||
{...params}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || t('builder.common.form.end-date.help-text')}
|
||||
helperText={fieldState.error?.message || t<string>('builder.common.form.end-date.help-text')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -215,7 +215,7 @@ const EducationModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
@ -233,7 +233,7 @@ const EducationModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
@ -247,7 +247,7 @@ const EducationModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<ArrayInput
|
||||
label={t('builder.leftSidebar.sections.education.form.courses.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.education.form.courses.label')}
|
||||
value={field.value as string[]}
|
||||
onChange={field.onChange}
|
||||
errors={fieldState.error}
|
||||
|
||||
@ -41,8 +41,8 @@ const InterestModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -92,7 +92,7 @@ const InterestModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
@ -106,7 +106,7 @@ const InterestModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<ArrayInput
|
||||
label={t('builder.common.form.keywords.label')}
|
||||
label={t<string>('builder.common.form.keywords.label')}
|
||||
value={field.value as string[]}
|
||||
onChange={field.onChange}
|
||||
errors={fieldState.error}
|
||||
|
||||
@ -42,8 +42,8 @@ const LanguageModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -93,7 +93,7 @@ const LanguageModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -107,7 +107,7 @@ const LanguageModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.common.form.level.label')}
|
||||
label={t<string>('builder.common.form.level.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -120,7 +120,7 @@ const LanguageModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2">
|
||||
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
|
||||
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
|
||||
|
||||
<div className="px-10">
|
||||
<Slider
|
||||
@ -144,7 +144,7 @@ const LanguageModal: React.FC = () => {
|
||||
defaultValue={0}
|
||||
color="secondary"
|
||||
valueLabelDisplay="auto"
|
||||
aria-label={t('builder.common.form.levelNum.label')}
|
||||
aria-label={t<string>('builder.common.form.levelNum.label')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -42,11 +42,11 @@ const ProfileModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = t('builder.common.actions.add', {
|
||||
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
|
||||
const addText = t<string>('builder.common.actions.add', {
|
||||
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
|
||||
});
|
||||
const editText = t('builder.common.actions.edit', {
|
||||
token: t('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
|
||||
const editText = t<string>('builder.common.actions.edit', {
|
||||
token: t<string>('builder.leftSidebar.sections.profiles.heading', { count: 1 }),
|
||||
});
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
@ -97,7 +97,7 @@ const ProfileModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.leftSidebar.sections.profiles.form.network.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.profiles.form.network.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -111,7 +111,7 @@ const ProfileModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.leftSidebar.sections.profiles.form.username.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.profiles.form.username.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
InputProps={{
|
||||
@ -127,7 +127,7 @@ const ProfileModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
className="col-span-2"
|
||||
placeholder="https://"
|
||||
error={!!fieldState.error}
|
||||
|
||||
@ -59,8 +59,8 @@ const ProjectModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -110,7 +110,7 @@ const ProjectModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -124,7 +124,7 @@ const ProjectModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.common.form.description.label')}
|
||||
label={t<string>('builder.common.form.description.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -139,7 +139,7 @@ const ProjectModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.start-date.label')}
|
||||
label={t<string>('builder.common.form.start-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -163,7 +163,7 @@ const ProjectModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.end-date.label')}
|
||||
label={t<string>('builder.common.form.end-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -185,7 +185,7 @@ const ProjectModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
@ -203,7 +203,7 @@ const ProjectModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
@ -217,7 +217,7 @@ const ProjectModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<ArrayInput
|
||||
label={t('builder.common.form.keywords.label')}
|
||||
label={t<string>('builder.common.form.keywords.label')}
|
||||
value={field.value as string[]}
|
||||
onChange={field.onChange}
|
||||
errors={fieldState.error}
|
||||
|
||||
@ -50,8 +50,8 @@ const PublicationModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -101,7 +101,7 @@ const PublicationModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -115,7 +115,7 @@ const PublicationModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.leftSidebar.sections.publications.form.publisher.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.publications.form.publisher.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -130,7 +130,7 @@ const PublicationModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.date.label')}
|
||||
label={t<string>('builder.common.form.date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -152,7 +152,7 @@ const PublicationModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
@ -169,7 +169,7 @@ const PublicationModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
|
||||
@ -47,8 +47,8 @@ const ReferenceModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -98,7 +98,7 @@ const ReferenceModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -112,7 +112,7 @@ const ReferenceModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.leftSidebar.sections.references.form.relationship.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.references.form.relationship.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -125,7 +125,7 @@ const ReferenceModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.phone.label')}
|
||||
label={t<string>('builder.common.form.phone.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -138,7 +138,7 @@ const ReferenceModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.email.label')}
|
||||
label={t<string>('builder.common.form.email.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -154,7 +154,7 @@ const ReferenceModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
|
||||
@ -45,8 +45,8 @@ const SkillModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -96,7 +96,7 @@ const SkillModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -109,7 +109,7 @@ const SkillModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.level.label')}
|
||||
label={t<string>('builder.common.form.level.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -122,7 +122,7 @@ const SkillModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="col-span-2">
|
||||
<h4 className="mb-3 font-semibold">{t('builder.common.form.levelNum.label')}</h4>
|
||||
<h4 className="mb-3 font-semibold">{t<string>('builder.common.form.levelNum.label')}</h4>
|
||||
|
||||
<div className="px-3">
|
||||
<Slider
|
||||
@ -146,7 +146,7 @@ const SkillModal: React.FC = () => {
|
||||
defaultValue={0}
|
||||
color="secondary"
|
||||
valueLabelDisplay="auto"
|
||||
aria-label={t('builder.common.form.levelNum.label')}
|
||||
aria-label={t<string>('builder.common.form.levelNum.label')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -158,7 +158,7 @@ const SkillModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<ArrayInput
|
||||
label={t('builder.common.form.keywords.label')}
|
||||
label={t<string>('builder.common.form.keywords.label')}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
errors={fieldState.error}
|
||||
|
||||
@ -56,8 +56,8 @@ const VolunteerModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -107,7 +107,7 @@ const VolunteerModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.leftSidebar.sections.volunteer.form.organization.label')}
|
||||
label={t<string>('builder.leftSidebar.sections.volunteer.form.organization.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -121,7 +121,7 @@ const VolunteerModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.common.form.position.label')}
|
||||
label={t<string>('builder.common.form.position.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -136,7 +136,7 @@ const VolunteerModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.start-date.label')}
|
||||
label={t<string>('builder.common.form.start-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -160,7 +160,7 @@ const VolunteerModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.end-date.label')}
|
||||
label={t<string>('builder.common.form.end-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -182,7 +182,7 @@ const VolunteerModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
@ -200,7 +200,7 @@ const VolunteerModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
|
||||
@ -56,8 +56,8 @@ const WorkModal: React.FC = () => {
|
||||
const item: FormData = get(payload, 'item', null);
|
||||
const isEditMode = useMemo(() => !!item, [item]);
|
||||
|
||||
const addText = useMemo(() => t('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
const addText = useMemo(() => t<string>('builder.common.actions.add', { token: heading }), [t, heading]);
|
||||
const editText = useMemo(() => t<string>('builder.common.actions.edit', { token: heading }), [t, heading]);
|
||||
|
||||
const { reset, control, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: defaultState,
|
||||
@ -107,7 +107,7 @@ const WorkModal: React.FC = () => {
|
||||
<TextField
|
||||
required
|
||||
autoFocus
|
||||
label={t('builder.common.form.name.label')}
|
||||
label={t<string>('builder.common.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -121,7 +121,7 @@ const WorkModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
required
|
||||
label={t('builder.common.form.position.label')}
|
||||
label={t<string>('builder.common.form.position.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -136,7 +136,7 @@ const WorkModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.start-date.label')}
|
||||
label={t<string>('builder.common.form.start-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -160,7 +160,7 @@ const WorkModal: React.FC = () => {
|
||||
<DatePicker
|
||||
{...field}
|
||||
openTo="year"
|
||||
label={t('builder.common.form.end-date.label')}
|
||||
label={t<string>('builder.common.form.end-date.label')}
|
||||
views={['year', 'month', 'day']}
|
||||
onChange={(date: Date | null, keyboardInputValue: string | undefined) => {
|
||||
isEmpty(keyboardInputValue) && field.onChange('');
|
||||
@ -170,7 +170,7 @@ const WorkModal: React.FC = () => {
|
||||
<TextField
|
||||
{...params}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || t('builder.common.form.end-date.help-text')}
|
||||
helperText={fieldState.error?.message || t<string>('builder.common.form.end-date.help-text')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -182,7 +182,7 @@ const WorkModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('builder.common.form.url.label')}
|
||||
label={t<string>('builder.common.form.url.label')}
|
||||
placeholder="https://"
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
@ -200,7 +200,7 @@ const WorkModal: React.FC = () => {
|
||||
multiline
|
||||
minRows={3}
|
||||
maxRows={6}
|
||||
label={t('builder.common.form.summary.label')}
|
||||
label={t<string>('builder.common.form.summary.label')}
|
||||
className="col-span-2"
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message || <MarkdownSupported />}
|
||||
|
||||
@ -85,15 +85,15 @@ const CreateResumeModal: React.FC = () => {
|
||||
<BaseModal
|
||||
isOpen={isOpen}
|
||||
icon={<Add />}
|
||||
heading={t('modals.dashboard.create-resume.heading')}
|
||||
heading={t<string>('modals.dashboard.create-resume.heading')}
|
||||
handleClose={handleClose}
|
||||
footerChildren={
|
||||
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
|
||||
{t('modals.dashboard.create-resume.actions.create-resume')}
|
||||
{t<string>('modals.dashboard.create-resume.actions.create-resume')}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<p>{t('modals.dashboard.create-resume.body')}</p>
|
||||
<p>{t<string>('modals.dashboard.create-resume.body')}</p>
|
||||
|
||||
<form className="grid gap-4">
|
||||
<Controller
|
||||
@ -102,7 +102,7 @@ const CreateResumeModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
autoFocus
|
||||
label={t('modals.dashboard.create-resume.form.name.label')}
|
||||
label={t<string>('modals.dashboard.create-resume.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -115,7 +115,7 @@ const CreateResumeModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('modals.dashboard.create-resume.form.slug.label')}
|
||||
label={t<string>('modals.dashboard.create-resume.form.slug.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -125,7 +125,7 @@ const CreateResumeModal: React.FC = () => {
|
||||
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
label={t('modals.dashboard.create-resume.form.public.label') as string}
|
||||
label={t<string>('modals.dashboard.create-resume.form.public.label')}
|
||||
control={
|
||||
<Controller
|
||||
name="isPublic"
|
||||
|
||||
@ -63,7 +63,7 @@ const ImportExternalModal: React.FC = () => {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (file.size > FILE_UPLOAD_MAX_SIZE) {
|
||||
toast.error(t('common.toast.error.upload-file-size'));
|
||||
toast.error(t<string>('common.toast.error.upload-file-size'));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,13 +78,13 @@ const ImportExternalModal: React.FC = () => {
|
||||
<BaseModal
|
||||
isOpen={isOpen}
|
||||
icon={<ImportExport />}
|
||||
heading={t('modals.dashboard.import-external.heading')}
|
||||
heading={t<string>('modals.dashboard.import-external.heading')}
|
||||
handleClose={handleClose}
|
||||
>
|
||||
<div className="grid gap-5">
|
||||
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
|
||||
<LinkedIn />
|
||||
{t('modals.dashboard.import-external.linkedin.heading')}
|
||||
{t<string>('modals.dashboard.import-external.linkedin.heading')}
|
||||
</h2>
|
||||
|
||||
<p className="mb-2">
|
||||
@ -110,7 +110,7 @@ const ImportExternalModal: React.FC = () => {
|
||||
startIcon={<UploadFile />}
|
||||
onClick={() => handleClick('linkedin')}
|
||||
>
|
||||
{t('modals.dashboard.import-external.linkedin.actions.upload-archive')}
|
||||
{t<string>('modals.dashboard.import-external.linkedin.actions.upload-archive')}
|
||||
</Button>
|
||||
|
||||
<input
|
||||
@ -128,7 +128,7 @@ const ImportExternalModal: React.FC = () => {
|
||||
<div className="grid gap-5">
|
||||
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
|
||||
<Code />
|
||||
{t('modals.dashboard.import-external.json-resume.heading')}
|
||||
{t<string>('modals.dashboard.import-external.json-resume.heading')}
|
||||
</h2>
|
||||
|
||||
<p className="mb-2">
|
||||
@ -154,7 +154,7 @@ const ImportExternalModal: React.FC = () => {
|
||||
startIcon={<UploadFile />}
|
||||
onClick={() => handleClick('json-resume')}
|
||||
>
|
||||
{t('modals.dashboard.import-external.json-resume.actions.upload-json')}
|
||||
{t<string>('modals.dashboard.import-external.json-resume.actions.upload-json')}
|
||||
</Button>
|
||||
|
||||
<input
|
||||
@ -172,10 +172,10 @@ const ImportExternalModal: React.FC = () => {
|
||||
<div className="grid gap-5">
|
||||
<h2 className="inline-flex items-center gap-2 text-lg font-medium">
|
||||
<TrackChanges />
|
||||
{t('modals.dashboard.import-external.reactive-resume.heading')}
|
||||
{t<string>('modals.dashboard.import-external.reactive-resume.heading')}
|
||||
</h2>
|
||||
|
||||
<p className="mb-2">{t('modals.dashboard.import-external.reactive-resume.body')}</p>
|
||||
<p className="mb-2">{t<string>('modals.dashboard.import-external.reactive-resume.body')}</p>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<Button
|
||||
@ -184,7 +184,7 @@ const ImportExternalModal: React.FC = () => {
|
||||
startIcon={<UploadFile />}
|
||||
onClick={() => handleClick('reactive-resume')}
|
||||
>
|
||||
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
|
||||
{t<string>('modals.dashboard.import-external.reactive-resume.actions.upload-json')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
@ -193,7 +193,7 @@ const ImportExternalModal: React.FC = () => {
|
||||
startIcon={<UploadFile />}
|
||||
onClick={() => handleClick('reactive-resume-v2')}
|
||||
>
|
||||
{t('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
|
||||
{t<string>('modals.dashboard.import-external.reactive-resume.actions.upload-json-v2')}
|
||||
</Button>
|
||||
|
||||
<input
|
||||
|
||||
@ -92,11 +92,11 @@ const RenameResumeModal: React.FC = () => {
|
||||
<BaseModal
|
||||
icon={<DriveFileRenameOutline />}
|
||||
isOpen={isOpen}
|
||||
heading={t('modals.dashboard.rename-resume.heading')}
|
||||
heading={t<string>('modals.dashboard.rename-resume.heading')}
|
||||
handleClose={handleClose}
|
||||
footerChildren={
|
||||
<Button type="submit" disabled={isLoading} onClick={handleSubmit(onSubmit)}>
|
||||
{t('modals.dashboard.rename-resume.actions.rename-resume')}
|
||||
{t<string>('modals.dashboard.rename-resume.actions.rename-resume')}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
@ -107,7 +107,7 @@ const RenameResumeModal: React.FC = () => {
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
autoFocus
|
||||
label={t('modals.dashboard.rename-resume.form.name.label')}
|
||||
label={t<string>('modals.dashboard.rename-resume.form.name.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
@ -120,7 +120,7 @@ const RenameResumeModal: React.FC = () => {
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextField
|
||||
label={t('modals.dashboard.rename-resume.form.slug.label')}
|
||||
label={t<string>('modals.dashboard.rename-resume.form.slug.label')}
|
||||
error={!!fieldState.error}
|
||||
helperText={fieldState.error?.message}
|
||||
{...field}
|
||||
|
||||
@ -12,7 +12,7 @@ const nextConfig = {
|
||||
},
|
||||
|
||||
images: {
|
||||
domains: ['www.gravatar.com'],
|
||||
domains: ['cdn.rxresu.me', 'www.gravatar.com'],
|
||||
},
|
||||
|
||||
async rewrites() {
|
||||
|
||||
@ -9,70 +9,70 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@beam-australia/react-env": "^3.1.1",
|
||||
"@emotion/css": "^11.7.1",
|
||||
"@emotion/react": "^11.8.2",
|
||||
"@emotion/css": "^11.9.0",
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
"@hookform/resolvers": "2.8.8",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@mui/icons-material": "^5.5.1",
|
||||
"@mui/lab": "^5.0.0-alpha.74",
|
||||
"@mui/material": "^5.5.2",
|
||||
"@reduxjs/toolkit": "^1.8.0",
|
||||
"axios": "^0.26.1",
|
||||
"@monaco-editor/react": "^4.4.4",
|
||||
"@mui/icons-material": "^5.6.2",
|
||||
"@mui/lab": "^5.0.0-alpha.79",
|
||||
"@mui/material": "^5.6.3",
|
||||
"@reduxjs/toolkit": "^1.8.1",
|
||||
"axios": "^0.27.2",
|
||||
"clsx": "^1.1.1",
|
||||
"dayjs": "^1.11.0",
|
||||
"dayjs": "^1.11.1",
|
||||
"downloadjs": "^1.4.7",
|
||||
"joi": "^17.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"md5-hex": "^4.0.0",
|
||||
"monaco-editor": "^0.33.0",
|
||||
"nanoid": "^3.3.1",
|
||||
"next": "12.1.0",
|
||||
"next-i18next": "^10.5.0",
|
||||
"react": ">=17",
|
||||
"nanoid": "^3.3.3",
|
||||
"next": "12.1.5",
|
||||
"next-i18next": "^11.0.0",
|
||||
"react": "^18",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-colorful": "^5.5.1",
|
||||
"react-dnd": "^15.1.1",
|
||||
"react-dnd-html5-backend": "^15.1.2",
|
||||
"react-dom": ">=17",
|
||||
"react-google-login": "^5.2.2",
|
||||
"react-hook-form": "^7.28.1",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.30.0",
|
||||
"react-hot-toast": "2.2.0",
|
||||
"react-hotkeys-hook": "^3.4.4",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-markdown": "^8.0.1",
|
||||
"react-query": "^3.34.16",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-query": "^3.38.0",
|
||||
"react-redux": "^8.0.1",
|
||||
"react-zoom-pan-pinch": "^2.1.3",
|
||||
"redux": "^4.1.2",
|
||||
"redux": "^4.2.0",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"sharp": "^0.30.3",
|
||||
"sharp": "^0.30.4",
|
||||
"uuid": "^8.3.2",
|
||||
"webfontloader": "^1.6.28"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.8",
|
||||
"@babel/core": "^7.17.10",
|
||||
"@reactive-resume/schema": "workspace:*",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@types/downloadjs": "^1.4.3",
|
||||
"@types/lodash": "^4.14.180",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "17.0.42",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/node": "17.0.30",
|
||||
"@types/react": "^18",
|
||||
"@types/react-beautiful-dnd": "^13.1.2",
|
||||
"@types/react-redux": "^7.1.23",
|
||||
"@types/tailwindcss": "^3.0.9",
|
||||
"@types/react-redux": "^7.1.24",
|
||||
"@types/tailwindcss": "^3.0.10",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/webfontloader": "^1.6.34",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"eslint": "^8.11.0",
|
||||
"eslint-config-next": "12.1.0",
|
||||
"next-sitemap": "^2.5.13",
|
||||
"postcss": "^8.4.12",
|
||||
"prettier": "^2.6.0",
|
||||
"sass": "^1.49.9",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"typescript": "<4.6.0"
|
||||
"autoprefixer": "^10.4.5",
|
||||
"csstype": "^3.0.11",
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-config-next": "12.1.5",
|
||||
"next-sitemap": "^2.5.20",
|
||||
"postcss": "^8.4.13",
|
||||
"prettier": "^2.6.2",
|
||||
"sass": "^1.51.0",
|
||||
"tailwindcss": "^3.0.24",
|
||||
"typescript": "^4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ const Build: NextPage<Props> = ({ username, slug }) => {
|
||||
<div className={styles.container}>
|
||||
<Head>
|
||||
<title>
|
||||
{resume.name} | {t('common.title')}
|
||||
{resume.name} | {t<string>('common.title')}
|
||||
</title>
|
||||
</Head>
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import DateAdapter from '@mui/lab/AdapterDayjs';
|
||||
import LocalizationProvider from '@mui/lab/LocalizationProvider';
|
||||
import type { AppProps } from 'next/app';
|
||||
import Head from 'next/head';
|
||||
import Script from 'next/script';
|
||||
import { appWithTranslation } from 'next-i18next';
|
||||
import { Toaster } from 'react-hot-toast';
|
||||
import { QueryClientProvider } from 'react-query';
|
||||
@ -52,6 +53,8 @@ const App: React.FC<AppProps> = ({ Component, pageProps }) => {
|
||||
</PersistGate>
|
||||
</LocalizationProvider>
|
||||
</ReduxProvider>
|
||||
|
||||
<Script src="https://accounts.google.com/gsi/client" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -33,7 +33,7 @@ const Dashboard: NextPage = () => {
|
||||
<div className={styles.container}>
|
||||
<Head>
|
||||
<title>
|
||||
{t('dashboard.title')} | {t('common.title')}
|
||||
{t<string>('dashboard.title')} | {t<string>('common.title')}
|
||||
</title>
|
||||
</Head>
|
||||
|
||||
@ -51,15 +51,15 @@ const Dashboard: NextPage = () => {
|
||||
<ResumeCard
|
||||
modal="dashboard.create-resume"
|
||||
icon={Add}
|
||||
title={t('dashboard.create-resume.title')}
|
||||
subtitle={t('dashboard.create-resume.subtitle')}
|
||||
title={t<string>('dashboard.create-resume.title')}
|
||||
subtitle={t<string>('dashboard.create-resume.subtitle')}
|
||||
/>
|
||||
|
||||
<ResumeCard
|
||||
modal="dashboard.import-external"
|
||||
icon={ImportExport}
|
||||
title={t('dashboard.import-external.title')}
|
||||
subtitle={t('dashboard.import-external.subtitle')}
|
||||
title={t<string>('dashboard.import-external.title')}
|
||||
subtitle={t<string>('dashboard.import-external.subtitle')}
|
||||
/>
|
||||
|
||||
{data.map((resume) => (
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { DarkMode, LightMode, Link as LinkIcon } from '@mui/icons-material';
|
||||
import { Masonry } from '@mui/lab';
|
||||
import { Button, IconButton } from '@mui/material';
|
||||
import { Button, IconButton, NoSsr } from '@mui/material';
|
||||
import type { GetStaticProps, NextPage } from 'next';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
@ -11,7 +11,6 @@ import Testimony from '@/components/landing/Testimony';
|
||||
import Footer from '@/components/shared/Footer';
|
||||
import LanguageSwitcher from '@/components/shared/LanguageSwitcher';
|
||||
import Logo from '@/components/shared/Logo';
|
||||
import NoSSR from '@/components/shared/NoSSR';
|
||||
import { screenshots } from '@/config/screenshots';
|
||||
import { FLAG_DISABLE_SIGNUPS } from '@/constants/flags';
|
||||
import testimonials from '@/data/testimonials';
|
||||
@ -55,52 +54,52 @@ const Home: NextPage = () => {
|
||||
</div>
|
||||
|
||||
<div className={styles.main}>
|
||||
<h1>{t('common.title')}</h1>
|
||||
<h1>{t<string>('common.title')}</h1>
|
||||
|
||||
<h2>{t('common.subtitle')}</h2>
|
||||
<h2>{t<string>('common.subtitle')}</h2>
|
||||
|
||||
<NoSSR>
|
||||
<NoSsr>
|
||||
<div className={styles.buttonWrapper}>
|
||||
{isLoggedIn ? (
|
||||
<>
|
||||
<Link href="/dashboard" passHref>
|
||||
<Button>{t('landing.actions.app')}</Button>
|
||||
<Button>{t<string>('landing.actions.app')}</Button>
|
||||
</Link>
|
||||
|
||||
<Button variant="outlined" onClick={handleLogout}>
|
||||
{t('landing.actions.logout')}
|
||||
{t<string>('landing.actions.logout')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button onClick={handleLogin}>{t('landing.actions.login')}</Button>
|
||||
<Button onClick={handleLogin}>{t<string>('landing.actions.login')}</Button>
|
||||
|
||||
<Button variant="outlined" onClick={handleRegister} disabled={FLAG_DISABLE_SIGNUPS}>
|
||||
{t('landing.actions.register')}
|
||||
{t<string>('landing.actions.register')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</NoSSR>
|
||||
</NoSsr>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t('landing.summary.heading')}</h6>
|
||||
<h6>{t<string>('landing.summary.heading')}</h6>
|
||||
|
||||
<p>{t('landing.summary.body')}</p>
|
||||
<p>{t<string>('landing.summary.body')}</p>
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t('landing.features.heading')}</h6>
|
||||
<h6>{t<string>('landing.features.heading')}</h6>
|
||||
|
||||
<ul className="list-inside list-disc leading-loose">
|
||||
<li>{t('landing.features.list.free')}</li>
|
||||
<li>{t('landing.features.list.ads')}</li>
|
||||
<li>{t('landing.features.list.tracking')}</li>
|
||||
<li>{t('landing.features.list.languages')}</li>
|
||||
<li>{t('landing.features.list.import')}</li>
|
||||
<li>{t('landing.features.list.export')}</li>
|
||||
<li>{t<string>('landing.features.list.free')}</li>
|
||||
<li>{t<string>('landing.features.list.ads')}</li>
|
||||
<li>{t<string>('landing.features.list.tracking')}</li>
|
||||
<li>{t<string>('landing.features.list.languages')}</li>
|
||||
<li>{t<string>('landing.features.list.import')}</li>
|
||||
<li>{t<string>('landing.features.list.export')}</li>
|
||||
<li>
|
||||
<Trans t={t} i18nKey="landing.features.list.more">
|
||||
And a lot of exciting features,
|
||||
@ -113,7 +112,7 @@ const Home: NextPage = () => {
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t('landing.screenshots.heading')}</h6>
|
||||
<h6>{t<string>('landing.screenshots.heading')}</h6>
|
||||
|
||||
<div className={styles.screenshots}>
|
||||
{screenshots.map(({ src, alt }) => (
|
||||
@ -125,7 +124,7 @@ const Home: NextPage = () => {
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t('landing.testimonials.heading')}</h6>
|
||||
<h6>{t<string>('landing.testimonials.heading')}</h6>
|
||||
|
||||
<p className="my-3">
|
||||
<Trans t={t} i18nKey="landing.testimonials.body">
|
||||
@ -150,30 +149,30 @@ const Home: NextPage = () => {
|
||||
</section>
|
||||
|
||||
<section className={styles.section}>
|
||||
<h6>{t('landing.links.heading')}</h6>
|
||||
<h6>{t<string>('landing.links.heading')}</h6>
|
||||
|
||||
<div>
|
||||
<Link href="/meta/privacy" passHref>
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t('landing.links.links.privacy')}
|
||||
{t<string>('landing.links.links.privacy')}
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href="/meta/service" passHref>
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t('landing.links.links.service')}
|
||||
{t<string>('landing.links.links.service')}
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<a href={GITHUB_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t('landing.links.links.github')}
|
||||
{t<string>('landing.links.links.github')}
|
||||
</Button>
|
||||
</a>
|
||||
|
||||
<a href={DONATION_URL} target="_blank" rel="noreferrer">
|
||||
<Button variant="text" startIcon={<LinkIcon />}>
|
||||
{t('landing.links.links.donate')}
|
||||
{t<string>('landing.links.links.donate')}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
BIN
client/public/images/templates/leafish.jpg
Normal file
BIN
client/public/images/templates/leafish.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 187 KiB |
358
client/public/locales/el/builder.json
Normal file
358
client/public/locales/el/builder.json
Normal file
@ -0,0 +1,358 @@
|
||||
{
|
||||
"common": {
|
||||
"actions": {
|
||||
"add": "Προσθήκη νέου {{token}}",
|
||||
"delete": "Διαγραφή {{token}}",
|
||||
"edit": "Επεξεργασία {{token}}"
|
||||
},
|
||||
"columns": {
|
||||
"heading": "Στήλες",
|
||||
"tooltip": "Αλλαγή αριθμού στηλών"
|
||||
},
|
||||
"form": {
|
||||
"date": {
|
||||
"label": "Ημερομηνία"
|
||||
},
|
||||
"description": {
|
||||
"label": "Περιγραφή"
|
||||
},
|
||||
"email": {
|
||||
"label": "Διεύθυνση Email"
|
||||
},
|
||||
"end-date": {
|
||||
"help-text": "Αφήστε αυτό το πεδίο κενό, εάν εξακολουθεί να υπάρχει",
|
||||
"label": "Ημερομηνία λήξης"
|
||||
},
|
||||
"keywords": {
|
||||
"label": "Λέξεις κλειδιά"
|
||||
},
|
||||
"level": {
|
||||
"label": "Επίπεδο"
|
||||
},
|
||||
"levelNum": {
|
||||
"label": "Επίπεδο (αριθμός)"
|
||||
},
|
||||
"name": {
|
||||
"label": "Όνομα"
|
||||
},
|
||||
"phone": {
|
||||
"label": "Αριθμός τηλεφώνου"
|
||||
},
|
||||
"position": {
|
||||
"label": "Θέση"
|
||||
},
|
||||
"start-date": {
|
||||
"label": "Ημερομηνία έναρξης"
|
||||
},
|
||||
"subtitle": {
|
||||
"label": "Υπότιτλος"
|
||||
},
|
||||
"summary": {
|
||||
"label": "Σύνοψη"
|
||||
},
|
||||
"title": {
|
||||
"label": "Τίτλος"
|
||||
},
|
||||
"url": {
|
||||
"label": "Ιστοσελίδα"
|
||||
}
|
||||
},
|
||||
"glossary": {
|
||||
"page": "Σελίδα"
|
||||
},
|
||||
"list": {
|
||||
"actions": {
|
||||
"delete": "Διαγραφή",
|
||||
"duplicate": "Διπλότυπο",
|
||||
"edit": "Επεξεργασία"
|
||||
},
|
||||
"empty-text": "Αυτή η λίστα είναι κενή."
|
||||
},
|
||||
"tooltip": {
|
||||
"delete-item": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το στοιχείο; Αυτή είναι μια μη αναστρέψιμη ενέργεια.",
|
||||
"delete-section": "Διαγραφή ενότητας",
|
||||
"rename-section": "Μετονομασία ενότητας",
|
||||
"toggle-visibility": "Εναλλαγή ορατότητας"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"tooltip": {
|
||||
"center-artboard": "Κεντράρισμα πίνακα",
|
||||
"copy-link": "Αντιγραφή συνδέσμου στο βιογραφικό",
|
||||
"export-pdf": "Εξαγωγή σε PDF",
|
||||
"toggle-orientation": "Εναλλαγή προσανατολισμού σελίδας",
|
||||
"toggle-page-break-line": "Εναλλαγή γραμμής αλλαγής σελίδας",
|
||||
"toggle-sidebars": "Εναλλαγή πλευρικών γραμμών",
|
||||
"zoom-in": "Μεγέθυνση",
|
||||
"zoom-out": "Σμίκρυνση"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"menu": {
|
||||
"delete": "Διαγραφή",
|
||||
"duplicate": "Διπλότυπο",
|
||||
"rename": "Μετονομασία",
|
||||
"share-link": "Κοινοποίηση συνδέσμου",
|
||||
"tooltips": {
|
||||
"delete": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το βιογραφικό; Αυτή είναι μια μη αναστρέψιμη ενέργεια.",
|
||||
"share-link": "Πρέπει να αλλάξετε την ορατότητα του βιογραφικού σας σε δημόσιο για να το κάνετε ορατό σε άλλους."
|
||||
}
|
||||
}
|
||||
},
|
||||
"leftSidebar": {
|
||||
"sections": {
|
||||
"awards": {
|
||||
"form": {
|
||||
"awarder": {
|
||||
"label": "Βραβευόμενος"
|
||||
}
|
||||
}
|
||||
},
|
||||
"basics": {
|
||||
"actions": {
|
||||
"photo-filters": "Φίλτρα φωτογραφιών"
|
||||
},
|
||||
"heading": "Βασικά",
|
||||
"headline": {
|
||||
"label": "Επικεφαλίδα"
|
||||
},
|
||||
"name": {
|
||||
"label": "Ονοματεπώνυμο"
|
||||
},
|
||||
"photo-filters": {
|
||||
"effects": {
|
||||
"border": {
|
||||
"label": "Περίγραμμα"
|
||||
},
|
||||
"grayscale": {
|
||||
"label": "Κλίμακα του γκρι"
|
||||
},
|
||||
"heading": "Εφέ"
|
||||
},
|
||||
"shape": {
|
||||
"heading": "Σχήμα"
|
||||
},
|
||||
"size": {
|
||||
"heading": "Μέγεθος (σε px)"
|
||||
}
|
||||
},
|
||||
"photo-upload": {
|
||||
"tooltip": {
|
||||
"remove": "Αφαίρεση φωτογραφίας",
|
||||
"upload": "Ανέβασμα φωτογραφίας"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certifications": {
|
||||
"form": {
|
||||
"issuer": {
|
||||
"label": "Εκδότης"
|
||||
}
|
||||
}
|
||||
},
|
||||
"education": {
|
||||
"form": {
|
||||
"area-study": {
|
||||
"label": "Τομέας σπουδών"
|
||||
},
|
||||
"courses": {
|
||||
"label": "Σεμινάρια"
|
||||
},
|
||||
"degree": {
|
||||
"label": "Πτυχίο"
|
||||
},
|
||||
"grade": {
|
||||
"label": "Βαθμός"
|
||||
},
|
||||
"institution": {
|
||||
"label": "Ίδρυμα"
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"address": {
|
||||
"label": "Διεύθυνση"
|
||||
},
|
||||
"city": {
|
||||
"label": "Πόλη"
|
||||
},
|
||||
"country": {
|
||||
"label": "Χώρα"
|
||||
},
|
||||
"heading": "Τοποθεσία",
|
||||
"postal-code": {
|
||||
"label": "Ταχυδρομικός κώδικας"
|
||||
},
|
||||
"region": {
|
||||
"label": "Περιοχή"
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"form": {
|
||||
"network": {
|
||||
"label": "Δίκτυο"
|
||||
},
|
||||
"username": {
|
||||
"label": "Όνομα χρήστη"
|
||||
}
|
||||
},
|
||||
"heading": "Προφίλ",
|
||||
"heading_one": "Προφίλ"
|
||||
},
|
||||
"publications": {
|
||||
"form": {
|
||||
"publisher": {
|
||||
"label": "Εκδότης"
|
||||
}
|
||||
}
|
||||
},
|
||||
"references": {
|
||||
"form": {
|
||||
"relationship": {
|
||||
"label": "Σχέση"
|
||||
}
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"heading": "Ενότητα"
|
||||
},
|
||||
"volunteer": {
|
||||
"form": {
|
||||
"organization": {
|
||||
"label": "Οργανισμός"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rightSidebar": {
|
||||
"sections": {
|
||||
"css": {
|
||||
"heading": "Προσαρμοσμένο CSS"
|
||||
},
|
||||
"export": {
|
||||
"heading": "Εξαγωγή",
|
||||
"json": {
|
||||
"primary": "JSON",
|
||||
"secondary": "Κατεβάστε μια έκδοση JSON του βιογραφικού σας που μπορεί να εισαχθεί ξανά στο Reactive Resume."
|
||||
},
|
||||
"pdf": {
|
||||
"loading": {
|
||||
"primary": "Δημιουργία PDF",
|
||||
"secondary": "Περιμένετε μέχρι να δημιουργηθεί το PDF σας, αυτό μπορεί να διαρκέσει έως και 15 δευτερόλεπτα."
|
||||
},
|
||||
"normal": {
|
||||
"primary": "PDF",
|
||||
"secondary": "Κατεβάστε ένα PDF του βιογραφικού σας που μπορείτε να εκτυπώσετε και να στείλετε στην εργασία των ονείρων σας. Αυτό το αρχείο δεν μπορεί να εισαχθεί ξανά για περαιτέρω επεξεργασία."
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"heading": "Διάταξη",
|
||||
"tooltip": {
|
||||
"reset-layout": "Επαναφορά διάταξης"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"bugs-features": {
|
||||
"body": "Υπάρχει κάτι που σας εμποδίζει να φτιάξετε ένα βιογραφικό σημείωμα; Ή μήπως έχετε μια καταπληκτική ιδέα να προσθέσετε; Θέστε το ως σφάλμα στο GitHub για να ξεκινήσετε.",
|
||||
"button": "Σφάλματα GitHub",
|
||||
"heading": "Σφάλματα; Αιτήματα δυνατοτήτων;"
|
||||
},
|
||||
"donate": {
|
||||
"body": "Αν σας άρεσε να χρησιμοποιείτε το Reactive Resume, σκεφτείτε το ενδεχόμενο να δωρίσετε όσο το δυνατόν περισσότερα για τον σκοπό της διατήρησης και λειτουργίας της εφαρμογής, χωρίς διαφημίσεις και δωρεάν για πάντα.",
|
||||
"button": "Κεράστε με ένα καφεδάκι",
|
||||
"heading": "Κάντε δωρεά στο Reactive βιογραφικό"
|
||||
},
|
||||
"github": "Πηγαίος κώδικας",
|
||||
"heading": "Σύνδεσμοι"
|
||||
},
|
||||
"settings": {
|
||||
"global": {
|
||||
"date": {
|
||||
"primary": "Ημερομηνία",
|
||||
"secondary": "Μορφή ημερομηνίας για χρήση στην εφαρμογή"
|
||||
},
|
||||
"heading": "Καθολικό",
|
||||
"language": {
|
||||
"primary": "Γλώσσα",
|
||||
"secondary": "Εμφάνιση γλώσσας για χρήση στην εφαρμογή"
|
||||
},
|
||||
"theme": {
|
||||
"primary": "Θέμα"
|
||||
}
|
||||
},
|
||||
"heading": "Ρυθμίσεις",
|
||||
"page": {
|
||||
"break-line": {
|
||||
"primary": "Γραμμή διακοπής",
|
||||
"secondary": "Εμφάνιση μιας γραμμής σε όλες τις σελίδες για να επισημάνετε το ύψος μιας σελίδας Α4"
|
||||
},
|
||||
"heading": "Σελίδα",
|
||||
"orientation": {
|
||||
"disabled": "Δεν έχει αποτέλεσμα όταν υπάρχει μόνο μία σελίδα",
|
||||
"primary": "Προσανατολισμός",
|
||||
"secondary": "Αν θα εμφανίζονται οι σελίδες οριζόντια ή κάθετα"
|
||||
}
|
||||
},
|
||||
"resume": {
|
||||
"heading": "Βιογραφικό σημείωμα",
|
||||
"reset": {
|
||||
"primary": "Επαναφορά όλων",
|
||||
"secondary": "Κάνατε πάρα πολλά λάθη; Κάντε κλικ εδώ για να επαναφέρετε όλες τις αλλαγές και να ξεκινήσετε από την αρχή. Προσέξτε, αυτή η ενέργεια δεν μπορεί να αντιστραφεί."
|
||||
},
|
||||
"sample": {
|
||||
"primary": "Φόρτωση δειγμάτων δεδομένων",
|
||||
"secondary": "Δεν είστε σίγουροι από πού να ξεκινήσετε; Κάντε κλικ εδώ για να φορτώσετε μερικά δείγματα δεδομένων για να δείτε πώς φαίνεται ένα πλήρες βιογραφικό."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sharing": {
|
||||
"heading": "Κοινοποίηση",
|
||||
"short-url": {
|
||||
"label": "Προτίμηση σύντομης διεύθυνσης"
|
||||
},
|
||||
"visibility": {
|
||||
"subtitle": "Επιτρέψτε σε οποιονδήποτε έχει σύνδεσμο να δει το βιογραφικό σας",
|
||||
"title": "Δημόσιο"
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"heading": "Πρότυπα"
|
||||
},
|
||||
"theme": {
|
||||
"form": {
|
||||
"background": {
|
||||
"label": "Φόντο"
|
||||
},
|
||||
"primary": {
|
||||
"label": "Πρωτεύον"
|
||||
},
|
||||
"text": {
|
||||
"label": "Κείμενο"
|
||||
}
|
||||
},
|
||||
"heading": "Θέμα"
|
||||
},
|
||||
"typography": {
|
||||
"form": {
|
||||
"font-family": {
|
||||
"label": "Γραμματοσειρά"
|
||||
},
|
||||
"font-size": {
|
||||
"label": "Μέγεθος γραμματοσειράς"
|
||||
}
|
||||
},
|
||||
"heading": "Τυπογραφία",
|
||||
"widgets": {
|
||||
"body": {
|
||||
"label": "Σώμα"
|
||||
},
|
||||
"headings": {
|
||||
"label": "Επικεφαλίδες"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
client/public/locales/el/common.json
Normal file
29
client/public/locales/el/common.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"avatar": {
|
||||
"menu": {
|
||||
"greeting": "Γειά σου",
|
||||
"logout": "Αποσύνδεση"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"credit": "Ένα έργο με πάθος από τον <1>Amruth Pillai</1>",
|
||||
"license": "Από την κοινότητα, για την κοινότητα."
|
||||
},
|
||||
"markdown": {
|
||||
"help-text": "Αυτή η ενότητα υποστηρίζει τη μορφοποίηση <1>markdown</1>."
|
||||
},
|
||||
"date": {
|
||||
"present": "Τώρα"
|
||||
},
|
||||
"subtitle": "Ένας δωρεάν κατασκευαστής βιογραφικών σημειωμάτων ανοικτού κώδικα.",
|
||||
"title": "Reactive Resume",
|
||||
"toast": {
|
||||
"error": {
|
||||
"upload-file-size": "Παρακαλούμε ανεβάζετε μόνο αρχεία κάτω των 2 megabytes.",
|
||||
"upload-photo-size": "Παρακαλούμε ανεβάστε μόνο φωτογραφίες κάτω των 2 megabytes, κατά προτίμηση τετράγωνες."
|
||||
},
|
||||
"success": {
|
||||
"resume-link-copied": "Ένας σύνδεσμος για το βιογραφικό σας αντιγράφηκε."
|
||||
}
|
||||
}
|
||||
}
|
||||
25
client/public/locales/el/dashboard.json
Normal file
25
client/public/locales/el/dashboard.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"create-resume": {
|
||||
"subtitle": "Επανεκκίνηση από την αρχή",
|
||||
"title": "Δημιουργία νέου βιογραφικού"
|
||||
},
|
||||
"import-external": {
|
||||
"subtitle": "LinkedIn, JSON Resume, Reactive Resume",
|
||||
"title": "Εισαγωγή από εξωτερικές πηγές"
|
||||
},
|
||||
"resume": {
|
||||
"menu": {
|
||||
"delete": "Διαγραφή",
|
||||
"duplicate": "Διπλότυπο",
|
||||
"open": "Άνοιγμα",
|
||||
"rename": "Μετονομασία",
|
||||
"share-link": "Κοινοποίηση συνδέσμου",
|
||||
"tooltips": {
|
||||
"delete": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το βιογραφικό; Αυτή είναι μια μη αναστρέψιμη ενέργεια.",
|
||||
"share-link": "Πρέπει να αλλάξετε την ορατότητα του βιογραφικού σας σε δημόσιο για να το κάνετε ορατό σε άλλους."
|
||||
}
|
||||
},
|
||||
"timestamp": "Τελευταία ενημέρωση πριν από {{timestamp}}"
|
||||
},
|
||||
"title": "Πίνακας ελέγχου"
|
||||
}
|
||||
41
client/public/locales/el/landing.json
Normal file
41
client/public/locales/el/landing.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"actions": {
|
||||
"app": "Μετάβαση στην εφαρμογή",
|
||||
"login": "Σύνδεση",
|
||||
"logout": "Αποσύνδεση",
|
||||
"register": "Εγγραφή"
|
||||
},
|
||||
"features": {
|
||||
"heading": "Δυνατότητες",
|
||||
"list": {
|
||||
"ads": "Χωρίς διαφημίσεις",
|
||||
"export": "Εξαγωγή του βιογραφικού σας σε μορφή JSON ή PDF",
|
||||
"free": "Δωρεάν για πάντα",
|
||||
"import": "Εισαγωγή δεδομένων από το LinkedIn, JSON Resume",
|
||||
"languages": "Προσβάσιμο σε πολλές γλώσσες",
|
||||
"more": "Και πολλά άλλα συναρπαστικά χαρακτηριστικά, <1>διαβάστε τα όλα εδώ</1>",
|
||||
"tracking": "Χωρίς παρακολούθηση χρήστη"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"heading": "Σύνδεσμοι",
|
||||
"links": {
|
||||
"donate": "Δωρεά",
|
||||
"github": "Πηγαίος Κώδικας",
|
||||
"privacy": "Πολιτική Απορρήτου",
|
||||
"service": "Όρους παροχής υπηρεσιών"
|
||||
}
|
||||
},
|
||||
"screenshots": {
|
||||
"heading": "Στιγμιότυπα οθόνης"
|
||||
},
|
||||
"testimonials": {
|
||||
"heading": "Αναφορές",
|
||||
"body": "Καλή ή κακή, θα ήθελα πολύ να ακούσω τη γνώμη σας για το Reactive Resume και πώς ήταν η εμπειρία σας.<br/>Ακολουθούν μερικά από τα μηνύματα που έστειλαν χρήστες από όλο τον κόσμο.",
|
||||
"contact": "Μπορείτε να επικοινωνήσετε μαζί μου μέσω <1>του email μου</1> ή μέσω της φόρμας επικοινωνίας στην <3>ιστοσελίδα μου</3>."
|
||||
},
|
||||
"summary": {
|
||||
"body": "Το Reactive Resume είναι ένας δωρεάν κατασκευαστής βιογραφικών σημειωμάτων ανοικτού κώδικα που έχει δημιουργηθεί για να κάνει τις καθημερινές εργασίες δημιουργίας, ενημέρωσης και κοινοποίησης του βιογραφικού σας σημειώματος τόσο εύκολες όσο το 1, 2, 3. Με αυτή την εφαρμογή, μπορείτε να δημιουργήσετε πολλαπλά βιογραφικά, να τα μοιραστείτε με τους υπεύθυνους προσλήψεων ή τους φίλους σας μέσω ενός μοναδικού συνδέσμου και να τα εκτυπώσετε σε μορφή PDF, και όλα αυτά δωρεάν, χωρίς διαφημίσεις, χωρίς παρακολούθηση, χωρίς να χάσετε την ακεραιότητα και το απόρρητο των δεδομένων σας.",
|
||||
"heading": "Σύνοψη"
|
||||
}
|
||||
}
|
||||
136
client/public/locales/el/modals.json
Normal file
136
client/public/locales/el/modals.json
Normal file
@ -0,0 +1,136 @@
|
||||
{
|
||||
"auth": {
|
||||
"forgot-password": {
|
||||
"actions": {
|
||||
"send-email": "Αποστολή email επαναφοράς κωδικού πρόσβασης"
|
||||
},
|
||||
"body": "Απλώς εισάγετε τη διεύθυνση ηλεκτρονικού ταχυδρομείου που σχετίζεται με τον λογαριασμό που θέλετε να ανακτήσετε.",
|
||||
"form": {
|
||||
"email": {
|
||||
"label": "Διεύθυνση Email"
|
||||
}
|
||||
},
|
||||
"heading": "Ξεχάσατε τον κωδικό σας;",
|
||||
"help-text": "Εάν ο λογαριασμός υπάρχει, θα λάβετε ένα email με έναν σύνδεσμο για να επαναφέρετε τον κωδικό πρόσβασής σας."
|
||||
},
|
||||
"login": {
|
||||
"actions": {
|
||||
"login": "Σύνδεση",
|
||||
"google": "Συνδεθείτε με το Google"
|
||||
},
|
||||
"body": "Εισαγάγετε το όνομα χρήστη και τον κωδικό πρόσβασης που σχετίζονται με τον λογαριασμό σας για να συνδεθείτε και να αποκτήσετε πρόσβαση, να διαχειριστείτε και να μοιραστείτε τα βιογραφικά σας.",
|
||||
"form": {
|
||||
"password": {
|
||||
"label": "Κωδικός πρόσβασης"
|
||||
},
|
||||
"username": {
|
||||
"help-text": "Μπορείτε επίσης να εισάγετε τη διεύθυνση email σας",
|
||||
"label": "Όνομα χρήστη"
|
||||
}
|
||||
},
|
||||
"heading": "Συνδεθείτε στο λογαριασμό σας",
|
||||
"recover-text": "Σε περίπτωση που έχετε ξεχάσει τον κωδικό πρόσβασής σας, μπορείτε να <1>ανακτήσετε τον λογαριασμό σας</1> εδώ.",
|
||||
"register-text": "Αν δεν έχετε, μπορείτε να <1>δημιουργήσετε έναν λογαριασμό</1> εδώ."
|
||||
},
|
||||
"register": {
|
||||
"actions": {
|
||||
"register": "Εγγραφή",
|
||||
"google": "Εγγραφή με το Google"
|
||||
},
|
||||
"body": "Εισαγάγετε τα προσωπικά σας στοιχεία για να δημιουργήσετε έναν λογαριασμό.",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "Επιβεβαίωση Κωδικού Πρόσβασης"
|
||||
},
|
||||
"email": {
|
||||
"label": "Διεύθυνση ηλεκτρονικού ταχυδρομείου"
|
||||
},
|
||||
"name": {
|
||||
"label": "Ονοματεπώνυμο"
|
||||
},
|
||||
"password": {
|
||||
"label": "Κωδικός πρόσβασης"
|
||||
},
|
||||
"username": {
|
||||
"label": "Όνομα χρήστη"
|
||||
}
|
||||
},
|
||||
"heading": "Δημιουργία λογαριασμού",
|
||||
"loginText": "Αν έχετε ήδη λογαριασμό, μπορείτε να <1>συνδεθείτε εδώ</1>."
|
||||
},
|
||||
"reset-password": {
|
||||
"actions": {
|
||||
"set-password": "Ορισμός νέου κωδικού πρόσβασης"
|
||||
},
|
||||
"body": "Εισάγετε έναν νέο κωδικό πρόσβασης για το λογαριασμό σας.",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "Επιβεβαίωση κωδικού πρόσβασης"
|
||||
},
|
||||
"password": {
|
||||
"label": "Κωδικός πρόσβασης"
|
||||
}
|
||||
},
|
||||
"heading": "Επαναφορά του κωδικού πρόσβασής σας"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"create-resume": {
|
||||
"actions": {
|
||||
"create-resume": "Δημιουργία βιογραφικού σημειώματος"
|
||||
},
|
||||
"body": "Ξεκινήστε να δημιουργείτε το βιογραφικό σας δίνοντάς του ένα όνομα. Θα μπορούσε να αναφέρεται στον ρόλο για τον οποίο κάνετε αίτηση ή απλώς στο αγαπημένο σας σνακ.",
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "Όνομα"
|
||||
},
|
||||
"public": {
|
||||
"label": "Είναι δημόσια προσβάσιμο;"
|
||||
},
|
||||
"slug": {
|
||||
"label": "Slug"
|
||||
}
|
||||
},
|
||||
"heading": "Δημιουργία νέου βιογραφικού σημειώματος"
|
||||
},
|
||||
"import-external": {
|
||||
"heading": "Εισαγωγή από εξωτερικές πηγές",
|
||||
"json-resume": {
|
||||
"actions": {
|
||||
"upload-json": "Μεταφόρτωση JSON"
|
||||
},
|
||||
"body": "Αν έχετε έτοιμο ένα <1>επικυρωμένο JSON Resume</1>, μπορείτε να το χρησιμοποιήσετε για να επιταχύνετε την ανάπτυξή σας στο Reactive Resume. Κάντε κλικ στο παρακάτω κουμπί και ανεβάστε ένα έγκυρο αρχείο JSON για να ξεκινήσετε.",
|
||||
"heading": "Εισαγωγή από JSON Resume"
|
||||
},
|
||||
"linkedin": {
|
||||
"actions": {
|
||||
"upload-archive": "Ανεβάστε το αρχείο ZIP"
|
||||
},
|
||||
"body": "Μπορείτε να εξοικονομήσετε χρόνο εξάγοντας τα δεδομένα σας από το LinkedIn και χρησιμοποιώντας τα για αυτόματη συμπλήρωση πεδίων στο Reactive Resume. Μεταβείτε στην ενότητα <1>Απόρρητο δεδομένων</1> στο LinkedIn και ζητήστε ένα αρχείο των δεδομένων σας. Μόλις είναι διαθέσιμο, ανεβάστε το αρχείο ZIP παρακάτω.",
|
||||
"heading": "Εισαγωγή από το LinkedIn"
|
||||
},
|
||||
"reactive-resume": {
|
||||
"actions": {
|
||||
"upload-json": "Μεταφόρτωση JSON",
|
||||
"upload-json-v2": "Μεταφόρτωση JSON από v2"
|
||||
},
|
||||
"body": "Εάν έχετε ένα JSON που εξήχθη με την τρέχουσα έκδοση του Reactive Resume, μπορείτε να το εισάγετε ξανά εδώ για να λάβετε ξανά μια επεξεργάσιμη έκδοση.",
|
||||
"heading": "Εισαγωγή από Reactive Resume"
|
||||
}
|
||||
},
|
||||
"rename-resume": {
|
||||
"actions": {
|
||||
"rename-resume": "Μετονομασία βιογραφικού"
|
||||
},
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "Ονομα"
|
||||
},
|
||||
"slug": {
|
||||
"label": "Slug"
|
||||
}
|
||||
},
|
||||
"heading": "Μετονομασία του βιογραφικού σας"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -119,6 +119,9 @@
|
||||
"name": {
|
||||
"label": "Full Name"
|
||||
},
|
||||
"birthdate": {
|
||||
"label": "Date of Birth"
|
||||
},
|
||||
"photo-filters": {
|
||||
"effects": {
|
||||
"border": {
|
||||
|
||||
358
client/public/locales/or/builder.json
Normal file
358
client/public/locales/or/builder.json
Normal file
@ -0,0 +1,358 @@
|
||||
{
|
||||
"common": {
|
||||
"actions": {
|
||||
"add": "ନୂତନ {{token}} ଯୋଡ଼ନ୍ତୁ ।",
|
||||
"delete": "{{token}} ଲିଭାନ୍ତୁ ।",
|
||||
"edit": "{{token}} ସମ୍ପାଦନ କରନ୍ତୁ ।"
|
||||
},
|
||||
"columns": {
|
||||
"heading": "ସ୍ତମ୍ଭଗୁଡିକ",
|
||||
"tooltip": "ସ୍ତମ୍ଭ ସଂଖ୍ୟା ପରିବର୍ତ୍ତନ କରନ୍ତୁ ।"
|
||||
},
|
||||
"form": {
|
||||
"date": {
|
||||
"label": "ତାରିଖ"
|
||||
},
|
||||
"description": {
|
||||
"label": "ବର୍ଣ୍ଣନା"
|
||||
},
|
||||
"email": {
|
||||
"label": "ଇମେଲ ଠିକଣା"
|
||||
},
|
||||
"end-date": {
|
||||
"help-text": "ଯଦି ଉପସ୍ଥିତ ଅଛି ତେବେ ଏହି କ୍ଷେତ୍ରକୁ ଖାଲି ଛାଡିଦିଅନ୍ତୁ ।",
|
||||
"label": "ଶେଷ ତାରିଖ"
|
||||
},
|
||||
"keywords": {
|
||||
"label": "କୀୱାର୍ଡ଼"
|
||||
},
|
||||
"level": {
|
||||
"label": "ସ୍ତର"
|
||||
},
|
||||
"levelNum": {
|
||||
"label": "ସ୍ତର (ସଂଖ୍ୟା)"
|
||||
},
|
||||
"name": {
|
||||
"label": "ନାମ"
|
||||
},
|
||||
"phone": {
|
||||
"label": "ଫୋନ୍ ନମ୍ବର"
|
||||
},
|
||||
"position": {
|
||||
"label": "ଅବସ୍ଥାନ"
|
||||
},
|
||||
"start-date": {
|
||||
"label": "ଆରମ୍ଭ ତାରିଖ"
|
||||
},
|
||||
"subtitle": {
|
||||
"label": "ସବଟାଇଟଲ"
|
||||
},
|
||||
"summary": {
|
||||
"label": "ସାରାଂଶ"
|
||||
},
|
||||
"title": {
|
||||
"label": "ଆଖ୍ୟା"
|
||||
},
|
||||
"url": {
|
||||
"label": "ୱେବସାଇଟ୍"
|
||||
}
|
||||
},
|
||||
"glossary": {
|
||||
"page": "ପୃଷ୍ଠା"
|
||||
},
|
||||
"list": {
|
||||
"actions": {
|
||||
"delete": "ବିଲୋପ କରନ୍ତୁ",
|
||||
"duplicate": "ନକଲ",
|
||||
"edit": "ସମ୍ପାଦନ କରନ୍ତୁ"
|
||||
},
|
||||
"empty-text": "ଏହି ତାଲିକା ଖାଲି ଅଛି ।"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete-item": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ଏହି ଆଇଟମ୍ ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି? ଏହା ଏକ ଅପରିବର୍ତ୍ତନୀୟ କାର୍ଯ୍ୟ ।",
|
||||
"delete-section": "ବିଭାଗ ବିଲୋପ କରନ୍ତୁ ।",
|
||||
"rename-section": "ବିଭାଗର ନାମ ପରିବର୍ତ୍ତନ କରନ୍ତୁ ।",
|
||||
"toggle-visibility": "ଭିଜିବିଲିଟି ଟଗଲ କରନ୍ତୁ ।"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"tooltip": {
|
||||
"center-artboard": "କେନ୍ଦ୍ର ଆର୍ଟବୋର୍ଡ",
|
||||
"copy-link": "ଜାରିରଖିବାକୁ ପାଇଁ ଲିଙ୍କ୍ କପି କରନ୍ତୁ ।",
|
||||
"export-pdf": "PDF ରପ୍ତାନି କରନ୍ତୁ",
|
||||
"toggle-orientation": "ପୃଷ୍ଠା ଓରିଏଣ୍ଟେସନ୍ ଟଗଲ କରନ୍ତୁ ।",
|
||||
"toggle-page-break-line": "ପୃଷ୍ଠା ବ୍ରେକ୍ ଲାଇନ୍ ଟଗଲ କରନ୍ତୁ ।",
|
||||
"toggle-sidebars": "ସାଇଡ୍ ବାର ଟଗଲ କରନ୍ତୁ ।",
|
||||
"zoom-in": "ଜୁମ୍ ଇନ୍ କରନ୍ତୁ ।",
|
||||
"zoom-out": "ଜୁମ୍ ଆଉଟ୍ କରନ୍ତୁ ।"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"menu": {
|
||||
"delete": "ବିଲୋପ କରନ୍ତୁ",
|
||||
"duplicate": "ନକଲ",
|
||||
"rename": "ନାମ ବଦଳାନ୍ତୁ",
|
||||
"share-link": "ଲିଙ୍କ୍ ଅଂଶୀଦାର କରନ୍ତୁ ।",
|
||||
"tooltips": {
|
||||
"delete": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ଏହି ଆଇଟମ୍ ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି? ଏହା ଏକ ଅପରିବର୍ତ୍ତନୀୟ କାର୍ଯ୍ୟ ।",
|
||||
"share-link": "ଏହାକୁ ଅନ୍ୟମାନଙ୍କ ପାଇଁ ଦୃଶ୍ୟମାନ କରିବା ପାଇଁ ଆପଣଙ୍କର ରେଜ୍ୟୁମର ଦୃଶ୍ୟତାକୁ ସର୍ବସାଧାରଣରେ ପରିବର୍ତ୍ତନ କରିବାକୁ ପଡିବ ।"
|
||||
}
|
||||
}
|
||||
},
|
||||
"leftSidebar": {
|
||||
"sections": {
|
||||
"awards": {
|
||||
"form": {
|
||||
"awarder": {
|
||||
"label": "ପୁରସ୍କାରଦାତା"
|
||||
}
|
||||
}
|
||||
},
|
||||
"basics": {
|
||||
"actions": {
|
||||
"photo-filters": "ଫଟୋ ଫିଲ୍ଟର୍"
|
||||
},
|
||||
"heading": "ମୌଳିକ",
|
||||
"headline": {
|
||||
"label": "ଶୀର୍ଷକ"
|
||||
},
|
||||
"name": {
|
||||
"label": "ପୁରା ନାମ"
|
||||
},
|
||||
"photo-filters": {
|
||||
"effects": {
|
||||
"border": {
|
||||
"label": "ବର୍ଡର"
|
||||
},
|
||||
"grayscale": {
|
||||
"label": "ଗ୍ରେସ୍କେଲ୍"
|
||||
},
|
||||
"heading": "ପ୍ରଭାବଗୁଡ଼ିକ"
|
||||
},
|
||||
"shape": {
|
||||
"heading": "ଆକୃତି"
|
||||
},
|
||||
"size": {
|
||||
"heading": "ଆକାର (px ରେ)"
|
||||
}
|
||||
},
|
||||
"photo-upload": {
|
||||
"tooltip": {
|
||||
"remove": "ଫଟୋ ହଟାନ୍ତୁ",
|
||||
"upload": "ଫୋଟୋ ଅପଲୋଡ କରନ୍ତୁ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certifications": {
|
||||
"form": {
|
||||
"issuer": {
|
||||
"label": "ପ୍ରଦାନକାରୀ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"education": {
|
||||
"form": {
|
||||
"area-study": {
|
||||
"label": "ଅଧ୍ୟୟନର କ୍ଷେତ୍ର"
|
||||
},
|
||||
"courses": {
|
||||
"label": "ପାଠ୍ୟକ୍ରମ"
|
||||
},
|
||||
"degree": {
|
||||
"label": "ଡିଗ୍ରୀ"
|
||||
},
|
||||
"grade": {
|
||||
"label": "ଗ୍ରେଡ୍"
|
||||
},
|
||||
"institution": {
|
||||
"label": "ସଂସ୍ଥା"
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"address": {
|
||||
"label": "ଠିକଣା"
|
||||
},
|
||||
"city": {
|
||||
"label": "ସହର"
|
||||
},
|
||||
"country": {
|
||||
"label": "ଦେଶ"
|
||||
},
|
||||
"heading": "ଅବସ୍ଥାନ",
|
||||
"postal-code": {
|
||||
"label": "ଡାକ କୋଡ୍"
|
||||
},
|
||||
"region": {
|
||||
"label": "ଅଞ୍ଚଳ"
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"form": {
|
||||
"network": {
|
||||
"label": "ନେଟୱର୍କ"
|
||||
},
|
||||
"username": {
|
||||
"label": "ଉପଯୋଗକର୍ତ୍ତା ନାମ"
|
||||
}
|
||||
},
|
||||
"heading": "ପ୍ରୋଫାଇଲ୍ ଗୁଡ଼ିକ",
|
||||
"heading_one": "ପ୍ରୋଫାଇଲ୍"
|
||||
},
|
||||
"publications": {
|
||||
"form": {
|
||||
"publisher": {
|
||||
"label": "ପ୍ରକାଶକ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"references": {
|
||||
"form": {
|
||||
"relationship": {
|
||||
"label": "ସମ୍ପର୍କ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"heading": "ବିଭାଗ"
|
||||
},
|
||||
"volunteer": {
|
||||
"form": {
|
||||
"organization": {
|
||||
"label": "ସଙ୍ଗଠନ"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rightSidebar": {
|
||||
"sections": {
|
||||
"css": {
|
||||
"heading": "କଷ୍ଟମ୍ CSS"
|
||||
},
|
||||
"export": {
|
||||
"heading": "ରପ୍ତାନି କରନ୍ତୁ",
|
||||
"json": {
|
||||
"primary": "JSON",
|
||||
"secondary": "ତୁମର ରିଜ୍ୟୁମର ଏକ JSON ସଂସ୍କରଣ ଡାଉନଲୋଡ୍ କର ଯାହାକି Reactive Resume କୁ ଆମଦାନୀ ହୋଇପାରିବ ।"
|
||||
},
|
||||
"pdf": {
|
||||
"loading": {
|
||||
"primary": "PDF ସୃଷ୍ଟି କରୁଛି",
|
||||
"secondary": "ଆପଣଙ୍କର PDF ସୃଷ୍ଟି ହେଉଛି ଦୟାକରି ଅପେକ୍ଷା କରନ୍ତୁ, ଏହା ୧୫ ସେକେଣ୍ଡ ପର୍ଯ୍ୟନ୍ତ ସମୟ ନେଇପାରେ ।"
|
||||
},
|
||||
"normal": {
|
||||
"primary": "PDF",
|
||||
"secondary": "ଆପଣଙ୍କର ରିଜ୍ୟୁମର ଏକ PDF ଡାଉନଲୋଡ୍ କରନ୍ତୁ ଯାହାକୁ ଆପଣ ଆପଣଙ୍କର ପ୍ରିୟ ନିଯୁକ୍ତିଦାତାଙ୍କୁ ପ୍ରିଣ୍ଟ କରି ପଠାଇ ପାରିବେ । ପରବର୍ତ୍ତୀ ସମ୍ପାଦନା ପାଇଁ ଏହି ଫାଇଲ୍ ପୁନର୍ବାର ଆମଦାନୀ ହୋଇପାରିବ ନାହିଁ ।"
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"heading": "ଲେଆଉଟ୍",
|
||||
"tooltip": {
|
||||
"reset-layout": "ଲେଆଉଟ୍ ରିସେଟ୍ କରନ୍ତୁ"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"bugs-features": {
|
||||
"body": "ଏକ ରିଜ୍ୟୁମ୍ ତିଆରି କରିବାରେ ଆପଣଙ୍କୁ କିଛି ବାଧା ଦେଉଛି କି? କିମ୍ବା ଯୋଡିବାକୁ ଆପଣଙ୍କର ଏକ ଆଶ୍ଚର୍ଯ୍ୟଜନକ ଧାରଣା ଅଛି କି? ଆରମ୍ଭ କରିବା ପାଇଁ GitHub ରେ ଏକ ସମସ୍ୟା ଉଠାନ୍ତୁ ।",
|
||||
"button": "GitHub ସମସ୍ୟା",
|
||||
"heading": "ତ୍ରୁଟି? ବୈଶିଷ୍ଟ୍ୟ ଅନୁରୋଧ?"
|
||||
},
|
||||
"donate": {
|
||||
"body": "ଯଦି ଆପଣ Reactive Resume ବ୍ୟବହାର କରିବାକୁ ପସନ୍ଦ କରନ୍ତି, ଦୟାକରି ବିଜ୍ଞାପନ ବିନା ଏବଂ ସବୁଦିନ ପାଇଁ ମାଗଣା ଆପ୍ କୁ ଚାଲୁରଖିବା ପାଇଁ ଆପଣ ଯେତେ ସମ୍ଭବ ଦାନ କରିବାକୁ ଚିନ୍ତା କରନ୍ତୁ ।",
|
||||
"button": "ମୋତେ ଏକ କଫି କିଣନ୍ତୁ",
|
||||
"heading": "Reactive Resume ପାଇଁ ଦାନ କରନ୍ତୁ ।"
|
||||
},
|
||||
"github": "ଉତ୍ସ କୋଡ୍",
|
||||
"heading": "ଲିଙ୍କ୍"
|
||||
},
|
||||
"settings": {
|
||||
"global": {
|
||||
"date": {
|
||||
"primary": "ତାରିଖ",
|
||||
"secondary": "ଆପ୍ ରେ ବ୍ୟବହାର କରିବାକୁ ତାରିଖ ଫର୍ମାଟ୍"
|
||||
},
|
||||
"heading": "ଗ୍ଲୋବାଲ୍",
|
||||
"language": {
|
||||
"primary": "ଭାଷା",
|
||||
"secondary": "ଆପ୍ ରେ ବ୍ୟବହାର କରିବାକୁ ଭାଷା ପ୍ରଦର୍ଶନ କରନ୍ତୁ"
|
||||
},
|
||||
"theme": {
|
||||
"primary": "ଥିମ୍"
|
||||
}
|
||||
},
|
||||
"heading": "ସେଟିଂସ୍",
|
||||
"page": {
|
||||
"break-line": {
|
||||
"primary": "ବ୍ରେକ୍ ଲାଇନ୍",
|
||||
"secondary": "A4 ପୃଷ୍ଠାର ଉଚ୍ଚତା ଚିହ୍ନିତ କରିବାକୁ ସମସ୍ତ ପୃଷ୍ଠାରେ ଏକ ରେଖା ଦେଖାନ୍ତୁ ।"
|
||||
},
|
||||
"heading": "ପୃଷ୍ଠା",
|
||||
"orientation": {
|
||||
"disabled": "କେବଳ ଗୋଟିଏ ପୃଷ୍ଠା ଥିବାବେଳେ ଏହାର କୌଣସି ପ୍ରଭାବ ନାହିଁ ।",
|
||||
"primary": "ଓରିଏଣ୍ଟେସନ୍",
|
||||
"secondary": "ପୃଷ୍ଠାଗୁଡ଼ିକ ଭୂସମାନ୍ତର କିମ୍ବା ଭୂଲମ୍ବ ଭାବରେ ପ୍ରଦର୍ଶିତ ହେବ କି ନାହିଁ ।"
|
||||
}
|
||||
},
|
||||
"resume": {
|
||||
"heading": "ରେଜ୍ୟୁମ",
|
||||
"reset": {
|
||||
"primary": "ସବୁକିଛି ରିସେଟ୍ କରନ୍ତୁ ।",
|
||||
"secondary": "ବହୁତ ଭୁଲ୍ କରିଛନ୍ତି କି? ସମସ୍ତ ପରିବର୍ତ୍ତନକୁ ରିସେଟ୍ କରିବାକୁ ଏବଂ ଆରମ୍ଭରୁ ଆରମ୍ଭ କରିବାକୁ ଏଠାରେ କ୍ଲିକ୍ କରନ୍ତୁ । ସାବଧାନ ରୁହନ୍ତୁ, ଏହି କାର୍ଯ୍ୟଟି ଅପରିବର୍ତ୍ତନୀୟ ।"
|
||||
},
|
||||
"sample": {
|
||||
"primary": "ନମୁନା ତଥ୍ୟ ଲୋଡ୍ କରନ୍ତୁ ।",
|
||||
"secondary": "କେଉଁଠାରୁ ଆରମ୍ଭ କରିବେ ନିଶ୍ଚିତ ନୁହଁନ୍ତି? ଏକ ସଂପୂର୍ଣ୍ଣ ରିଜ୍ୟୁମ୍ କିପରି ଦେଖାଯାଉଛି ଦେଖିବା ପାଇଁ କିଛି ନମୁନା ତଥ୍ୟ ଲୋଡ୍ କରିବାକୁ ଏଠାରେ କ୍ଲିକ୍ କରନ୍ତୁ ।"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sharing": {
|
||||
"heading": "ଅଂଶୀଦାର",
|
||||
"short-url": {
|
||||
"label": "ସଂକ୍ଷିପ୍ତ URL କୁ ପସନ୍ଦ କରନ୍ତୁ ।"
|
||||
},
|
||||
"visibility": {
|
||||
"subtitle": "ଆପଣଙ୍କର ରିଜ୍ୟୁମ୍ ଦେଖିବାକୁ ଲିଙ୍କ୍ ଥିବା କାହାକୁ ଅନୁମତି ଦିଅନ୍ତୁ ।",
|
||||
"title": "ଜନସାଧାରଣ"
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"heading": "ଟେମ୍ପଲେଟ୍"
|
||||
},
|
||||
"theme": {
|
||||
"form": {
|
||||
"background": {
|
||||
"label": "ପୃଷ୍ଠଭୂମି"
|
||||
},
|
||||
"primary": {
|
||||
"label": "ପ୍ରାଥମିକ"
|
||||
},
|
||||
"text": {
|
||||
"label": "ଟେକ୍ସଟ"
|
||||
}
|
||||
},
|
||||
"heading": "ଥିମ୍"
|
||||
},
|
||||
"typography": {
|
||||
"form": {
|
||||
"font-family": {
|
||||
"label": "ଫଣ୍ଟ ପରିବାର"
|
||||
},
|
||||
"font-size": {
|
||||
"label": "ଫଣ୍ଟ ଆକାର"
|
||||
}
|
||||
},
|
||||
"heading": "ଟାଇପୋଗ୍ରାଫି",
|
||||
"widgets": {
|
||||
"body": {
|
||||
"label": "ଶରୀର"
|
||||
},
|
||||
"headings": {
|
||||
"label": "ଶିରୋନାମା"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
client/public/locales/or/common.json
Normal file
29
client/public/locales/or/common.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"avatar": {
|
||||
"menu": {
|
||||
"greeting": "ନମସ୍କାର",
|
||||
"logout": "ଲଗ ଆଉଟ"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"credit": "<1> ଅମୃତ ପିଲ୍ଲାଇ</1> ଦ୍ୱାରା ଏକ ଉତ୍ସାହ ପ୍ରୋଜେକ୍ଟ ।",
|
||||
"license": "ସମ୍ପ୍ରଦାୟ ଦ୍ୱାରା, ସମ୍ପ୍ରଦାୟ ପାଇଁ ।"
|
||||
},
|
||||
"markdown": {
|
||||
"help-text": "ଏହି ବିଭାଗ <1> ମାର୍କଡାଉନ୍ </1> ଫର୍ମାଟିଂକୁ ସମର୍ଥନ କରେ"
|
||||
},
|
||||
"date": {
|
||||
"present": "ବର୍ତ୍ତମାନ"
|
||||
},
|
||||
"subtitle": "ଏକ ମାଗଣା ଏବଂ ମୁକ୍ତ ଉତ୍ସ ପୁନଃନିର୍ମାଣକାରୀ ।",
|
||||
"title": "ଋଆକ୍ଟିଭ ରେଜ୍ୟୁମ",
|
||||
"toast": {
|
||||
"error": {
|
||||
"upload-file-size": "ଦୟାକରି କେବଳ 2 ମେଗାବାଇଟ୍ ରୁ କମ ଆକାରର ଫାଇଲ୍ ଅପଲୋଡ୍ କରନ୍ତୁ ।",
|
||||
"upload-photo-size": "ଦୟାକରି କେବଳ ୨ ମେଗାବାଇଟ୍ ତଳେ ଫଟୋ ଅପଲୋଡ୍ କରନ୍ତୁ ।"
|
||||
},
|
||||
"success": {
|
||||
"resume-link-copied": "ତୁମର ରିଜ୍ୟୁମର ଏକ ଲିଙ୍କ୍ ତୁମର କ୍ଲିପବୋର୍ଡରେ କପି କରାଯାଇଛି ।"
|
||||
}
|
||||
}
|
||||
}
|
||||
25
client/public/locales/or/dashboard.json
Normal file
25
client/public/locales/or/dashboard.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"create-resume": {
|
||||
"subtitle": "ଆରମ୍ଭରୁ ଆରମ୍ଭ କରନ୍ତୁ",
|
||||
"title": "ନୂତନ ରିଜ୍ୟୁମ୍ ସୃଷ୍ଟି କରନ୍ତୁ"
|
||||
},
|
||||
"import-external": {
|
||||
"subtitle": "LinkedIn, JSON Resume, Reactive Resume",
|
||||
"title": "ବାହ୍ୟ ଉତ୍ସରୁ ଆମଦାନୀ କରନ୍ତୁ"
|
||||
},
|
||||
"resume": {
|
||||
"menu": {
|
||||
"delete": "ବିଲୋପ କରନ୍ତୁ",
|
||||
"duplicate": "ନକଲ",
|
||||
"open": "ଖୋଲନ୍ତୁ",
|
||||
"rename": "ନାମ ବଦଳାନ୍ତୁ",
|
||||
"share-link": "ଲିଙ୍କ୍ ଶେୟର କରନ୍ତୁ",
|
||||
"tooltips": {
|
||||
"delete": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ଏହି ଆଇଟମ୍ ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି? ଏହା ଏକ ଅପରିବର୍ତ୍ତନୀୟ କାର୍ଯ୍ୟ ।",
|
||||
"share-link": "ଏହାକୁ ଅନ୍ୟମାନଙ୍କ ପାଇଁ ଦୃଶ୍ୟମାନ କରିବା ପାଇଁ ଆପଣଙ୍କର ରେଜ୍ୟୁମର ଦୃଶ୍ୟତାକୁ ସର୍ବସାଧାରଣରେ ପରିବର୍ତ୍ତନ କରିବାକୁ ପଡିବ ।"
|
||||
}
|
||||
},
|
||||
"timestamp": "{{timestamp}} ପୂର୍ବରୁ ଶେଷ ଅଦ୍ୟତନ ହୋଇଛି"
|
||||
},
|
||||
"title": "ଡ୍ୟାସବୋର୍ଡ"
|
||||
}
|
||||
41
client/public/locales/or/landing.json
Normal file
41
client/public/locales/or/landing.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"actions": {
|
||||
"app": "ଆପ୍ କୁ ଯାଆନ୍ତୁ",
|
||||
"login": "ଲଗ ଇନ",
|
||||
"logout": "ଲଗ ଆଉଟ",
|
||||
"register": "ପଞ୍ଜୀକରଣ କରନ୍ତୁ"
|
||||
},
|
||||
"features": {
|
||||
"heading": "ବୈଶିଷ୍ଟ୍ୟଗୁଡ଼ିକ",
|
||||
"list": {
|
||||
"ads": "କୌଣସି ବିଜ୍ଞାପନ ନାହିଁ",
|
||||
"export": "ତୁମର ରିଜ୍ୟୁମ୍ JSON କିମ୍ବା PDF ଫର୍ମାଟକୁ ରପ୍ତାନି କରନ୍ତୁ",
|
||||
"free": "ମାଗଣା, ସବୁଦିନ ପାଇଁ",
|
||||
"import": "LinkedIn, JSON Resume ରୁ ତଥ୍ୟ ଆମଦାନୀ କରନ୍ତୁ",
|
||||
"languages": "ଏକାଧିକ ଭାଷାରେ ଉପଲବ୍ଧ",
|
||||
"more": "ଏବଂ ଅଧିକ ରୋମାଞ୍ଚକର ବୈଶିଷ୍ଟ୍ୟଗୁଡିକ, <1>ଏଠାରେ ସମସ୍ତ ବିଷୟରେ ପଢ଼ନ୍ତୁ</1>",
|
||||
"tracking": "କୌଣସି ଉପଭୋକ୍ତା ଟ୍ରାକିଂ ନାହିଁ"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"heading": "ଲିଙ୍କ୍",
|
||||
"links": {
|
||||
"donate": "ଦାନ କରନ୍ତୁ",
|
||||
"github": "ଉତ୍ସ କୋଡ୍",
|
||||
"privacy": "ଗୋପନୀୟତା ନୀତି",
|
||||
"service": "ସେବା ସର୍ତ୍ତାବଳୀ"
|
||||
}
|
||||
},
|
||||
"screenshots": {
|
||||
"heading": "ସ୍କ୍ରିନସଟ୍"
|
||||
},
|
||||
"testimonials": {
|
||||
"heading": "ପ୍ରଶଂସାପତ୍ର",
|
||||
"body": "ଭଲ କି ଖରାପ, ମୁଁ ରିଆକ୍ଟିଭ୍ ରିଜ୍ୟୁମ୍ ଉପରେ ଆପଣଙ୍କ ମତାମତ ଶୁଣିବାକୁ ପସନ୍ଦ କରିବି ଏବଂ ଆପଣଙ୍କ ପାଇଁ ଅଭିଜ୍ଞତା କିପରି ହୋଇଛି । <br/>ସମଗ୍ର ବିଶ୍ୱରେ ଉପଭୋକ୍ତାମାନଙ୍କ ଦ୍ୱାରା ପଠାଯାଇଥିବା କିଛି ବାର୍ତ୍ତା ଏଠାରେ ଅଛି ।",
|
||||
"contact": "ତୁମେ <1>ମୋ ଇମେଲ</1> ମାଧ୍ୟମରେ ମୋ ପାଖରେ ପହଞ୍ଚିପାରିବ । କିମ୍ବା <3> ମୋ ୱେବସାଇଟ୍</3> ର ଯୋଗାଯୋଗ ଫର୍ମ ମାଧ୍ୟମରେ ।"
|
||||
},
|
||||
"summary": {
|
||||
"body": "ରିଆକ୍ଟିଭ୍ ରିଜ୍ୟୁମ୍ ହେଉଛି ଏକ ମାଗଣା ଏବଂ ଓପନ ସୋର୍ସ ରିଜ୍ୟୁମ୍ ବିଲଡର୍ ଯାହା ଆପଣଙ୍କର ରିଜ୍ୟୁମ୍ ସୃଷ୍ଟି କରିବା, ଅପଡେଟ୍ କରିବା ଏବଂ ଅଂଶୀଦାର କରିବାର ସାଧାରଣ କାର୍ଯ୍ୟକୁ ୧, ୨, ୩ ଭଳି ସହଜ କରିବା ପାଇଁ ନିର୍ମିତ, ଏହି ଆପ୍ ସହିତ, ଆପଣ ଏକାଧିକ ରିଜ୍ୟୁମ୍ ସୃଷ୍ଟି କରିପାରିବେ, ନିଯୁକ୍ତିକାରୀ କିମ୍ବା ସାଙ୍ଗମାନଙ୍କ ସହିତ ଅଂଶୀଦାର କରିପାରିବେ । ଆପଣଙ୍କର ତଥ୍ୟର ଅଖଣ୍ଡତା ଏବଂ ଗୋପନୀୟତା ନହରାଇ ଏକ ଅନନ୍ୟ ଲିଙ୍କ୍ ମାଧ୍ୟମରେ, ଏହାକୁ ଏକ PDF ଭାବରେ ମୁଦ୍ରଣ କରନ୍ତୁ, ସମସ୍ତ ମାଗଣାରେ, ବିନା ବିଜ୍ଞାପନ ବା ଉପଭୋକ୍ତା ଟ୍ରାକିଂରେ ।",
|
||||
"heading": "ସାରାଂଶ"
|
||||
}
|
||||
}
|
||||
136
client/public/locales/or/modals.json
Normal file
136
client/public/locales/or/modals.json
Normal file
@ -0,0 +1,136 @@
|
||||
{
|
||||
"auth": {
|
||||
"forgot-password": {
|
||||
"actions": {
|
||||
"send-email": "ପାସୱାର୍ଡ଼ ରିସେଟ ଇମେଲ ପଠାନ୍ତୁ"
|
||||
},
|
||||
"body": "ଆପଣ ପୁନରୁଦ୍ଧାର କରିବାକୁ ଚାହୁଁଥିବା ଖାତା ସହିତ ଜଡିତ ଇମେଲ ଠିକଣା ପ୍ରବେଶ କରନ୍ତୁ ।",
|
||||
"form": {
|
||||
"email": {
|
||||
"label": "ଇମେଲ ଠିକଣା"
|
||||
}
|
||||
},
|
||||
"heading": "ପାସୱାର୍ଡ଼ ଭୁଲି ଯାଇଛନ୍ତି?",
|
||||
"help-text": "ଯଦି ଖାତା ବିଦ୍ୟମାନ ଅଛି, ଆପଣଙ୍କର ପାସୱାର୍ଡ ରିସେଟ୍ କରିବାକୁ ଏକ ଲିଙ୍କ୍ ସହିତ ଏକ ଇମେଲ୍ ପାଇବେ ।"
|
||||
},
|
||||
"login": {
|
||||
"actions": {
|
||||
"login": "ଲଗ ଇନ",
|
||||
"google": "ଗୁଗୁଲ୍ ସହିତ ଲଗ୍ଇନ୍ କରନ୍ତୁ"
|
||||
},
|
||||
"body": "ଲଗ୍ଇନ୍ ଏବଂ ଆକ୍ସେସ୍, ପରିଚାଳନା ଏବଂ ଅଂଶୀଦାର କରିବା ପାଇଁ ଦୟାକରି ଆପଣଙ୍କର ଖାତା ସହିତ ଜଡିତ ଆପଣଙ୍କର ଉପଯୋଗକର୍ତ୍ତା ନାମ ଏବଂ ପାସୱାର୍ଡ ପ୍ରବେଶ କରନ୍ତୁ ।",
|
||||
"form": {
|
||||
"password": {
|
||||
"label": "ପାସ୍ୱାର୍ଡ଼"
|
||||
},
|
||||
"username": {
|
||||
"help-text": "ଆପଣ ଆପଣଙ୍କର ଇମେଲ୍ ଠିକଣା ମଧ୍ୟ ପ୍ରବେଶ କରିପାରିବେ ।",
|
||||
"label": "ଉପଯୋଗକର୍ତ୍ତା ନାମ"
|
||||
}
|
||||
},
|
||||
"heading": "ଆପଣଙ୍କ ଖାତାକୁ ଲଗ୍ଇନ୍ କରନ୍ତୁ ।",
|
||||
"recover-text": "ଯଦି ଆପଣ ଆପଣଙ୍କର ପାସୱାର୍ଡ ଭୁଲି ଯାଇଛନ୍ତି, ଆପଣ ଆପଣଙ୍କର ଖାତାକୁ <1>ପୁନରୁଦ୍ଧାର କରିପାରିବେ </1> ଏଠାରେ ।",
|
||||
"register-text": "ଯଦି ଆପଣଙ୍କର ପାଖରେ ନାହିଁ, ଆପଣ <1> ଏକ ଖାତା ସୃଷ୍ଟି କରିପାରିବେ </1> ଏଠାରେ"
|
||||
},
|
||||
"register": {
|
||||
"actions": {
|
||||
"register": "ପଞ୍ଜୀକରଣ କରନ୍ତୁ",
|
||||
"google": "ଗୁଗୁଲ୍ ସହିତ ପଞ୍ଜୀକରଣ କରନ୍ତୁ"
|
||||
},
|
||||
"body": "ଏକ ଖାତା ସୃଷ୍ଟି କରିବାକୁ ଦୟାକରି ଆପଣଙ୍କର ବ୍ୟକ୍ତିଗତ ସୂଚନା ପ୍ରବେଶ କରନ୍ତୁ ।",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "ପାସୱାର୍ଡ଼ ନିଶ୍ଚିତ କରନ୍ତୁ"
|
||||
},
|
||||
"email": {
|
||||
"label": "ଇମେଲ ଠିକଣା"
|
||||
},
|
||||
"name": {
|
||||
"label": "ପୁରା ନାମ"
|
||||
},
|
||||
"password": {
|
||||
"label": "ପାସ୍ୱାର୍ଡ଼"
|
||||
},
|
||||
"username": {
|
||||
"label": "ଉପଯୋଗକର୍ତ୍ତା ନାମ"
|
||||
}
|
||||
},
|
||||
"heading": "ଏକ ଆକାଉଣ୍ଟ ସୃଷ୍ଟି କରନ୍ତୁ",
|
||||
"loginText": "ଯଦି ଆପଣଙ୍କର ପୂର୍ବରୁ ଏକ ଖାତା ଅଛି, ଆପଣ ଏଠାରେ <1>ଲଗଇନ୍ କରିପାରିବେ</1> ।"
|
||||
},
|
||||
"reset-password": {
|
||||
"actions": {
|
||||
"set-password": "ଏକ ନୂତନ ପାସୱାର୍ଡ୍ ସେଟ୍ କରନ୍ତୁ"
|
||||
},
|
||||
"body": "ଆପଣଙ୍କ ଖାତା ପାଇଁ ଏକ ନୂତନ ପାସୱାର୍ଡ ପ୍ରବେଶ କରନ୍ତୁ ।",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "ପାସୱାର୍ଡ଼ ନିଶ୍ଚିତ କରନ୍ତୁ"
|
||||
},
|
||||
"password": {
|
||||
"label": "ପାସ୍ୱାର୍ଡ଼"
|
||||
}
|
||||
},
|
||||
"heading": "ଆପଣଙ୍କ ପାସୱାର୍ଡ ରିସେଟ୍ କରନ୍ତୁ"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"create-resume": {
|
||||
"actions": {
|
||||
"create-resume": "ନୂତନ ରିଜ୍ୟୁମ୍ ସୃଷ୍ଟି କରନ୍ତୁ"
|
||||
},
|
||||
"body": "ଏହାକୁ ଏକ ନାମ ଦେଇ ଆପଣଙ୍କର ରିଜ୍ୟୁମ୍ ନିର୍ମାଣ ଆରମ୍ଭ କରନ୍ତୁ । ଆପଣ ଯେଉଁ ଭୂମିକା ପାଇଁ ଆବେଦନ କରୁଛନ୍ତି, କିମ୍ବା କେବଳ ଆପଣଙ୍କର ପ୍ରିୟ ସ୍ନାକ୍ସ ବିଷୟରେ ଏହା ସୂଚିତ ହୋଇପାରେ ।",
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "ନାମ"
|
||||
},
|
||||
"public": {
|
||||
"label": "ସର୍ବସାଧାରଣରେ ଉପଲବ୍ଧ କି?"
|
||||
},
|
||||
"slug": {
|
||||
"label": "ସ୍ଲଗ୍"
|
||||
}
|
||||
},
|
||||
"heading": "ନୂତନ ରିଜ୍ୟୁମ୍ ସୃଷ୍ଟି କରନ୍ତୁ"
|
||||
},
|
||||
"import-external": {
|
||||
"heading": "ବାହ୍ୟ ଉତ୍ସରୁ ଆମଦାନୀ କରନ୍ତୁ",
|
||||
"json-resume": {
|
||||
"actions": {
|
||||
"upload-json": "JSON ଅପଲୋଡ୍ କରନ୍ତୁ ।"
|
||||
},
|
||||
"body": "ଯଦି ଆପଣଙ୍କର ଏକ <1> ବୈଧ JSON ରିଜ୍ୟୁମ୍ ଅଛି |</1> ଯିବାକୁ ପ୍ରସ୍ତୁତ, ଆପଣ ଏହାକୁ Reactive Resume ରେ ଆପଣଙ୍କର ବିକାଶକୁ ଫାଷ୍ଟ-ଟ୍ରାକ୍ କରିବାକୁ ବ୍ୟବହାର କରିପାରିବେ । ନିମ୍ନରେ ବଟନ୍ କ୍ଲିକ୍ କରନ୍ତୁ ଏବଂ ଆରମ୍ଭ କରିବାକୁ ଏକ ବୈଧ JSON ଫାଇଲ୍ ଅପଲୋଡ୍ କରନ୍ତୁ ।",
|
||||
"heading": "JSON Resume ରୁ ଆମଦାନୀ କରନ୍ତୁ"
|
||||
},
|
||||
"linkedin": {
|
||||
"actions": {
|
||||
"upload-archive": "ZIP ଅଭିଲେଖାଗାର ଅପଲୋଡ୍ କରନ୍ତୁ ।"
|
||||
},
|
||||
"body": "LinkedInରୁ ଆପଣଙ୍କର ତଥ୍ୟ ରପ୍ତାନି କରି ଏହାକୁ Reactive Resume ରେ ଅଟୋ-ଫିଲ୍ ଫିଲ୍ଡରେ ବ୍ୟବହାର କରି ଆପଣ ସମୟ ସଞ୍ଚୟ କରିପାରିବେ । <1> ଡାଟା ଗୋପନୀୟତାକୁ ଯାଆନ୍ତୁ</1> LinkedIn ରେ ବିଭାଗ ଏବଂ ଆପଣଙ୍କର ତଥ୍ୟର ଏକ ଅଭିଲେଖାଗାର ପାଇଁ ଅନୁରୋଧ । ଏହା ଉପଲବ୍ଧ ହେବା ପରେ, ନିମ୍ନରେ ZIP ଫାଇଲ୍ ଅପଲୋଡ୍ କରନ୍ତୁ ।",
|
||||
"heading": "LinkedIn ରୁ ଆମଦାନୀ କରନ୍ତୁ ।"
|
||||
},
|
||||
"reactive-resume": {
|
||||
"actions": {
|
||||
"upload-json": "JSON ଅପଲୋଡ୍ କରନ୍ତୁ ।",
|
||||
"upload-json-v2": "V2 ରୁ JSON ଅପଲୋଡ୍ କରନ୍ତୁ ।"
|
||||
},
|
||||
"body": "ଯଦି ଆପଣଙ୍କର ଏକ JSON ଅଛି ଯାହା Reactive Resume ର ସାମ୍ପ୍ରତିକ ସଂସ୍କରଣ ସହିତ ରପ୍ତାନି ହୋଇଛି, ଆପଣ ପୁନର୍ବାର ଏକ ସମ୍ପାଦିତ ସଂସ୍କରଣ ପାଇବାକୁ ଏହାକୁ ଏଠାରେ ଆମଦାନି କରିପାରିବେ ।",
|
||||
"heading": "Reactive Resume ରୁ ଆମଦାନୀ କରନ୍ତୁ"
|
||||
}
|
||||
},
|
||||
"rename-resume": {
|
||||
"actions": {
|
||||
"rename-resume": "ରେଜ୍ୟୁମ ନାମ ବଦଳାନ୍ତୁ"
|
||||
},
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "ନାମ"
|
||||
},
|
||||
"slug": {
|
||||
"label": "ସ୍ଲଗ୍"
|
||||
}
|
||||
},
|
||||
"heading": "ଆପଣଙ୍କର ରେଜ୍ୟୁମ ନାମ ବଦଳାନ୍ତୁ"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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",
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
{
|
||||
"actions": {
|
||||
"app": "Ir para o App",
|
||||
"app": "Rodar aplicativo",
|
||||
"login": "Entrar",
|
||||
"logout": "Sair",
|
||||
"register": "Registrar-se"
|
||||
"logout": "Encerrar",
|
||||
"register": "Inscrição"
|
||||
},
|
||||
"features": {
|
||||
"heading": "Características",
|
||||
@ -12,30 +12,30 @@
|
||||
"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": "Acessível em vários idiomas",
|
||||
"more": "E muito mais recursos interessantes, <1>leia tudo sobre isso aqui</1>",
|
||||
"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": "Doar",
|
||||
"donate": "Fazer doação",
|
||||
"github": "Código Fonte",
|
||||
"privacy": "Política de privacidade",
|
||||
"service": "Termos de serviço"
|
||||
}
|
||||
},
|
||||
"screenshots": {
|
||||
"heading": "Capturas de tela"
|
||||
"heading": "Imagens"
|
||||
},
|
||||
"testimonials": {
|
||||
"heading": "Depoimentos",
|
||||
"body": "Boa ou ruim, eu adoraria saber sua opinião sobre o Reactive Resume e como tem sido a experiência para você.<br/>Aqui estão algumas das mensagens enviadas por usuários em todo o mundo.",
|
||||
"contact": "Você pode entrar em contato comigo pelo <1>meu e-mail</1> ou por meio do formulário de contato no <3>meu site</3>."
|
||||
"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 construtor de currículos gratuito e de código aberto criado para tornar as tarefas mundanas de criar, atualizar e compartilhar seu currículo tão fáceis quanto 1, 2, 3. Com este aplicativo, você pode criar vários currículos, compartilhá-los com recrutadores ou amigos através de um link exclusivo e imprimi-los como PDF, tudo de graça, sem anúncios, sem rastreamento, sem perder a integridade e privacidade dos seus dados.",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
358
client/public/locales/sv/builder.json
Normal file
358
client/public/locales/sv/builder.json
Normal file
@ -0,0 +1,358 @@
|
||||
{
|
||||
"common": {
|
||||
"actions": {
|
||||
"add": "Lägg till {{token}}",
|
||||
"delete": "Ta bort {{token}}",
|
||||
"edit": "Redigera {{token}}"
|
||||
},
|
||||
"columns": {
|
||||
"heading": "Kolumner",
|
||||
"tooltip": "Ändra antalet kolumner"
|
||||
},
|
||||
"form": {
|
||||
"date": {
|
||||
"label": "Datum"
|
||||
},
|
||||
"description": {
|
||||
"label": "Beskrivning"
|
||||
},
|
||||
"email": {
|
||||
"label": "E-postadress"
|
||||
},
|
||||
"end-date": {
|
||||
"help-text": "Lämna fältet blankt, om fortfarande aktuellt",
|
||||
"label": "Slutdatum"
|
||||
},
|
||||
"keywords": {
|
||||
"label": "Nyckelord"
|
||||
},
|
||||
"level": {
|
||||
"label": "Nivå"
|
||||
},
|
||||
"levelNum": {
|
||||
"label": "Nivå (siffror)"
|
||||
},
|
||||
"name": {
|
||||
"label": "Namn"
|
||||
},
|
||||
"phone": {
|
||||
"label": "Telefonnummer"
|
||||
},
|
||||
"position": {
|
||||
"label": "Position"
|
||||
},
|
||||
"start-date": {
|
||||
"label": "Startdatum"
|
||||
},
|
||||
"subtitle": {
|
||||
"label": "Undertitel"
|
||||
},
|
||||
"summary": {
|
||||
"label": "Sammanfattning"
|
||||
},
|
||||
"title": {
|
||||
"label": "Titel"
|
||||
},
|
||||
"url": {
|
||||
"label": "Webbplats"
|
||||
}
|
||||
},
|
||||
"glossary": {
|
||||
"page": "Sida"
|
||||
},
|
||||
"list": {
|
||||
"actions": {
|
||||
"delete": "Ta bort",
|
||||
"duplicate": "Duplicera",
|
||||
"edit": "Redigera"
|
||||
},
|
||||
"empty-text": "Denna lista är tom."
|
||||
},
|
||||
"tooltip": {
|
||||
"delete-item": "Är du säker på att du vill ta bort det här objektet? Detta är en oåterkallelig handling.",
|
||||
"delete-section": "Ta bort avsnitt",
|
||||
"rename-section": "Döp om avsnitt",
|
||||
"toggle-visibility": "Visa/dölj"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"tooltip": {
|
||||
"center-artboard": "Centrera Artboard",
|
||||
"copy-link": "Kopiera länken till CV:et",
|
||||
"export-pdf": "Exportera som PDF",
|
||||
"toggle-orientation": "Byt sidans orientering",
|
||||
"toggle-page-break-line": "Visa/dölj Sidbrytningslinjer",
|
||||
"toggle-sidebars": "Visa/dölj Sidpanelen",
|
||||
"zoom-in": "Zooma in",
|
||||
"zoom-out": "Zooma Ut"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"menu": {
|
||||
"delete": "Ta bort",
|
||||
"duplicate": "Duplicera",
|
||||
"rename": "Ändra Namn",
|
||||
"share-link": "Dela länk",
|
||||
"tooltips": {
|
||||
"delete": "Är du säker du vill ta bort detta CV? Detta går ej att ångra.",
|
||||
"share-link": "Du måste ändra synligheten av ditt CV till offentligt för att göra det synligt för andra."
|
||||
}
|
||||
}
|
||||
},
|
||||
"leftSidebar": {
|
||||
"sections": {
|
||||
"awards": {
|
||||
"form": {
|
||||
"awarder": {
|
||||
"label": "Utmärkelser"
|
||||
}
|
||||
}
|
||||
},
|
||||
"basics": {
|
||||
"actions": {
|
||||
"photo-filters": "Fotofilter"
|
||||
},
|
||||
"heading": "Grunder",
|
||||
"headline": {
|
||||
"label": "Rubrik"
|
||||
},
|
||||
"name": {
|
||||
"label": "Fullständigt namn"
|
||||
},
|
||||
"photo-filters": {
|
||||
"effects": {
|
||||
"border": {
|
||||
"label": "Kant"
|
||||
},
|
||||
"grayscale": {
|
||||
"label": "Gråskala"
|
||||
},
|
||||
"heading": "Effekter"
|
||||
},
|
||||
"shape": {
|
||||
"heading": "Form"
|
||||
},
|
||||
"size": {
|
||||
"heading": "Storlek (i pixlar)"
|
||||
}
|
||||
},
|
||||
"photo-upload": {
|
||||
"tooltip": {
|
||||
"remove": "Ta bort bild",
|
||||
"upload": "Ladda upp bild"
|
||||
}
|
||||
}
|
||||
},
|
||||
"certifications": {
|
||||
"form": {
|
||||
"issuer": {
|
||||
"label": "Utgivare"
|
||||
}
|
||||
}
|
||||
},
|
||||
"education": {
|
||||
"form": {
|
||||
"area-study": {
|
||||
"label": "Studieinriktning"
|
||||
},
|
||||
"courses": {
|
||||
"label": "Kurser"
|
||||
},
|
||||
"degree": {
|
||||
"label": "Examen"
|
||||
},
|
||||
"grade": {
|
||||
"label": "Betyg"
|
||||
},
|
||||
"institution": {
|
||||
"label": "Institution"
|
||||
}
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"address": {
|
||||
"label": "Adress"
|
||||
},
|
||||
"city": {
|
||||
"label": "Ort"
|
||||
},
|
||||
"country": {
|
||||
"label": "Land"
|
||||
},
|
||||
"heading": "Plats",
|
||||
"postal-code": {
|
||||
"label": "Postnummer"
|
||||
},
|
||||
"region": {
|
||||
"label": "Län"
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"form": {
|
||||
"network": {
|
||||
"label": "Nätverk"
|
||||
},
|
||||
"username": {
|
||||
"label": "Användarnamn"
|
||||
}
|
||||
},
|
||||
"heading": "Profiler",
|
||||
"heading_one": "Profil"
|
||||
},
|
||||
"publications": {
|
||||
"form": {
|
||||
"publisher": {
|
||||
"label": "Utgivare"
|
||||
}
|
||||
}
|
||||
},
|
||||
"references": {
|
||||
"form": {
|
||||
"relationship": {
|
||||
"label": "Relation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"heading": "Sektion"
|
||||
},
|
||||
"volunteer": {
|
||||
"form": {
|
||||
"organization": {
|
||||
"label": "Organisation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rightSidebar": {
|
||||
"sections": {
|
||||
"css": {
|
||||
"heading": "Anpassad CSS"
|
||||
},
|
||||
"export": {
|
||||
"heading": "Exportera",
|
||||
"json": {
|
||||
"primary": "JSON",
|
||||
"secondary": "Ladda ner en JSON-version av ditt CV som kan importeras tillbaka till Reactive Resume."
|
||||
},
|
||||
"pdf": {
|
||||
"loading": {
|
||||
"primary": "Genererar PDF",
|
||||
"secondary": "Vänligen vänta medans din PDF genereras, detta kan ta upp till 15 sekunder."
|
||||
},
|
||||
"normal": {
|
||||
"primary": "PDF",
|
||||
"secondary": "Ladda ner en PDF av ditt CV som du kan skriva ut och skicka till ditt drömjobb. Den här filen kan inte importeras tillbaka för ytterligare redigering."
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"heading": "Layout",
|
||||
"tooltip": {
|
||||
"reset-layout": "Återställ layout"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"bugs-features": {
|
||||
"body": "Något som hindrar dig från att göra ett CV? Eller har du en fantastisk idé att lägga till? Starta en issue på GitHub för att komma igång.",
|
||||
"button": "GitHub Issues",
|
||||
"heading": "Buggar? Funktionsförslag?"
|
||||
},
|
||||
"donate": {
|
||||
"body": "Om du gillade att använda Reactive Resume, överväg att donera så mycket som möjligt för att hålla appen igång utan annonser och gratis för alltid.",
|
||||
"button": "Köp mig en kaffe",
|
||||
"heading": "Donera till Reactive Resume"
|
||||
},
|
||||
"github": "Källkod",
|
||||
"heading": "Länkar"
|
||||
},
|
||||
"settings": {
|
||||
"global": {
|
||||
"date": {
|
||||
"primary": "Datum",
|
||||
"secondary": "Datumformat som ska användas i hela appen"
|
||||
},
|
||||
"heading": "Globalt",
|
||||
"language": {
|
||||
"primary": "Språk",
|
||||
"secondary": "Visa det språk som ska användas i hela appen"
|
||||
},
|
||||
"theme": {
|
||||
"primary": "Tema"
|
||||
}
|
||||
},
|
||||
"heading": "Inställningar",
|
||||
"page": {
|
||||
"break-line": {
|
||||
"primary": "Radbrytning",
|
||||
"secondary": "Visa en linje på alla sidor för att markera höjden på en A4-sida"
|
||||
},
|
||||
"heading": "Sida",
|
||||
"orientation": {
|
||||
"disabled": "Har ingen effekt när det bara finns en sida",
|
||||
"primary": "Orientering",
|
||||
"secondary": "Om sidor ska visas horisontellt eller vertikalt"
|
||||
}
|
||||
},
|
||||
"resume": {
|
||||
"heading": "CV",
|
||||
"reset": {
|
||||
"primary": "Återställ allt",
|
||||
"secondary": "Har du gjort för många misstag? Klicka här för att återställa alla ändringar och börja om från början. Var försiktig, den här åtgärden kan inte återställas."
|
||||
},
|
||||
"sample": {
|
||||
"primary": "Läs in exempeldata",
|
||||
"secondary": "Vet du inte var du ska börja? Klicka här för att ladda några exempel för att se hur ett komplett CV ser ut."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sharing": {
|
||||
"heading": "Delning",
|
||||
"short-url": {
|
||||
"label": "Föredra kort URL"
|
||||
},
|
||||
"visibility": {
|
||||
"subtitle": "Tillåt alla med en länk att se ditt CV",
|
||||
"title": "Publik"
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"heading": "Mallar"
|
||||
},
|
||||
"theme": {
|
||||
"form": {
|
||||
"background": {
|
||||
"label": "Bakgrund"
|
||||
},
|
||||
"primary": {
|
||||
"label": "Primär"
|
||||
},
|
||||
"text": {
|
||||
"label": "Text"
|
||||
}
|
||||
},
|
||||
"heading": "Tema"
|
||||
},
|
||||
"typography": {
|
||||
"form": {
|
||||
"font-family": {
|
||||
"label": "Typsnittsfamilj"
|
||||
},
|
||||
"font-size": {
|
||||
"label": "Textstorlek"
|
||||
}
|
||||
},
|
||||
"heading": "Typografi",
|
||||
"widgets": {
|
||||
"body": {
|
||||
"label": "Innehåll"
|
||||
},
|
||||
"headings": {
|
||||
"label": "Rubriker"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
client/public/locales/sv/common.json
Normal file
29
client/public/locales/sv/common.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"avatar": {
|
||||
"menu": {
|
||||
"greeting": "Hej",
|
||||
"logout": "Logga ut"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"credit": "Ett passionsprojekt av <1>Amruth Pillai</1>",
|
||||
"license": "Av communityn, för communityn."
|
||||
},
|
||||
"markdown": {
|
||||
"help-text": "Det här avsnittet stöder <1>markdown</1> formatering."
|
||||
},
|
||||
"date": {
|
||||
"present": "Nuvarande"
|
||||
},
|
||||
"subtitle": "En CV byggare som är kostnadsfri och under öppen källkod.",
|
||||
"title": "Reactive Resume",
|
||||
"toast": {
|
||||
"error": {
|
||||
"upload-file-size": "Vänligen ladda endast upp filer under 2 megabyte.",
|
||||
"upload-photo-size": "Vänligen ladda endast upp bilder under 2 megabyte, helst kvadratiska."
|
||||
},
|
||||
"success": {
|
||||
"resume-link-copied": "En länk till ditt CV har kopierats till ditt urklipp."
|
||||
}
|
||||
}
|
||||
}
|
||||
25
client/public/locales/sv/dashboard.json
Normal file
25
client/public/locales/sv/dashboard.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"create-resume": {
|
||||
"subtitle": "Börja från grunden",
|
||||
"title": "Skapa nytt CV"
|
||||
},
|
||||
"import-external": {
|
||||
"subtitle": "LinkedIn, JSON CV, Reactive Resume",
|
||||
"title": "Importera från externa källor"
|
||||
},
|
||||
"resume": {
|
||||
"menu": {
|
||||
"delete": "Ta bort",
|
||||
"duplicate": "Duplicera",
|
||||
"open": "Öppna",
|
||||
"rename": "Ändra Namn",
|
||||
"share-link": "Dela länk",
|
||||
"tooltips": {
|
||||
"delete": "Är du säker du vill ta bort detta CV? Detta går ej att ångra.",
|
||||
"share-link": "Du måste ändra synligheten av ditt CV till offentligt för att göra det synligt för andra."
|
||||
}
|
||||
},
|
||||
"timestamp": "Senast uppdaterad {{timestamp}}"
|
||||
},
|
||||
"title": "Dashboard"
|
||||
}
|
||||
41
client/public/locales/sv/landing.json
Normal file
41
client/public/locales/sv/landing.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"actions": {
|
||||
"app": "Till appen",
|
||||
"login": "Logga in",
|
||||
"logout": "Logga ut",
|
||||
"register": "Registrera"
|
||||
},
|
||||
"features": {
|
||||
"heading": "Funktioner",
|
||||
"list": {
|
||||
"ads": "Ingen reklam",
|
||||
"export": "Exportera ditt CV till JSON- eller PDF-format",
|
||||
"free": "Gratis för alltid",
|
||||
"import": "Importera data från LinkedIn, JSON CV",
|
||||
"languages": "Tillgänglig på flera språk",
|
||||
"more": "Och många fler spännande funktioner, <1>läs allt om det här</1>",
|
||||
"tracking": "Ingen spårning av användare"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"heading": "Länkar",
|
||||
"links": {
|
||||
"donate": "Donera",
|
||||
"github": "Källkod",
|
||||
"privacy": "Sekretesspolicy",
|
||||
"service": "Användarvillkor"
|
||||
}
|
||||
},
|
||||
"screenshots": {
|
||||
"heading": "Skärmdumpar"
|
||||
},
|
||||
"testimonials": {
|
||||
"heading": "Rekommendationer",
|
||||
"body": "Bra eller dåligt, jag skulle älska att höra din åsikt om Reactive Resume och hur upplevelsen har varit för dig.<br/>Här är några av de meddelanden som skickas in av användare över hela världen.",
|
||||
"contact": "Du kan nå mig via <1>min e-post</1> eller genom kontaktformuläret på <3>min hemsida</3> ."
|
||||
},
|
||||
"summary": {
|
||||
"body": "Reactive Resume är en gratis och öppen källkodsbyggare för CV som är gjord för att göra de vardagliga uppgifterna som att skapa, uppdatera och dela ditt CV så enkelt som 1, 2, 3. Med den här appen kan du skapa flera CV, dela dem med rekryterare eller vänner genom en unik länk och skriva ut den som en PDF, helt gratis, inga annonser, ingen spårning och utan att förlora integriteten för dina data.",
|
||||
"heading": "Sammanfattning"
|
||||
}
|
||||
}
|
||||
136
client/public/locales/sv/modals.json
Normal file
136
client/public/locales/sv/modals.json
Normal file
@ -0,0 +1,136 @@
|
||||
{
|
||||
"auth": {
|
||||
"forgot-password": {
|
||||
"actions": {
|
||||
"send-email": "Skicka e-post för återställning av lösenord"
|
||||
},
|
||||
"body": "Ange bara e-postadressen som är kopplad till kontot du vill återställa.",
|
||||
"form": {
|
||||
"email": {
|
||||
"label": "E-postadress"
|
||||
}
|
||||
},
|
||||
"heading": "Glömt ditt lösenord?",
|
||||
"help-text": "Om kontot finns får du ett e-postmeddelande med en länk för att återställa ditt lösenord."
|
||||
},
|
||||
"login": {
|
||||
"actions": {
|
||||
"login": "Logga in",
|
||||
"google": "Logga in med Google"
|
||||
},
|
||||
"body": "Vänligen ange ditt användarnamn och lösenord som är kopplat till ditt konto för att logga in och komma åt, hantera och dela dina CV.",
|
||||
"form": {
|
||||
"password": {
|
||||
"label": "Lösenord"
|
||||
},
|
||||
"username": {
|
||||
"help-text": "Du kan också ange din e-postadress",
|
||||
"label": "Användarnamn"
|
||||
}
|
||||
},
|
||||
"heading": "Logga in på ditt konto",
|
||||
"recover-text": "Om du har glömt ditt lösenord kan du <1>återställa ditt konto</1> här.",
|
||||
"register-text": "Om du inte har ett kan du <1>skapa ett konto</1> här."
|
||||
},
|
||||
"register": {
|
||||
"actions": {
|
||||
"register": "Registrera",
|
||||
"google": "Registrera dig med Google"
|
||||
},
|
||||
"body": "Ange dina personliga uppgifter för att skapa ett konto.",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "Bekräfta lösenord"
|
||||
},
|
||||
"email": {
|
||||
"label": "E-postadress"
|
||||
},
|
||||
"name": {
|
||||
"label": "Fullständigt namn"
|
||||
},
|
||||
"password": {
|
||||
"label": "Lösenord"
|
||||
},
|
||||
"username": {
|
||||
"label": "Användarnamn"
|
||||
}
|
||||
},
|
||||
"heading": "Skapa ett konto",
|
||||
"loginText": "Om du redan har ett konto kan du <1>logga in här</1> ."
|
||||
},
|
||||
"reset-password": {
|
||||
"actions": {
|
||||
"set-password": "Ange nytt lösenord"
|
||||
},
|
||||
"body": "Ange ett nytt lösenord för ditt konto.",
|
||||
"form": {
|
||||
"confirm-password": {
|
||||
"label": "Bekräfta lösenord"
|
||||
},
|
||||
"password": {
|
||||
"label": "Lösenord"
|
||||
}
|
||||
},
|
||||
"heading": "Återställ ditt lösenord"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"create-resume": {
|
||||
"actions": {
|
||||
"create-resume": "Skapa CV"
|
||||
},
|
||||
"body": "Börja bygga ditt CV genom att ge det ett namn. Det kan vara med hänvisning till rollen du söker, eller bara ditt favoritmellanmål.",
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "Namn"
|
||||
},
|
||||
"public": {
|
||||
"label": "Är allmänt tillgängligt?"
|
||||
},
|
||||
"slug": {
|
||||
"label": "Permalänk"
|
||||
}
|
||||
},
|
||||
"heading": "Skapa ett nytt CV"
|
||||
},
|
||||
"import-external": {
|
||||
"heading": "Importera från externa källor",
|
||||
"json-resume": {
|
||||
"actions": {
|
||||
"upload-json": "Ladda upp JSON"
|
||||
},
|
||||
"body": "Om du har ett <1>validerat JSON CV</1> redo att användas, kan du använda det för att snabba upp din utveckling på Reactive Resume. Klicka på knappen nedan och ladda upp en giltig JSON-fil för att börja.",
|
||||
"heading": "Importera från JSON CV"
|
||||
},
|
||||
"linkedin": {
|
||||
"actions": {
|
||||
"upload-archive": "Ladda upp ZIP-arkiv"
|
||||
},
|
||||
"body": "Du kan spara tid genom att exportera dina uppgifter från LinkedIn och använda dem för att automatiskt fylla i fälten i Reactive Resume. Gå till avsnittet <1>Dataintegritet</1> på LinkedIn och begär ett arkiv av dina uppgifter. När det är tillgängligt laddar du upp ZIP-filen nedan.",
|
||||
"heading": "Importera från LinkedIn"
|
||||
},
|
||||
"reactive-resume": {
|
||||
"actions": {
|
||||
"upload-json": "Ladda upp JSON",
|
||||
"upload-json-v2": "Ladda upp JSON från v2"
|
||||
},
|
||||
"body": "Om du har en JSON som exporterades med den aktuella versionen av Reactive Resume, kan du importera den tillbaka hit för att få en redigerbar version igen.",
|
||||
"heading": "Importera från Reactive Resume"
|
||||
}
|
||||
},
|
||||
"rename-resume": {
|
||||
"actions": {
|
||||
"rename-resume": "Byt namn på CV"
|
||||
},
|
||||
"form": {
|
||||
"name": {
|
||||
"label": "Namn"
|
||||
},
|
||||
"slug": {
|
||||
"label": "Permalänk"
|
||||
}
|
||||
},
|
||||
"heading": "Byt namn på ditt CV"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
|
||||
<url><loc>https://rxresu.me</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/meta/privacy</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/meta/service</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/bn/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/de/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/es/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/fr/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/hi/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/it/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/kn/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ta/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/bn</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/de</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/es</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/fr</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/hi</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/it</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/kn</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ta</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-03-14T08:00:09.072Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/meta/privacy</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/meta/service</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ar/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/bn/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/da/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/de/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/es/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/fr/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/hi/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/it/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/kn/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ml/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/nl/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/pl/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/pt/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ru/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ta/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/tr/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/vi/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/zh/dashboard</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ar</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/bn</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/da</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/de</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/es</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/fr</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/hi</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/it</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/kn</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ml</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/nl</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/pl</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/pt</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ru</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/ta</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/tr</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/vi</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
<url><loc>https://rxresu.me/zh</loc><changefreq>monthly</changefreq><priority>0.7</priority><lastmod>2022-04-30T10:56:16.825Z</lastmod></url>
|
||||
</urlset>
|
||||
@ -13,7 +13,7 @@ export type LoginParams = {
|
||||
};
|
||||
|
||||
export type LoginWithGoogleParams = {
|
||||
accessToken: string;
|
||||
credential: string;
|
||||
};
|
||||
|
||||
export type RegisterParams = {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import _axios, { AxiosError } from 'axios';
|
||||
import _axios from 'axios';
|
||||
import Router from 'next/router';
|
||||
|
||||
import { logout } from '@/store/auth/authSlice';
|
||||
@ -27,7 +27,7 @@ axios.interceptors.request.use((config) => {
|
||||
|
||||
axios.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error: AxiosError) => {
|
||||
(error) => {
|
||||
const { response } = error;
|
||||
|
||||
if (response) {
|
||||
|
||||
@ -5,7 +5,7 @@ import { useMemo } from 'react';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
|
||||
const Heading: React.FC = ({ children }) => {
|
||||
const Heading: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
const darkerPrimary = useMemo(() => darken(theme.primary, 0.2), [theme.primary]);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { Cake, Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { Theme } from '@reactive-resume/schema';
|
||||
import clsx from 'clsx';
|
||||
import get from 'lodash/get';
|
||||
@ -9,12 +9,14 @@ import { useMemo } from 'react';
|
||||
import Markdown from '@/components/shared/Markdown';
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import DataDisplay from '@/templates/shared/DataDisplay';
|
||||
import { formatDateString } from '@/utils/date';
|
||||
import getProfileIcon from '@/utils/getProfileIcon';
|
||||
import { getContrastColor } from '@/utils/styles';
|
||||
import { addHttp, formatLocation, getPhotoClassNames } from '@/utils/template';
|
||||
|
||||
export const MastheadSidebar: React.FC = () => {
|
||||
const { name, headline, photo, email, phone, website, location, profiles } = useAppSelector(
|
||||
const dateFormat: string = useAppSelector((state) => get(state.resume, 'metadata.date.format'));
|
||||
const { name, headline, photo, email, phone, birthdate, website, location, profiles } = useAppSelector(
|
||||
(state) => state.resume.basics
|
||||
);
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
@ -43,6 +45,10 @@ export const MastheadSidebar: React.FC = () => {
|
||||
{formatLocation(location)}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Cake />} className="!gap-2 text-xs">
|
||||
{formatDateString(birthdate, dateFormat)}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Email />} className="!gap-2 text-xs" link={`mailto:${email}`}>
|
||||
{email}
|
||||
</DataDisplay>
|
||||
|
||||
@ -3,7 +3,7 @@ import get from 'lodash/get';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
|
||||
const Heading: React.FC = ({ children }) => {
|
||||
const Heading: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
|
||||
return (
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { Cake, Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { alpha } from '@mui/material';
|
||||
import { Theme } from '@reactive-resume/schema';
|
||||
import clsx from 'clsx';
|
||||
@ -10,12 +10,14 @@ import { useMemo } from 'react';
|
||||
import Markdown from '@/components/shared/Markdown';
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import DataDisplay from '@/templates/shared/DataDisplay';
|
||||
import { formatDateString } from '@/utils/date';
|
||||
import getProfileIcon from '@/utils/getProfileIcon';
|
||||
import { getContrastColor } from '@/utils/styles';
|
||||
import { addHttp, formatLocation, getPhotoClassNames } from '@/utils/template';
|
||||
|
||||
export const MastheadSidebar: React.FC = () => {
|
||||
const { name, headline, photo, email, phone, website, location, profiles } = useAppSelector(
|
||||
const dateFormat: string = useAppSelector((state) => get(state.resume, 'metadata.date.format'));
|
||||
const { name, headline, photo, email, phone, birthdate, website, location, profiles } = useAppSelector(
|
||||
(state) => state.resume.basics
|
||||
);
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
@ -44,6 +46,10 @@ export const MastheadSidebar: React.FC = () => {
|
||||
{formatLocation(location)}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Cake />} className="!gap-2 text-xs">
|
||||
{formatDateString(birthdate, dateFormat)}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Email />} className="!gap-2 text-xs" link={`mailto:${email}`}>
|
||||
{email}
|
||||
</DataDisplay>
|
||||
|
||||
@ -3,7 +3,7 @@ import get from 'lodash/get';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
|
||||
const Heading: React.FC = ({ children }) => {
|
||||
const Heading: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {}));
|
||||
|
||||
return (
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
import { Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { Cake, Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import get from 'lodash/get';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import Markdown from '@/components/shared/Markdown';
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import DataDisplay from '@/templates/shared/DataDisplay';
|
||||
import { formatDateString } from '@/utils/date';
|
||||
import getProfileIcon from '@/utils/getProfileIcon';
|
||||
import { addHttp, formatLocation, getPhotoClassNames } from '@/utils/template';
|
||||
|
||||
export const MastheadSidebar: React.FC = () => {
|
||||
const dateFormat: string = useAppSelector((state) => get(state.resume, 'metadata.date.format'));
|
||||
const primaryColor: string = useAppSelector((state) => get(state.resume, 'metadata.theme.primary'));
|
||||
const { name, headline, photo, email, phone, website, location, profiles } = useAppSelector(
|
||||
const { name, headline, photo, email, phone, birthdate, website, location, profiles } = useAppSelector(
|
||||
(state) => state.resume.basics
|
||||
);
|
||||
|
||||
@ -36,6 +38,10 @@ export const MastheadSidebar: React.FC = () => {
|
||||
{formatLocation(location)}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Cake />} className="text-xs">
|
||||
{formatDateString(birthdate, dateFormat)}
|
||||
</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Email />} className="text-xs" link={`mailto:${email}`}>
|
||||
{email}
|
||||
</DataDisplay>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
const Heading: React.FC = ({ children }) => {
|
||||
const Heading: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||
return <h3 className="my-2 inline-block border-b px-5 pb-2">{children}</h3>;
|
||||
};
|
||||
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
import { Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import { Cake, Email, Phone, Public, Room } from '@mui/icons-material';
|
||||
import get from 'lodash/get';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import React from 'react';
|
||||
|
||||
import { useAppSelector } from '@/store/hooks';
|
||||
import DataDisplay from '@/templates/shared/DataDisplay';
|
||||
import { formatDateString } from '@/utils/date';
|
||||
import getProfileIcon from '@/utils/getProfileIcon';
|
||||
import { addHttp, formatLocation, getPhotoClassNames } from '@/utils/template';
|
||||
|
||||
const Masthead = () => {
|
||||
const { name, photo, email, phone, website, headline, location, profiles } = useAppSelector(
|
||||
const dateFormat: string = useAppSelector((state) => get(state.resume, 'metadata.date.format'));
|
||||
const { name, photo, email, phone, website, birthdate, headline, location, profiles } = useAppSelector(
|
||||
(state) => state.resume.basics
|
||||
);
|
||||
|
||||
@ -32,6 +35,8 @@ const Masthead = () => {
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap justify-center gap-3">
|
||||
<DataDisplay icon={<Cake />}>{formatDateString(birthdate, dateFormat)}</DataDisplay>
|
||||
|
||||
<DataDisplay icon={<Email />} link={`mailto:${email}`}>
|
||||
{email}
|
||||
</DataDisplay>
|
||||
|
||||
7
client/templates/Leafish/Leafish.module.scss
Normal file
7
client/templates/Leafish/Leafish.module.scss
Normal file
@ -0,0 +1,7 @@
|
||||
.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
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
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<React.PropsWithChildren<unknown>> = ({ 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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user