mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-19 03:01:53 +10:00
- implement i18n
- translation dynamic for sections - added articles for SEO
This commit is contained in:
@ -1,15 +1,16 @@
|
||||
import React, { Fragment, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Element } from 'react-scroll';
|
||||
import sections from '../../../data/rightSections';
|
||||
import RightNavbar from './RightNavbar';
|
||||
import styles from './RightSidebar.module.css';
|
||||
import About from './sections/About';
|
||||
import Actions from './sections/Actions';
|
||||
import Colors from './sections/Colors';
|
||||
import Fonts from './sections/Fonts';
|
||||
import Layout from './sections/Layout';
|
||||
import Templates from './sections/Templates';
|
||||
import Actions from './sections/Actions';
|
||||
import Settings from './sections/Settings';
|
||||
import About from './sections/About';
|
||||
import Templates from './sections/Templates';
|
||||
|
||||
const getComponent = (id) => {
|
||||
switch (id) {
|
||||
@ -33,16 +34,22 @@ const getComponent = (id) => {
|
||||
};
|
||||
|
||||
const RightSidebar = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<div id="RightSidebar" className={styles.container}>
|
||||
{sections.map(({ id, name, event }) => {
|
||||
{sections.map(({ id, event }) => {
|
||||
const Component = getComponent(id);
|
||||
|
||||
return (
|
||||
<Fragment key={id}>
|
||||
<Element name={id}>
|
||||
<Component id={id} name={name} event={event} />
|
||||
<Component
|
||||
id={id}
|
||||
name={t(`builder.sections.${id}`)}
|
||||
event={event}
|
||||
/>
|
||||
</Element>
|
||||
<hr />
|
||||
</Fragment>
|
||||
|
||||
@ -1,31 +1,25 @@
|
||||
import React, { memo } from 'react';
|
||||
import { FaCoffee, FaBug } from 'react-icons/fa';
|
||||
import { FaCoffee, FaBug, FaExternalLinkAlt } from 'react-icons/fa';
|
||||
import { MdCode } from 'react-icons/md';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './About.module.css';
|
||||
|
||||
const About = () => {
|
||||
const About = ({ name }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>About</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Donate to Reactive Resume</h5>
|
||||
<h5>{t('builder.about.donate.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
As you know, every nook and cranny of this app is free and
|
||||
open-source, but servers don't pay for themselves.
|
||||
</p>
|
||||
|
||||
<p className="leading-loose">
|
||||
I try to do what I can, but if you found the app helpful, or
|
||||
you're in a better position than the others who depend on this
|
||||
project for their first job, please consider donating{' '}
|
||||
<span className="font-semibold">
|
||||
as little as $5 to help keep the project alive
|
||||
</span>{' '}
|
||||
:)
|
||||
<Trans t={t} i18nKey="builder.about.donate.text">
|
||||
A<span className="font-bold">B</span>C
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
@ -34,19 +28,15 @@ const About = () => {
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<Button icon={FaCoffee}>Buy me a coffee!</Button>
|
||||
<Button icon={FaCoffee}>{t('builder.about.donate.button')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Bug? Feature Request?</h5>
|
||||
<h5>{t('builder.about.bugFeature.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
Something halting your progress from making a resume? Found a pesky
|
||||
bug that just won't quit? Talk about it on the GitHub Issues
|
||||
section, or send me and email using the actions below.
|
||||
</p>
|
||||
<p className="leading-loose">{t('builder.about.bugFeature.text')}</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<a
|
||||
@ -54,19 +44,27 @@ const About = () => {
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<Button icon={FaBug}>Raise an Issue</Button>
|
||||
<Button icon={FaBug}>{t('builder.about.bugFeature.button')}</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Source Code</h5>
|
||||
<h5>{t('builder.about.appreciate.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
Want to run the project from its source? Are you a developer willing
|
||||
to contribute to the open-source development of this project? Click
|
||||
the button below.
|
||||
</p>
|
||||
<p className="leading-loose">{t('builder.about.appreciate.text')}</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<a href="https://amruthpillai.com" rel="noreferrer" target="_blank">
|
||||
<Button icon={FaExternalLinkAlt}>amruthpillai.com</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>{t('builder.about.sourceCode.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">{t('builder.about.sourceCode.text')}</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<a
|
||||
@ -74,38 +72,20 @@ const About = () => {
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<Button icon={MdCode}>GitHub Repo</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>License Information</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
The project is governed under the MIT License, which you can read more
|
||||
about below. Basically, you are allowed to use the project anywhere
|
||||
provided you give credits to the original author.
|
||||
</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<a
|
||||
href="https://github.com/AmruthPillai/Reactive-Resume/blob/master/LICENSE"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<Button icon={MdCode}>MIT License</Button>
|
||||
<Button icon={MdCode}>
|
||||
{t('builder.about.sourceCode.button')}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="my-4 text-center opacity-50 text-sm">
|
||||
<p>
|
||||
Made with Love by{' '}
|
||||
<Trans t={t} i18nKey="builder.about.footer">
|
||||
A
|
||||
<a href="https://amruthpillai.com" rel="noreferrer" target="_blank">
|
||||
Amruth Pillai
|
||||
B
|
||||
</a>
|
||||
</p>
|
||||
</Trans>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import { FaFileExport, FaFileImport } from 'react-icons/fa';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ModalContext from '../../../../contexts/ModalContext';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import Button from '../../../shared/Button';
|
||||
@ -7,9 +8,15 @@ import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import styles from './Actions.module.css';
|
||||
|
||||
const Actions = () => {
|
||||
const [loadDemoText, setLoadDemoText] = useState('Load Demo Data');
|
||||
const [resetText, setResetText] = useState('Reset Everything');
|
||||
const Actions = ({ name }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [loadDemoText, setLoadDemoText] = useState(
|
||||
t('builder.actions.loadDemoData.button'),
|
||||
);
|
||||
const [resetText, setResetText] = useState(
|
||||
t('builder.actions.resetEverything.button'),
|
||||
);
|
||||
|
||||
const state = useSelector();
|
||||
const dispatch = useDispatch();
|
||||
@ -31,66 +38,57 @@ const Actions = () => {
|
||||
};
|
||||
|
||||
const handleLoadDemo = () => {
|
||||
if (loadDemoText === 'Load Demo Data') {
|
||||
setLoadDemoText('Are you sure?');
|
||||
if (loadDemoText === t('builder.actions.loadDemoData.button')) {
|
||||
setLoadDemoText(t('shared.buttons.confirmation'));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: 'load_demo_data' });
|
||||
setLoadDemoText('Load Demo Data');
|
||||
setLoadDemoText(t('builder.actions.loadDemoData.button'));
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
if (resetText === 'Reset Everything') {
|
||||
setResetText('Are you sure?');
|
||||
if (resetText === t('builder.actions.resetEverything.button')) {
|
||||
setResetText(t('shared.buttons.confirmation'));
|
||||
return;
|
||||
}
|
||||
|
||||
setResetText('Reset Everything');
|
||||
setResetText(t('builder.actions.resetEverything.button'));
|
||||
dispatch({ type: 'reset_data' });
|
||||
};
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>Actions</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Import Your Resume</h5>
|
||||
<h5>{t('builder.actions.import.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
You can import your information from various sources like JSON Resume
|
||||
or your LinkedIn to autofill most of the data for your resume.
|
||||
</p>
|
||||
<p className="leading-loose">{t('builder.actions.import.text')}</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<Button icon={FaFileImport} onClick={handleImport}>
|
||||
Import
|
||||
{t('builder.actions.import.button')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Export Your Resume</h5>
|
||||
<h5>{t('builder.actions.export.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
Export your resume as a PDF to share with recruiters or a JSON that
|
||||
you will be able to import back onto this app on another computer.
|
||||
</p>
|
||||
<p className="leading-loose">{t('builder.actions.export.text')}</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<Button icon={FaFileExport} onClick={handleExport}>
|
||||
Export
|
||||
{t('builder.actions.export.button')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Share Your Resume</h5>
|
||||
<h5>{t('builder.actions.share.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
The link below will be accessible publicly if you choose to share it,
|
||||
and viewers would see the latest version of your resume at any time.
|
||||
</p>
|
||||
<p className="leading-loose">{t('builder.actions.export.text')}</p>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
@ -102,11 +100,10 @@ const Actions = () => {
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Load Demo Data</h5>
|
||||
<h5>{t('builder.actions.loadDemoData.button')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
Unclear on what to do with a fresh blank page? Load some demo data to
|
||||
see how a resume should look and you can start editing from there.
|
||||
{t('builder.actions.loadDemoData.text')}
|
||||
</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
@ -115,11 +112,10 @@ const Actions = () => {
|
||||
</div>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Reset Everything</h5>
|
||||
<h5>{t('builder.actions.resetEverything.button')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
Feels like you made too many mistakes? No worries, clear everything
|
||||
with just one click, but be careful if there are no backups.
|
||||
{t('builder.actions.resetEverything.text')}
|
||||
</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
import React, { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch } from '../../../../contexts/ResumeContext';
|
||||
import colorOptions from '../../../../data/colorOptions';
|
||||
import { handleKeyUp } from '../../../../utils';
|
||||
@ -7,8 +8,9 @@ import Heading from '../../../shared/Heading';
|
||||
import Input from '../../../shared/Input';
|
||||
import styles from './Colors.module.css';
|
||||
|
||||
const Colors = () => {
|
||||
const Colors = ({ name }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClick = (value) => {
|
||||
dispatch({
|
||||
@ -22,7 +24,7 @@ const Colors = () => {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>Colors</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<div className="mb-6 grid grid-cols-8 col-gap-2 row-gap-6">
|
||||
{colorOptions.map((color) => (
|
||||
@ -41,7 +43,7 @@ const Colors = () => {
|
||||
<Input
|
||||
type="color"
|
||||
name="primary"
|
||||
label="Primary Color"
|
||||
label={t('builder.colors.primary')}
|
||||
placeholder="#FF4081"
|
||||
path="metadata.colors.primary"
|
||||
/>
|
||||
@ -49,7 +51,7 @@ const Colors = () => {
|
||||
<Input
|
||||
type="color"
|
||||
name="text"
|
||||
label="Text Color"
|
||||
label={t('builder.colors.text')}
|
||||
placeholder="#444444"
|
||||
path="metadata.colors.text"
|
||||
/>
|
||||
@ -57,7 +59,7 @@ const Colors = () => {
|
||||
<Input
|
||||
type="color"
|
||||
name="background"
|
||||
label="Background Color"
|
||||
label={t('builder.colors.background')}
|
||||
placeholder="#FFFFFF"
|
||||
path="metadata.colors.background"
|
||||
/>
|
||||
|
||||
@ -6,7 +6,7 @@ import { handleKeyUp } from '../../../../utils';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Fonts.module.css';
|
||||
|
||||
const Fonts = () => {
|
||||
const Fonts = ({ name }) => {
|
||||
const dispatch = useDispatch();
|
||||
const font = useSelector('metadata.font');
|
||||
|
||||
@ -22,7 +22,7 @@ const Fonts = () => {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>Fonts</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
{fontOptions.map((x) => (
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
import React, { memo, useState } from 'react';
|
||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import { move, reorder } from '../../../../utils';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Layout.module.css';
|
||||
|
||||
const Layout = () => {
|
||||
const [resetLayoutText, setResetLayoutText] = useState('Reset Layout');
|
||||
const Layout = ({ name }) => {
|
||||
const { t } = useTranslation();
|
||||
const [resetLayoutText, setResetLayoutText] = useState(
|
||||
t('builder.layout.reset'),
|
||||
);
|
||||
|
||||
const template = useSelector('metadata.template');
|
||||
const blocks = useSelector(`metadata.layout.${template}`, [[]]);
|
||||
@ -49,22 +53,21 @@ const Layout = () => {
|
||||
};
|
||||
|
||||
const handleResetLayout = () => {
|
||||
if (resetLayoutText === 'Reset Layout') {
|
||||
setResetLayoutText('Are you sure?');
|
||||
if (resetLayoutText === t('builder.layout.reset')) {
|
||||
setResetLayoutText(t('shared.buttons.confirmation'));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: 'reset_layout' });
|
||||
setResetLayoutText('Reset Layout');
|
||||
setResetLayoutText(t('builder.layout.reset'));
|
||||
};
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>Layout</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<p className="leading-loose">
|
||||
This template supports {blocks.length} blocks. You can re-order or move
|
||||
sections by dragging/dropping the section names across lists.
|
||||
{t('builder.layout.text', { count: blocks.length })}
|
||||
</p>
|
||||
|
||||
<div className={`grid gap-8 grid-cols-${blocks.length}`}>
|
||||
@ -79,7 +82,7 @@ const Layout = () => {
|
||||
>
|
||||
<div className="grid gap-3">
|
||||
<span className="uppercase font-semibold text-xs">
|
||||
Block {ind + 1}
|
||||
{t('builder.layout.block')} {ind + 1}
|
||||
</span>
|
||||
{el.map((item, index) => (
|
||||
<Draggable key={item} index={index} draggableId={item}>
|
||||
@ -90,7 +93,7 @@ const Layout = () => {
|
||||
{...dragProvided.draggableProps}
|
||||
{...dragProvided.dragHandleProps}
|
||||
>
|
||||
{item}
|
||||
{t(`builder.sections.${item}`)}
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
}
|
||||
|
||||
.draggable {
|
||||
@apply px-4 py-2 capitalize font-medium rounded bg-primary-200;
|
||||
@apply px-4 py-2 font-medium rounded bg-primary-200;
|
||||
}
|
||||
|
||||
@ -1,30 +1,42 @@
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import { FaAngleDown } from 'react-icons/fa';
|
||||
import { useTranslation, Trans } from 'react-i18next';
|
||||
import UserContext from '../../../../contexts/UserContext';
|
||||
import Button from '../../../shared/Button';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Settings.module.css';
|
||||
import Input from '../../../shared/Input';
|
||||
import ThemeContext from '../../../../contexts/ThemeContext';
|
||||
import SettingsContext from '../../../../contexts/SettingsContext';
|
||||
import themeConfig from '../../../../data/themeConfig';
|
||||
import languageConfig from '../../../../data/languageConfig';
|
||||
import { languages } from '../../../../i18n';
|
||||
import { useDispatch } from '../../../../contexts/ResumeContext';
|
||||
|
||||
const Settings = () => {
|
||||
const [deleteText, setDeleteText] = useState('Delete Account');
|
||||
const Settings = ({ name }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [deleteText, setDeleteText] = useState(
|
||||
t('builder.settings.dangerZone.button'),
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { deleteAccount } = useContext(UserContext);
|
||||
const { theme, setTheme } = useContext(ThemeContext);
|
||||
const { theme, setTheme, language, setLanguage } = useContext(
|
||||
SettingsContext,
|
||||
);
|
||||
|
||||
const handleChangeTheme = (e) => {
|
||||
setTheme(e.target.value);
|
||||
};
|
||||
|
||||
const handleChangeLanguage = (e) => {
|
||||
console.log(e.target.value);
|
||||
const lang = e.target.value;
|
||||
setLanguage(lang);
|
||||
dispatch({ type: 'change_language', payload: lang });
|
||||
};
|
||||
|
||||
const handleDeleteAccount = () => {
|
||||
if (deleteText === 'Delete Account') {
|
||||
setDeleteText('Are you sure?');
|
||||
if (deleteText === t('builder.settings.dangerZone.button')) {
|
||||
setDeleteText(t('shared.buttons.confirmation'));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -36,10 +48,10 @@ const Settings = () => {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>Settings</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<Input
|
||||
label="Theme"
|
||||
label={t('builder.settings.theme')}
|
||||
type="dropdown"
|
||||
options={Object.keys(themeConfig)}
|
||||
value={theme}
|
||||
@ -47,11 +59,11 @@ const Settings = () => {
|
||||
/>
|
||||
|
||||
<label>
|
||||
<span>Language</span>
|
||||
<span>{t('builder.settings.language')}</span>
|
||||
<div className="relative grid items-center">
|
||||
<select onChange={handleChangeLanguage}>
|
||||
{languageConfig.map((x) => (
|
||||
<option key={x.key} value={x.key}>
|
||||
<select onChange={handleChangeLanguage} value={language}>
|
||||
{languages.map((x) => (
|
||||
<option key={x.code} value={x.code}>
|
||||
{x.name}
|
||||
</option>
|
||||
))}
|
||||
@ -65,26 +77,23 @@ const Settings = () => {
|
||||
</label>
|
||||
|
||||
<p className="text-sm leading-loose">
|
||||
If you would like to contribute by providing translations to Reactive
|
||||
Resume in your language,{' '}
|
||||
<a
|
||||
href="https://github.com/AmruthPillai/Reactive-Resume/blob/master/TRANSLATING.md"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
please visit this link
|
||||
</a>
|
||||
.
|
||||
<Trans t={t} i18nKey="builder.settings.translate">
|
||||
A
|
||||
<a
|
||||
href="https://github.com/AmruthPillai/Reactive-Resume/blob/master/TRANSLATING.md"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
B
|
||||
</a>
|
||||
C
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.container}>
|
||||
<h5>Danger Zone</h5>
|
||||
<h5>{t('builder.settings.dangerZone.heading')}</h5>
|
||||
|
||||
<p className="leading-loose">
|
||||
If you would like to delete your account and erase all your resumes,
|
||||
it’s just one button away. Please be weary as this is an irreversible
|
||||
process.
|
||||
</p>
|
||||
<p className="leading-loose">{t('builder.settings.dangerZone.text')}</p>
|
||||
|
||||
<div className="mt-4 flex">
|
||||
<Button isDelete onClick={handleDeleteAccount}>
|
||||
|
||||
@ -8,7 +8,7 @@ import { handleKeyUp } from '../../../../utils';
|
||||
import Heading from '../../../shared/Heading';
|
||||
import styles from './Templates.module.css';
|
||||
|
||||
const Templates = () => {
|
||||
const Templates = ({ name }) => {
|
||||
const dispatch = useDispatch();
|
||||
const template = useSelector('metadata.template');
|
||||
|
||||
@ -71,7 +71,7 @@ const Templates = () => {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading>Templates</Heading>
|
||||
<Heading>{name}</Heading>
|
||||
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
{templateOptions.map((x) => (
|
||||
|
||||
Reference in New Issue
Block a user