🚀 release v3.0.0
This commit is contained in:
parent
00505a9e5d
commit
9c1380f401
|
@ -1,8 +0,0 @@
|
||||||
# Changesets
|
|
||||||
|
|
||||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
||||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
||||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
||||||
|
|
||||||
We have a quick list of common questions to get you started engaging with this project in
|
|
||||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://unpkg.com/@changesets/config@1.7.0/schema.json",
|
|
||||||
"changelog": "@changesets/cli/changelog",
|
|
||||||
"commit": false,
|
|
||||||
"fixed": [],
|
|
||||||
"linked": [],
|
|
||||||
"ignore": [],
|
|
||||||
"baseBranch": "v3",
|
|
||||||
"access": "restricted",
|
|
||||||
"updateInternalDependencies": "patch"
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
dist
|
dist
|
||||||
|
.next
|
||||||
Dockerfile
|
Dockerfile
|
||||||
node_modules
|
node_modules
|
||||||
.dockerignore
|
.dockerignore
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
# Editor configuration, see http://editorconfig.org
|
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.md]
|
|
||||||
max_line_length = off
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# Reactive Resume
|
# Reactive Resume
|
||||||
TZ=UTC
|
TZ=UTC
|
||||||
NODE_ENV=development
|
|
||||||
SECRET_KEY=change-me
|
SECRET_KEY=change-me
|
||||||
|
|
||||||
# URLs
|
# URLs
|
||||||
|
|
|
@ -1,58 +1,39 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"ignorePatterns": ["**/*"],
|
"parser": "@typescript-eslint/parser",
|
||||||
"plugins": ["@nrwl/nx"],
|
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
|
||||||
"extends": ["prettier"],
|
"plugins": ["@typescript-eslint/eslint-plugin", "simple-import-sort", "unused-imports"],
|
||||||
|
"rules": {
|
||||||
|
// TypeScript ESLint
|
||||||
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/interface-name-prefix": "off",
|
||||||
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
|
|
||||||
|
// Simple Import Sort
|
||||||
|
"simple-import-sort/imports": "error",
|
||||||
|
"simple-import-sort/exports": "error",
|
||||||
|
|
||||||
|
// Unused Imports
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"unused-imports/no-unused-imports": "error",
|
||||||
|
"unused-imports/no-unused-vars": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
"vars": "all",
|
||||||
|
"varsIgnorePattern": "^_",
|
||||||
|
"args": "none",
|
||||||
|
"argsIgnorePattern": "^_"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.js"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"@nrwl/nx/enforce-module-boundaries": [
|
"@typescript-eslint/no-var-requires": "off"
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"enforceBuildableLibDependency": true,
|
|
||||||
"allow": [],
|
|
||||||
"depConstraints": [
|
|
||||||
{
|
|
||||||
"sourceTag": "*",
|
|
||||||
"onlyDependOnLibsWithTags": ["*"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx"],
|
|
||||||
"extends": ["plugin:@nrwl/nx/typescript"],
|
|
||||||
"plugins": ["simple-import-sort", "unused-imports"],
|
|
||||||
"rules": {
|
|
||||||
// TypeScript ESLint
|
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
|
|
||||||
// Simple Import Sort
|
|
||||||
"simple-import-sort/imports": "error",
|
|
||||||
"simple-import-sort/exports": "error",
|
|
||||||
|
|
||||||
// Unused Imports
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"unused-imports/no-unused-imports": "error",
|
|
||||||
"unused-imports/no-unused-vars": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"vars": "all",
|
|
||||||
"varsIgnorePattern": "^_",
|
|
||||||
"args": "none",
|
|
||||||
"argsIgnorePattern": "^_"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.js", "*.jsx"],
|
|
||||||
"extends": ["plugin:@nrwl/nx/javascript"],
|
|
||||||
"rules": {}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
name: Build Image and Push to Docker Hub
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [v3]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
|
||||||
with:
|
|
||||||
images: ${{ secrets.DOCKER_USERNAME }}/reactive-resume
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
|
||||||
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
|
@ -1,44 +1,16 @@
|
||||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
# Package Manager
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
# compiled output
|
# Project Dependencies
|
||||||
/dist
|
node_modules
|
||||||
/tmp
|
|
||||||
/out-tsc
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
|
|
||||||
# IDEs and editors
|
|
||||||
/.idea
|
|
||||||
.project
|
|
||||||
.classpath
|
|
||||||
.c9/
|
|
||||||
*.launch
|
|
||||||
.settings/
|
|
||||||
*.sublime-workspace
|
|
||||||
|
|
||||||
# IDE - VSCode
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
|
|
||||||
# misc
|
|
||||||
/.sass-cache
|
|
||||||
/connect.lock
|
|
||||||
/coverage
|
|
||||||
/libpeerconnection.log
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
testem.log
|
|
||||||
/typings
|
|
||||||
|
|
||||||
# System Files
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Environment Variables
|
# Environment Variables
|
||||||
/.env
|
.env
|
||||||
/.env.*
|
.env.*
|
||||||
!.env.example
|
!.env.example
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npx changeset version
|
|
||||||
npm run lint && npm run format
|
|
|
@ -1,4 +0,0 @@
|
||||||
# Add files here to ignore them from prettier formatting
|
|
||||||
|
|
||||||
/dist
|
|
||||||
/coverage
|
|
|
@ -1,9 +1,3 @@
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "lokalise.i18n-ally"]
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"firsttris.vscode-jest-runner",
|
|
||||||
"lokalise.i18n-ally",
|
|
||||||
"nrwl.angular-console"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
{
|
{
|
||||||
"css.validate": false,
|
"css.validate": false,
|
||||||
|
"scss.validate": false,
|
||||||
"editor.codeActionsOnSave": { "source.fixAll.eslint": true },
|
"editor.codeActionsOnSave": { "source.fixAll.eslint": true },
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.wordWrap": "on",
|
"editor.wordWrap": "on",
|
||||||
|
"eslint.workingDirectories": ["schema", "client", "server"],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.localesPaths": ["apps/client/public/locales"],
|
"i18n-ally.localesPaths": ["client/public/locales"],
|
||||||
"i18n-ally.namespace": true,
|
"i18n-ally.namespace": true,
|
||||||
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
|
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
|
||||||
"i18n-ally.sortKeys": true,
|
"i18n-ally.sortKeys": true
|
||||||
"scss.validate": false
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,7 @@
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
||||||
|
spec: "@yarnpkg/plugin-workspace-tools"
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-3.2.0.cjs
|
32
Dockerfile
32
Dockerfile
|
@ -1,32 +0,0 @@
|
||||||
FROM node AS builder
|
|
||||||
|
|
||||||
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY package.json pnpm-lock.yaml ./
|
|
||||||
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN pnpm build
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/playwright:focal AS production
|
|
||||||
|
|
||||||
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --from=builder /app/package.json /app/pnpm-lock.yaml ./
|
|
||||||
COPY --from=builder /app/dist ./dist
|
|
||||||
|
|
||||||
RUN pnpm install --frozen-lockfile --prod
|
|
||||||
|
|
||||||
# Expose App
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Export Server
|
|
||||||
EXPOSE 3100
|
|
||||||
|
|
||||||
CMD [ "pnpm", "start" ]
|
|
20
LICENSE.md
20
LICENSE.md
|
@ -1,20 +0,0 @@
|
||||||
Copyright (c) 2020-2022 Amruth Pillai
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"extends": ["plugin:@nrwl/nx/react-typescript", "../../.eslintrc.json", "next", "next/core-web-vitals"],
|
|
||||||
"ignorePatterns": ["!**/*"],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
||||||
"rules": {
|
|
||||||
"@next/next/no-html-link-for-pages": ["error", "apps/client/pages"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx"],
|
|
||||||
"rules": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.js", "*.jsx"],
|
|
||||||
"rules": {}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"jest": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"@next/next/no-img-element": "off"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { UserConfig } from 'next-i18next';
|
|
||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
const i18nConfig: UserConfig = {
|
|
||||||
i18n: {
|
|
||||||
defaultLocale: 'en',
|
|
||||||
locales: ['en'],
|
|
||||||
},
|
|
||||||
debug: false,
|
|
||||||
nsSeparator: '.',
|
|
||||||
localePath: join(__dirname, '../../../public/locales'),
|
|
||||||
ns: ['common', 'modals', 'landing', 'dashboard', 'builder'],
|
|
||||||
};
|
|
||||||
|
|
||||||
export default i18nConfig;
|
|
|
@ -1,6 +0,0 @@
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
declare module '*.svg' {
|
|
||||||
const content: any;
|
|
||||||
export const ReactComponent: any;
|
|
||||||
export default content;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
displayName: 'client',
|
|
||||||
preset: '../../jest.preset.js',
|
|
||||||
transform: {
|
|
||||||
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
|
|
||||||
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
|
|
||||||
},
|
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
||||||
coverageDirectory: '../../coverage/apps/client',
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
const { join } = require('path');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {
|
|
||||||
config: join(__dirname, 'tailwind.config.js'),
|
|
||||||
},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,55 +0,0 @@
|
||||||
{
|
|
||||||
"root": "apps/client",
|
|
||||||
"sourceRoot": "apps/client",
|
|
||||||
"projectType": "application",
|
|
||||||
"targets": {
|
|
||||||
"build": {
|
|
||||||
"executor": "@nrwl/next:build",
|
|
||||||
"outputs": ["{options.outputPath}"],
|
|
||||||
"defaultConfiguration": "production",
|
|
||||||
"options": {
|
|
||||||
"root": "apps/client",
|
|
||||||
"outputPath": "dist/apps/client"
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"serve": {
|
|
||||||
"executor": "@nrwl/next:server",
|
|
||||||
"options": {
|
|
||||||
"buildTarget": "client:build",
|
|
||||||
"dev": true,
|
|
||||||
"port": 3000
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"buildTarget": "client:build:production",
|
|
||||||
"dev": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"export": {
|
|
||||||
"executor": "@nrwl/next:export",
|
|
||||||
"options": {
|
|
||||||
"buildTarget": "client:build:production"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"executor": "@nrwl/jest:jest",
|
|
||||||
"outputs": ["coverage/apps/client"],
|
|
||||||
"options": {
|
|
||||||
"jestConfig": "apps/client/jest.config.js",
|
|
||||||
"passWithNoTests": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nrwl/linter:eslint",
|
|
||||||
"outputs": ["{options.outputFile}"],
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": ["apps/client/**/*.{ts,tsx,js,jsx}"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": []
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"module": "commonjs",
|
|
||||||
"types": ["jest", "node"],
|
|
||||||
"jsx": "react"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"**/*.test.ts",
|
|
||||||
"**/*.spec.ts",
|
|
||||||
"**/*.test.tsx",
|
|
||||||
"**/*.spec.tsx",
|
|
||||||
"**/*.test.js",
|
|
||||||
"**/*.spec.js",
|
|
||||||
"**/*.test.jsx",
|
|
||||||
"**/*.spec.jsx",
|
|
||||||
"**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"extends": ["../../.eslintrc.json"],
|
|
||||||
"ignorePatterns": ["!**/*"],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
||||||
"rules": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx"],
|
|
||||||
"rules": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.js", "*.jsx"],
|
|
||||||
"rules": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
displayName: 'server',
|
|
||||||
preset: '../../jest.preset.js',
|
|
||||||
globals: {
|
|
||||||
'ts-jest': {
|
|
||||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
testEnvironment: 'node',
|
|
||||||
transform: {
|
|
||||||
'^.+\\.[tj]s$': 'ts-jest',
|
|
||||||
},
|
|
||||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
||||||
coverageDirectory: '../../coverage/apps/server',
|
|
||||||
};
|
|
|
@ -1,57 +0,0 @@
|
||||||
{
|
|
||||||
"root": "apps/server",
|
|
||||||
"sourceRoot": "apps/server/src",
|
|
||||||
"projectType": "application",
|
|
||||||
"targets": {
|
|
||||||
"build": {
|
|
||||||
"executor": "@nrwl/node:webpack",
|
|
||||||
"outputs": ["{options.outputPath}"],
|
|
||||||
"options": {
|
|
||||||
"outputPath": "dist/apps/server",
|
|
||||||
"main": "apps/server/src/main.ts",
|
|
||||||
"tsConfig": "apps/server/tsconfig.app.json",
|
|
||||||
"assets": ["apps/server/src/assets"]
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"optimization": true,
|
|
||||||
"extractLicenses": true,
|
|
||||||
"inspect": false,
|
|
||||||
"fileReplacements": [
|
|
||||||
{
|
|
||||||
"replace": "apps/server/src/environments/environment.ts",
|
|
||||||
"with": "apps/server/src/environments/environment.prod.ts"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"serve": {
|
|
||||||
"executor": "@nrwl/node:node",
|
|
||||||
"options": {
|
|
||||||
"buildTarget": "server:build"
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"buildTarget": "server:build:production"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nrwl/linter:eslint",
|
|
||||||
"outputs": ["{options.outputFile}"],
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": ["apps/server/**/*.ts"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"executor": "@nrwl/jest:jest",
|
|
||||||
"outputs": ["coverage/apps/server"],
|
|
||||||
"options": {
|
|
||||||
"jestConfig": "apps/server/jest.config.js",
|
|
||||||
"passWithNoTests": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": []
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"module": "commonjs",
|
|
||||||
"types": ["node"],
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"target": "es2015",
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@reactive-resume/schema": ["../../libs/schema/src/index.ts"],
|
|
||||||
"@/auth/*": ["src/auth/*"],
|
|
||||||
"@/config/*": ["src/config/*"],
|
|
||||||
"@/constants/*": ["src/constants/*"],
|
|
||||||
"@/database/*": ["src/database/*"],
|
|
||||||
"@/decorators/*": ["src/decorators/*"],
|
|
||||||
"@/filters/*": ["src/filters/*"],
|
|
||||||
"@/mail/*": ["src/mail/*"],
|
|
||||||
"@/resume/*": ["src/resume/*"],
|
|
||||||
"@/users/*": ["src/users/*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exclude": ["**/*.spec.ts", "**/*.test.ts"],
|
|
||||||
"include": ["**/*.ts"]
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"files": [],
|
|
||||||
"include": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.app.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.spec.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"module": "commonjs",
|
|
||||||
"types": ["jest", "node"]
|
|
||||||
},
|
|
||||||
"include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"babelrcRoots": ["*"]
|
|
||||||
}
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Install dependencies only when needed
|
||||||
|
FROM node:16-alpine AS dependencies
|
||||||
|
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN yarn set version berry
|
||||||
|
RUN yarn plugin import workspace-tools
|
||||||
|
|
||||||
|
COPY package.json .yarnrc.yml yarn.lock ./
|
||||||
|
COPY schema/package.json ./schema/package.json
|
||||||
|
COPY client/package.json ./client/package.json
|
||||||
|
|
||||||
|
RUN yarn install
|
||||||
|
|
||||||
|
FROM node:16-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN yarn set version berry
|
||||||
|
RUN yarn plugin import workspace-tools
|
||||||
|
|
||||||
|
COPY --from=dependencies /app/package.json .
|
||||||
|
COPY --from=dependencies /app/node_modules ./node_modules
|
||||||
|
|
||||||
|
COPY ./schema ./schema
|
||||||
|
COPY ./client ./client
|
||||||
|
|
||||||
|
RUN yarn workspace @reactive-resume/schema run build
|
||||||
|
RUN yarn workspace @reactive-resume/client run build
|
||||||
|
|
||||||
|
FROM node:16-alpine AS production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV production
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
|
COPY --from=builder /app/client/next.config.js ./
|
||||||
|
COPY --from=builder /app/client/next-i18next.config.js ./
|
||||||
|
COPY --from=builder /app/client/public ./public
|
||||||
|
COPY --from=builder /app/client/package.json ./package.json
|
||||||
|
|
||||||
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/client/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/client/.next/static ./.next/static
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV PORT 3000
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"extends": ["../.eslintrc.json", "next/core-web-vitals"],
|
||||||
|
"ignorePatterns": [".next"],
|
||||||
|
"rules": {
|
||||||
|
"@next/next/no-img-element": "off"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
|
@ -74,19 +74,19 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className={styles.controller}>
|
<div className={styles.controller}>
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-in')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-in')}>
|
||||||
<ButtonBase onClick={() => zoomIn(0.25)}>
|
<ButtonBase onClick={() => zoomIn(0.25)}>
|
||||||
<ZoomIn fontSize="medium" />
|
<ZoomIn fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.zoom-out')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.zoom-out')}>
|
||||||
<ButtonBase onClick={() => zoomOut(0.25)}>
|
<ButtonBase onClick={() => zoomOut(0.25)}>
|
||||||
<ZoomOut fontSize="medium" />
|
<ZoomOut fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.center-artboard')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.center-artboard')}>
|
||||||
<ButtonBase onClick={() => centerView(0.95)}>
|
<ButtonBase onClick={() => centerView(0.95)}>
|
||||||
<FilterCenterFocus fontSize="medium" />
|
<FilterCenterFocus fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
@ -96,7 +96,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||||
|
|
||||||
{isDesktop && (
|
{isDesktop && (
|
||||||
<>
|
<>
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-orientation')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-orientation')}>
|
||||||
<ButtonBase onClick={handleTogglePageOrientation}>
|
<ButtonBase onClick={handleTogglePageOrientation}>
|
||||||
{orientation === 'vertical' ? (
|
{orientation === 'vertical' ? (
|
||||||
<AlignHorizontalCenter fontSize="medium" />
|
<AlignHorizontalCenter fontSize="medium" />
|
||||||
|
@ -106,13 +106,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-page-break-line')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-page-break-line')}>
|
||||||
<ButtonBase onClick={handleTogglePageBreakLine}>
|
<ButtonBase onClick={handleTogglePageBreakLine}>
|
||||||
<InsertPageBreak fontSize="medium" />
|
<InsertPageBreak fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.toggle-sidebars')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.toggle-sidebars')}>
|
||||||
<ButtonBase onClick={handleToggleSidebar}>
|
<ButtonBase onClick={handleToggleSidebar}>
|
||||||
<ViewSidebar fontSize="medium" />
|
<ViewSidebar fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
@ -122,13 +122,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.copy-link')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.copy-link')}>
|
||||||
<ButtonBase onClick={handleCopyLink}>
|
<ButtonBase onClick={handleCopyLink}>
|
||||||
<Link fontSize="medium" />
|
<Link fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip arrow placement="top" title={t('builder.controller.tooltip.export-pdf')}>
|
<Tooltip arrow placement="top" title={t<string>('builder.controller.tooltip.export-pdf')}>
|
||||||
<ButtonBase onClick={handleExportPDF} disabled={isLoading}>
|
<ButtonBase onClick={handleExportPDF} disabled={isLoading}>
|
||||||
<Download fontSize="medium" />
|
<Download fontSize="medium" />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
|
@ -184,7 +184,7 @@ const Header = () => {
|
||||||
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
|
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
) : (
|
) : (
|
||||||
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.share-link')}>
|
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.share-link')}>
|
||||||
<div>
|
<div>
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
@ -196,7 +196,7 @@ const Header = () => {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Tooltip arrow placement="right" title={t('builder.header.menu.tooltips.delete')}>
|
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.delete')}>
|
||||||
<MenuItem onClick={handleDelete}>
|
<MenuItem onClick={handleDelete}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Delete className="scale-90" />
|
<Delete className="scale-90" />
|
|
@ -30,7 +30,7 @@ const Page: React.FC<Props> = ({ page, showPageNumbers = false }) => {
|
||||||
|
|
||||||
const themeCSS = useMemo(() => !isEmpty(theme) && generateThemeStyles(theme), [theme]);
|
const themeCSS = useMemo(() => !isEmpty(theme) && generateThemeStyles(theme), [theme]);
|
||||||
const typographyCSS = useMemo(() => !isEmpty(typography) && generateTypographyStyles(typography), [typography]);
|
const typographyCSS = useMemo(() => !isEmpty(typography) && generateTypographyStyles(typography), [typography]);
|
||||||
const TemplatePage: React.FC<PageProps> = useMemo(() => get(templateMap, `${template}.component`, null), [template]);
|
const TemplatePage: React.FC<PageProps> | null = useMemo(() => templateMap[template].component, [template]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-page={page + 1} className={styles.container}>
|
<div data-page={page + 1} className={styles.container}>
|
|
@ -38,7 +38,9 @@ const LeftSidebar = () => {
|
||||||
const elementId = validate(id) ? `#section-${id}` : `#${id}`;
|
const elementId = validate(id) ? `#section-${id}` : `#${id}`;
|
||||||
const section = document.querySelector(elementId);
|
const section = document.querySelector(elementId);
|
||||||
|
|
||||||
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
if (section) {
|
||||||
|
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddSection = () => {
|
const handleAddSection = () => {
|
||||||
|
@ -79,7 +81,7 @@ const LeftSidebar = () => {
|
||||||
arrow
|
arrow
|
||||||
key={id}
|
key={id}
|
||||||
placement="right"
|
placement="right"
|
||||||
title={get(sections, `${id}.name`, t(`builder.leftSidebar.sections.${id}.heading`))}
|
title={get(sections, `${id}.name`, t<string>(`builder.leftSidebar.sections.${id}.heading`))}
|
||||||
>
|
>
|
||||||
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
|
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
|
@ -18,7 +18,7 @@ const PhotoFilters = () => {
|
||||||
const grayscale: boolean = get(photo, 'filters.grayscale', false);
|
const grayscale: boolean = get(photo, 'filters.grayscale', false);
|
||||||
const border: boolean = get(photo, 'filters.border', false);
|
const border: boolean = get(photo, 'filters.border', false);
|
||||||
|
|
||||||
const handleChangeSize = (size: number) =>
|
const handleChangeSize = (size: number | number[]) =>
|
||||||
dispatch(setResumeState({ path: 'basics.photo.filters.size', value: size }));
|
dispatch(setResumeState({ path: 'basics.photo.filters.size', value: size }));
|
||||||
|
|
||||||
const handleChangeShape = (shape: PhotoShape) =>
|
const handleChangeShape = (shape: PhotoShape) =>
|
||||||
|
@ -46,7 +46,7 @@ const PhotoFilters = () => {
|
||||||
{ value: 512, label: '512' },
|
{ value: 512, label: '512' },
|
||||||
]}
|
]}
|
||||||
value={size}
|
value={size}
|
||||||
onChange={(_, value: number) => handleChangeSize(value)}
|
onChange={(_, value: number | number[]) => handleChangeSize(value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,14 +58,14 @@ const PhotoFilters = () => {
|
||||||
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<FormControlLabel
|
<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={
|
control={
|
||||||
<Checkbox color="secondary" checked={grayscale} onChange={(_, value) => handleSetGrayscale(value)} />
|
<Checkbox color="secondary" checked={grayscale} onChange={(_, value) => handleSetGrayscale(value)} />
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormControlLabel
|
<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)} />}
|
control={<Checkbox color="secondary" checked={border} onChange={(_, value) => handleSetBorder(value)} />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
|
@ -67,8 +67,8 @@ const PhotoUpload: React.FC = () => {
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
isEmpty(photo.url)
|
isEmpty(photo.url)
|
||||||
? t('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload')
|
? t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload')
|
||||||
: t('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove')
|
: t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />
|
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />
|
|
@ -41,14 +41,14 @@ const Section: React.FC<Props> = ({
|
||||||
const visibility = useAppSelector<boolean>((state) => get(state.resume, `${path}.visible`, true));
|
const visibility = useAppSelector<boolean>((state) => get(state.resume, `${path}.visible`, true));
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
const id = path.split('.').at(-1);
|
const id = path.split('.').at(-1) as string;
|
||||||
const modal: ModalName = validate(id) ? 'builder.sections.custom' : `builder.${path}`;
|
const modal: ModalName = validate(id) ? 'builder.sections.custom' : `builder.${path}`;
|
||||||
|
|
||||||
dispatch(setModalState({ modal, state: { open: true, payload: { path } } }));
|
dispatch(setModalState({ modal, state: { open: true, payload: { path } } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (item: ListItem) => {
|
const handleEdit = (item: ListItem) => {
|
||||||
const id = path.split('.').at(-1);
|
const id = path.split('.').at(-1) as string;
|
||||||
const modal: ModalName = validate(id) ? 'builder.sections.custom' : `builder.${path}`;
|
const modal: ModalName = validate(id) ? 'builder.sections.custom' : `builder.${path}`;
|
||||||
const payload = validate(id) ? { path, item } : { item };
|
const payload = validate(id) ? { path, item } : { item };
|
||||||
|
|
|
@ -32,7 +32,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Tooltip title={t('builder.common.columns.tooltip')}>
|
<Tooltip title={t<string>('builder.common.columns.tooltip')}>
|
||||||
<ButtonBase onClick={handleClick} sx={{ padding: 1, borderRadius: 1 }} className="opacity-50 hover:opacity-75">
|
<ButtonBase onClick={handleClick} sx={{ padding: 1, borderRadius: 1 }} className="opacity-50 hover:opacity-75">
|
||||||
<ViewWeek /> <span className="ml-1.5 text-xs">{columns}</span>
|
<ViewWeek /> <span className="ml-1.5 text-xs">{columns}</span>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
|
@ -27,7 +27,10 @@ const RightSidebar = () => {
|
||||||
|
|
||||||
const handleClick = (id: string) => {
|
const handleClick = (id: string) => {
|
||||||
const section = document.querySelector(`#${id}`);
|
const section = document.querySelector(`#${id}`);
|
||||||
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
||||||
|
if (section) {
|
||||||
|
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -52,7 +55,7 @@ const RightSidebar = () => {
|
||||||
key={id}
|
key={id}
|
||||||
arrow
|
arrow
|
||||||
placement="right"
|
placement="right"
|
||||||
title={t(`builder.rightSidebar.sections.${id}.heading`, { defaultValue: capitalize(id) })}
|
title={t<string>(`builder.rightSidebar.sections.${id}.heading`, { defaultValue: capitalize(id) })}
|
||||||
>
|
>
|
||||||
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
|
<IconButton onClick={() => handleClick(id)}>{icon}</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
|
@ -19,7 +19,7 @@ const CustomCSS = () => {
|
||||||
|
|
||||||
const customCSS: CustomCSSType = useAppSelector((state) => get(state.resume, 'metadata.css', {}));
|
const customCSS: CustomCSSType = useAppSelector((state) => get(state.resume, 'metadata.css', {}));
|
||||||
|
|
||||||
const handleChange = (value: string) => {
|
const handleChange = (value: string | undefined) => {
|
||||||
dispatch(setResumeState({ path: 'metadata.css.value', value }));
|
dispatch(setResumeState({ path: 'metadata.css.value', value }));
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,7 @@ const Layout = () => {
|
||||||
path="metadata.layout"
|
path="metadata.layout"
|
||||||
name={t('builder.rightSidebar.sections.layout.heading')}
|
name={t('builder.rightSidebar.sections.layout.heading')}
|
||||||
action={
|
action={
|
||||||
<Tooltip title={t('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
|
<Tooltip title={t<string>('builder.rightSidebar.sections.layout.tooltip.reset-layout')}>
|
||||||
<IconButton onClick={handleResetLayout}>
|
<IconButton onClick={handleResetLayout}>
|
||||||
<Restore />
|
<Restore />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -80,7 +80,9 @@ const Layout = () => {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
|
<div className={clsx(styles.delete, { hidden: pageIndex === 0 })}>
|
||||||
<Tooltip title={t('builder.common.actions.delete', { token: t('builder.common.glossary.page') })}>
|
<Tooltip
|
||||||
|
title={t<string>('builder.common.actions.delete', { token: t('builder.common.glossary.page') })}
|
||||||
|
>
|
||||||
<IconButton size="small" onClick={() => handleDeletePage(pageIndex)}>
|
<IconButton size="small" onClick={() => handleDeletePage(pageIndex)}>
|
||||||
<Close fontSize="small" />
|
<Close fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
|
@ -55,10 +55,11 @@ const Settings = () => {
|
||||||
|
|
||||||
const handleSetTheme = (value: boolean) => dispatch(setTheme({ theme: value ? 'dark' : 'light' }));
|
const handleSetTheme = (value: boolean) => dispatch(setTheme({ theme: value ? 'dark' : 'light' }));
|
||||||
|
|
||||||
const handleChangeDateFormat = (value: string) => dispatch(setResumeState({ path: 'metadata.date.format', value }));
|
const handleChangeDateFormat = (value: string | null) =>
|
||||||
|
dispatch(setResumeState({ path: 'metadata.date.format', value }));
|
||||||
|
|
||||||
const handleChangeLanguage = (value: Language) =>
|
const handleChangeLanguage = (value: Language | null) =>
|
||||||
dispatch(setResumeState({ path: 'metadata.language', value: value.code }));
|
dispatch(setResumeState({ path: 'metadata.language', value: value?.code }));
|
||||||
|
|
||||||
const handleLoadSampleData = async () => {
|
const handleLoadSampleData = async () => {
|
||||||
await loadSampleDataMutation({ id });
|
await loadSampleDataMutation({ id });
|
|
@ -63,7 +63,7 @@ const Sharing = () => {
|
||||||
|
|
||||||
<div className="mt-1 flex w-full">
|
<div className="mt-1 flex w-full">
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label={t('builder.rightSidebar.sections.sharing.short-url.label') as string}
|
label={t<string>('builder.rightSidebar.sections.sharing.short-url.label')}
|
||||||
control={
|
control={
|
||||||
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
|
<Checkbox className="mr-1" checked={showShortUrl} onChange={(_, value) => setShowShortUrl(value)} />
|
||||||
}
|
}
|
|
@ -39,8 +39,8 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
|
||||||
select: (fonts) => fonts.sort((a, b) => a.category.localeCompare(b.category)),
|
select: (fonts) => fonts.sort((a, b) => a.category.localeCompare(b.category)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleChange = (property: TypeProperty, value: number | Font) => {
|
const handleChange = (property: TypeProperty, value: number | number[] | Font | null) => {
|
||||||
if (value === null) return;
|
if (!value) return;
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setResumeState({
|
setResumeState({
|
||||||
|
@ -50,7 +50,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isEmpty(fonts)) return <TypographySkeleton />;
|
if (!fonts || isEmpty(fonts)) return <TypographySkeleton />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -69,7 +69,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
|
||||||
]}
|
]}
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
value={size[category]}
|
value={size[category]}
|
||||||
onChange={(_, size: number) => handleChange('size', size)}
|
onChange={(_, size: number | number[]) => handleChange('size', size)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
|
||||||
getOptionLabel={(font) => font.family}
|
getOptionLabel={(font) => font.family}
|
||||||
isOptionEqualToValue={(a, b) => a.family === b.family}
|
isOptionEqualToValue={(a, b) => a.family === b.family}
|
||||||
value={fonts.find((font) => font.family === family[category])}
|
value={fonts.find((font) => font.family === family[category])}
|
||||||
onChange={(_, font: Font) => handleChange('family', font)}
|
onChange={(_, font: Font | null) => handleChange('family', font)}
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
|
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
|
||||||
)}
|
)}
|
|
@ -161,7 +161,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
|
||||||
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
|
<ListItemText>{t('dashboard.resume.menu.share-link')}</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
) : (
|
) : (
|
||||||
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.share-link')}>
|
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.share-link')}>
|
||||||
<div>
|
<div>
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
@ -173,7 +173,7 @@ const ResumePreview: React.FC<Props> = ({ resume }) => {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Tooltip arrow placement="right" title={t('dashboard.resume.menu.tooltips.delete')}>
|
<Tooltip arrow placement="right" title={t<string>('dashboard.resume.menu.tooltips.delete')}>
|
||||||
<MenuItem onClick={handleDelete}>
|
<MenuItem onClick={handleDelete}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<DeleteOutline className="scale-90" />
|
<DeleteOutline className="scale-90" />
|
|
@ -7,11 +7,11 @@ import { FieldError } from 'react-hook-form';
|
||||||
import styles from './ArrayInput.module.scss';
|
import styles from './ArrayInput.module.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: string[];
|
|
||||||
label: string;
|
label: string;
|
||||||
onChange: (event: any) => void;
|
value: string[];
|
||||||
errors: FieldError | FieldError[];
|
|
||||||
className?: string;
|
className?: string;
|
||||||
|
onChange: (event: any) => void;
|
||||||
|
errors?: FieldError | FieldError[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const ArrayInput: React.FC<Props> = ({ value, label, onChange, errors, className }) => {
|
const ArrayInput: React.FC<Props> = ({ value, label, onChange, errors, className }) => {
|
|
@ -12,7 +12,7 @@ import { deleteSection, setResumeState } from '@/store/resume/resumeSlice';
|
||||||
import styles from './Heading.module.scss';
|
import styles from './Heading.module.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
path?: string;
|
path: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
isEditable?: boolean;
|
isEditable?: boolean;
|
||||||
isHideable?: boolean;
|
isHideable?: boolean;
|
||||||
|
@ -72,19 +72,19 @@ const Heading: React.FC<Props> = ({
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{isEditable && (
|
{isEditable && (
|
||||||
<Tooltip title={t('builder.common.tooltip.rename-section')}>
|
<Tooltip title={t<string>('builder.common.tooltip.rename-section')}>
|
||||||
<IconButton onClick={toggleEditMode}>{editMode ? <Check /> : <DriveFileRenameOutline />}</IconButton>
|
<IconButton onClick={toggleEditMode}>{editMode ? <Check /> : <DriveFileRenameOutline />}</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isHideable && (
|
{isHideable && (
|
||||||
<Tooltip title={t('builder.common.tooltip.toggle-visibility')}>
|
<Tooltip title={t<string>('builder.common.tooltip.toggle-visibility')}>
|
||||||
<IconButton onClick={toggleVisibility}>{visibility ? <Visibility /> : <VisibilityOff />}</IconButton>
|
<IconButton onClick={toggleVisibility}>{visibility ? <Visibility /> : <VisibilityOff />}</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isDeletable && (
|
{isDeletable && (
|
||||||
<Tooltip title={t('builder.common.tooltip.delete-section')}>
|
<Tooltip title={t<string>('builder.common.tooltip.delete-section')}>
|
||||||
<IconButton onClick={handleDelete}>
|
<IconButton onClick={handleDelete}>
|
||||||
<Delete />
|
<Delete />
|
||||||
</IconButton>
|
</IconButton>
|
|
@ -29,7 +29,7 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
|
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
|
||||||
|
|
||||||
const [{ handlerId }, drop] = useDrop({
|
const [{ handlerId }, drop] = useDrop<DragItem, any, any>({
|
||||||
accept: 'ListItem',
|
accept: 'ListItem',
|
||||||
collect(monitor) {
|
collect(monitor) {
|
||||||
return { handlerId: monitor.getHandlerId() };
|
return { handlerId: monitor.getHandlerId() };
|
|
@ -1,4 +1,5 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
|
|
||||||
|
@ -8,6 +9,8 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Markdown: React.FC<Props> = ({ className, children }) => {
|
const Markdown: React.FC<Props> = ({ className, children }) => {
|
||||||
|
if (!children || isEmpty(children)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown remarkPlugins={[remarkGfm]} className={clsx('markdown', className)}>
|
<ReactMarkdown remarkPlugins={[remarkGfm]} className={clsx('markdown', className)}>
|
||||||
{children}
|
{children}
|
|
@ -11,7 +11,7 @@ export const languages: Language[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const languageMap = languages.reduce(
|
export const languageMap: Record<string, Language> = languages.reduce(
|
||||||
(acc, lang) => ({
|
(acc, lang) => ({
|
||||||
...acc,
|
...acc,
|
||||||
[lang.code]: lang,
|
[lang.code]: lang,
|
|
@ -164,7 +164,7 @@ export const right: SidebarSection[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getCustomSections = (sections: Record<string, SectionRecord>): Array<SectionRecord> => {
|
export const getCustomSections = (sections: Record<string, SectionRecord>): Array<Required<SectionRecord>> => {
|
||||||
if (isEmpty(sections)) return [];
|
if (isEmpty(sections)) return [];
|
||||||
|
|
||||||
return Object.entries(sections).reduce((acc, [id, section]) => {
|
return Object.entries(sections).reduce((acc, [id, section]) => {
|
||||||
|
@ -173,7 +173,7 @@ export const getCustomSections = (sections: Record<string, SectionRecord>): Arra
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, [] as Array<SectionRecord>);
|
}, [] as Array<Required<SectionRecord>>);
|
||||||
};
|
};
|
||||||
|
|
||||||
const sections = [...left, ...right];
|
const sections = [...left, ...right];
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue