🚀 release v3.0.0

This commit is contained in:
Amruth Pillai 2022-03-06 22:48:29 +01:00
parent 00505a9e5d
commit 9c1380f401
No known key found for this signature in database
GPG Key ID: E3C57DF9B80855AD
373 changed files with 12050 additions and 15783 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -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)

View File

@ -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"
}

View File

@ -1,4 +1,5 @@
dist
.next
Dockerfile
node_modules
.dockerignore

View File

@ -1,13 +1,8 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@ -1,6 +1,5 @@
# Reactive Resume
TZ=UTC
NODE_ENV=development
SECRET_KEY=change-me
# URLs

View File

@ -1,58 +1,39 @@
{
"root": true,
"ignorePatterns": ["**/*"],
"plugins": ["@nrwl/nx"],
"extends": ["prettier"],
"parser": "@typescript-eslint/parser",
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
"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": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"files": ["*.js"],
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
}
]
}
]
"@typescript-eslint/no-var-requires": "off"
}
},
{
"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": {}
}
]
}

View File

@ -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 }}

54
.gitignore vendored
View File

@ -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
/dist
/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
# Project Dependencies
node_modules
# Environment Variables
/.env
/.env.*
!.env.example
.env
.env.*
!.env.example

View File

@ -1,5 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx changeset version
npm run lint && npm run format

View File

@ -1,4 +0,0 @@
# Add files here to ignore them from prettier formatting
/dist
/coverage

View File

@ -1,9 +1,3 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"firsttris.vscode-jest-runner",
"lokalise.i18n-ally",
"nrwl.angular-console"
]
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "lokalise.i18n-ally"]
}

View File

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

File diff suppressed because one or more lines are too long

785
.yarn/releases/yarn-3.2.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

7
.yarnrc.yml Normal file
View File

@ -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

View File

@ -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" ]

View File

@ -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.

View File

@ -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"
}
}

View File

@ -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;

View File

@ -1,6 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
declare module '*.svg' {
const content: any;
export const ReactComponent: any;
export default content;
}

View File

@ -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',
};

View File

@ -1,10 +0,0 @@
const { join } = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: join(__dirname, 'tailwind.config.js'),
},
autoprefixer: {},
},
};

View File

@ -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": []
}

View File

@ -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"
]
}

View File

@ -1,18 +0,0 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -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',
};

View File

@ -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": []
}

View File

@ -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"]
}

View File

@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}

View File

@ -1,3 +0,0 @@
{
"babelrcRoots": ["*"]
}

58
client.Dockerfile Normal file
View File

@ -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"]

7
client/.eslintrc.json Normal file
View File

@ -0,0 +1,7 @@
{
"extends": ["../.eslintrc.json", "next/core-web-vitals"],
"ignorePatterns": [".next"],
"rules": {
"@next/next/no-img-element": "off"
}
}

36
client/.gitignore vendored Normal file
View File

@ -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

View File

@ -74,19 +74,19 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
})}
>
<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)}>
<ZoomIn fontSize="medium" />
</ButtonBase>
</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)}>
<ZoomOut fontSize="medium" />
</ButtonBase>
</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)}>
<FilterCenterFocus fontSize="medium" />
</ButtonBase>
@ -96,7 +96,7 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
{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}>
{orientation === 'vertical' ? (
<AlignHorizontalCenter fontSize="medium" />
@ -106,13 +106,13 @@ const ArtboardController: React.FC<ReactZoomPanPinchRef> = ({ zoomIn, zoomOut, c
</ButtonBase>
</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}>
<InsertPageBreak fontSize="medium" />
</ButtonBase>
</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}>
<ViewSidebar fontSize="medium" />
</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}>
<Link fontSize="medium" />
</ButtonBase>
</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}>
<Download fontSize="medium" />
</ButtonBase>

View File

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

View File

