🚀 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
|
||||
.next
|
||||
Dockerfile
|
||||
node_modules
|
||||
.dockerignore
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# Reactive Resume
|
||||
TZ=UTC
|
||||
NODE_ENV=development
|
||||
SECRET_KEY=change-me
|
||||
|
||||
# URLs
|
||||
|
|
|
@ -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": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/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
|
|
@ -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": [
|
||||
"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"]
|
||||
}
|
||||
|
|
|
@ -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
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}>
|
||||
<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>
|
|
@ -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" />
|
|
@ -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}>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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} />
|
|
@ -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 };
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 }));
|
||||
};
|
||||
|
|
@ -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>
|
|
@ -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 });
|
|
@ -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)} />
|
||||
}
|
|
@ -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')} />
|
||||
)}
|
|
@ -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" />
|
|
@ -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 }) => {
|
|
@ -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>
|
|
@ -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() };
|
|
@ -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}
|
|
@ -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,
|
|
@ -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
Loading…
Reference in New Issue