@ -30,7 +30,7 @@ const Page: React.FC<Props> = ({ page, showPageNumbers = false }) => {
const themeCSS = useMemo(() => !isEmpty(theme) && generateThemeStyles(theme), [theme]);
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 (
<div data-page={page + 1} className={styles.container}>

View File

@ -38,7 +38,9 @@ const LeftSidebar = () => {
const elementId = validate(id) ? `#section-${id}` : `#${id}`;
const section = document.querySelector(elementId);
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
if (section) {
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
const handleAddSection = () => {
@ -79,7 +81,7 @@ const LeftSidebar = () => {
arrow
key={id}
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>
</Tooltip>

View File

@ -18,7 +18,7 @@ const PhotoFilters = () => {
const grayscale: boolean = get(photo, 'filters.grayscale', 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 }));
const handleChangeShape = (shape: PhotoShape) =>
@ -46,7 +46,7 @@ const PhotoFilters = () => {
{ value: 512, label: '512' },
]}
value={size}
onChange={(_, value: number) => handleChangeSize(value)}
onChange={(_, value: number | number[]) => handleChangeSize(value)}
/>
</div>
</div>
@ -58,14 +58,14 @@ const PhotoFilters = () => {
<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>

View File

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

View File

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

View File

@ -32,7 +32,7 @@ const SectionSettings: React.FC<Props> = ({ path }) => {
return (
<div>
<Tooltip title={t('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">
<ViewWeek /> <span className="ml-1.5 text-xs">{columns}</span>
</ButtonBase>

View File

@ -27,7 +27,10 @@ const RightSidebar = () => {
const handleClick = (id: string) => {
const section = document.querySelector(`#${id}`);
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
if (section) {
section.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
return (
@ -52,7 +55,7 @@ const RightSidebar = () => {
key={id}
arrow
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>
</Tooltip>

View File

@ -19,7 +19,7 @@ const CustomCSS = () => {
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 }));
};

View File

@ -62,7 +62,7 @@ const Layout = () => {
path="metadata.layout"
name={t('builder.rightSidebar.sections.layout.heading')}
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}>
<Restore />
</IconButton>
@ -80,7 +80,9 @@ const Layout = () => {
</p>
<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)}>
<Close fontSize="small" />
</IconButton>

View File

@ -55,10 +55,11 @@ const Settings = () => {
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) =>
dispatch(setResumeState({ path: 'metadata.language', value: value.code }));
const handleChangeLanguage = (value: Language | null) =>
dispatch(setResumeState({ path: 'metadata.language', value: value?.code }));
const handleLoadSampleData = async () => {
await loadSampleDataMutation({ id });

View File

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

View File

@ -39,8 +39,8 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
select: (fonts) => fonts.sort((a, b) => a.category.localeCompare(b.category)),
});
const handleChange = (property: TypeProperty, value: number | Font) => {
if (value === null) return;
const handleChange = (property: TypeProperty, value: number | number[] | Font | null) => {
if (!value) return;
dispatch(
setResumeState({
@ -50,7 +50,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
);
};
if (isEmpty(fonts)) return <TypographySkeleton />;
if (!fonts || isEmpty(fonts)) return <TypographySkeleton />;
return (
<>
@ -69,7 +69,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
]}
valueLabelDisplay="auto"
value={size[category]}
onChange={(_, size: number) => handleChange('size', size)}
onChange={(_, size: number | number[]) => handleChange('size', size)}
/>
</div>
@ -80,7 +80,7 @@ const Widgets: React.FC<WidgetProps> = ({ label, category }) => {
getOptionLabel={(font) => font.family}
isOptionEqualToValue={(a, b) => a.family === b.family}
value={fonts.find((font) => font.family === family[category])}
onChange={(_, font: Font) => handleChange('family', font)}
onChange={(_, font: Font | null) => handleChange('family', font)}
renderInput={(params) => (
<TextField {...params} label={t('builder.rightSidebar.sections.typography.form.font-family.label')} />
)}

View File

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

View File

@ -7,11 +7,11 @@ import { FieldError } from 'react-hook-form';
import styles from './ArrayInput.module.scss';
type Props = {
value: string[];
label: string;
onChange: (event: any) => void;
errors: FieldError | FieldError[];
value: string[];
className?: string;
onChange: (event: any) => void;
errors?: FieldError | FieldError[];
};
const ArrayInput: React.FC<Props> = ({ value, label, onChange, errors, className }) => {

View File

@ -12,7 +12,7 @@ import { deleteSection, setResumeState } from '@/store/resume/resumeSlice';
import styles from './Heading.module.scss';
type Props = {
path?: string;
path: string;
name?: string;
isEditable?: boolean;
isHideable?: boolean;
@ -72,19 +72,19 @@ const Heading: React.FC<Props> = ({
})}
>
{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>
</Tooltip>
)}
{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>
</Tooltip>
)}
{isDeletable && (
<Tooltip title={t('builder.common.tooltip.delete-section')}>
<Tooltip title={t<string>('builder.common.tooltip.delete-section')}>
<IconButton onClick={handleDelete}>
<Delete />
</IconButton>

View File

@ -29,7 +29,7 @@ const ListItem: React.FC<Props> = ({ item, index, title, subtitle, onMove, onEdi
const ref = useRef<HTMLDivElement>(null);
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
const [{ handlerId }, drop] = useDrop({
const [{ handlerId }, drop] = useDrop<DragItem, any, any>({
accept: 'ListItem',
collect(monitor) {
return { handlerId: monitor.getHandlerId() };

View File

@ -1,4 +1,5 @@
import clsx from 'clsx';
import { isEmpty } from 'lodash';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
@ -8,6 +9,8 @@ type Props = {
};
const Markdown: React.FC<Props> = ({ className, children }) => {
if (!children || isEmpty(children)) return null;
return (
<ReactMarkdown remarkPlugins={[remarkGfm]} className={clsx('markdown', className)}>
{children}

View File

@ -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.code]: lang,

View File

@ -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 [];
return Object.entries(sections).reduce((acc, [id, section]) => {
@ -173,7 +173,7 @@ export const getCustomSections = (sections: Record<string, SectionRecord>): Arra
}
return acc;
}, [] as Array<SectionRecord>);
}, [] as Array<Required<SectionRecord>>);
};
const sections = [...left, ...right];

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