mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-09 20:12:26 +10:00
- creating the right sidebar
- designing the artboard - optimizing dark mode performance - optimizing input onChange handler
This commit is contained in:
@ -3,6 +3,7 @@ import "firebase/analytics";
|
||||
import "firebase/auth";
|
||||
import "firebase/firestore";
|
||||
import React from "react";
|
||||
import { DashboardProvider } from "./src/contexts/DashboardContext";
|
||||
import { ModalProvider } from "./src/contexts/ModalContext";
|
||||
import { ResumeProvider } from "./src/contexts/ResumeContext";
|
||||
import { ThemeProvider } from "./src/contexts/ThemeContext";
|
||||
@ -25,7 +26,9 @@ export const wrapRootElement = ({ element }) => (
|
||||
<MuiThemeProvider theme={theme}>
|
||||
<ModalProvider>
|
||||
<UserProvider>
|
||||
<ResumeProvider>{element}</ResumeProvider>
|
||||
<DashboardProvider>
|
||||
<ResumeProvider>{element}</ResumeProvider>
|
||||
</DashboardProvider>
|
||||
</UserProvider>
|
||||
</ModalProvider>
|
||||
</MuiThemeProvider>
|
||||
|
||||
8
src/components/builder/center/Artboard.js
Normal file
8
src/components/builder/center/Artboard.js
Normal file
@ -0,0 +1,8 @@
|
||||
import React from "react";
|
||||
import styles from "./Artboard.module.css";
|
||||
|
||||
const Artboard = () => {
|
||||
return <div className={styles.container}></div>;
|
||||
};
|
||||
|
||||
export default Artboard;
|
||||
6
src/components/builder/center/Artboard.module.css
Normal file
6
src/components/builder/center/Artboard.module.css
Normal file
@ -0,0 +1,6 @@
|
||||
.container {
|
||||
width: 400px;
|
||||
height: 600px;
|
||||
box-shadow: var(--shadow);
|
||||
@apply bg-white;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { Link } from "gatsby";
|
||||
import React from "react";
|
||||
import { MdPerson } from "react-icons/md";
|
||||
import Avatar from "../../shared/Avatar";
|
||||
import Logo from "../../shared/Logo";
|
||||
import styles from "./LeftNavbar.module.css";
|
||||
@ -11,9 +12,16 @@ const LeftNavbar = () => {
|
||||
<Logo size="40px" />
|
||||
</Link>
|
||||
|
||||
<hr className="my-4" />
|
||||
<hr className="my-6" />
|
||||
|
||||
<hr className="mt-auto my-4" />
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
<MdPerson
|
||||
className="text-secondary-dark hover:text-primary"
|
||||
size="20px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<hr className="mt-auto my-6" />
|
||||
|
||||
<Avatar />
|
||||
</div>
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
width: 75px;
|
||||
z-index: 20;
|
||||
box-shadow: var(--left-shadow);
|
||||
@apply p-4 h-screen flex flex-col items-center;
|
||||
@apply px-4 py-6 h-screen flex flex-col items-center;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import Input from "../../shared/Input";
|
||||
import Profile from "../sections/Profile";
|
||||
import LeftNavbar from "./LeftNavbar";
|
||||
import styles from "./LeftSidebar.module.css";
|
||||
|
||||
@ -9,13 +9,7 @@ const LeftSidebar = () => {
|
||||
<LeftNavbar />
|
||||
|
||||
<div className={styles.container}>
|
||||
<section>
|
||||
<h2 className="text-4xl mb-8">Profile</h2>
|
||||
<div className="flex items-center">
|
||||
<div className={styles.circle}></div>
|
||||
<Input label="Photograph" className="ml-6" />
|
||||
</div>
|
||||
</section>
|
||||
<Profile />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -3,10 +3,3 @@
|
||||
box-shadow: var(--left-shadow);
|
||||
@apply w-full h-screen p-8;
|
||||
}
|
||||
|
||||
.circle {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
flex: 0 0 60px;
|
||||
@apply bg-gray-300 rounded-full;
|
||||
}
|
||||
|
||||
18
src/components/builder/right/RightNavbar.js
Normal file
18
src/components/builder/right/RightNavbar.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
import { MdPerson } from "react-icons/md";
|
||||
import styles from "./RightNavbar.module.css";
|
||||
|
||||
const RightNavbar = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
<MdPerson
|
||||
className="text-secondary-dark hover:text-primary"
|
||||
size="20px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RightNavbar;
|
||||
6
src/components/builder/right/RightNavbar.module.css
Normal file
6
src/components/builder/right/RightNavbar.module.css
Normal file
@ -0,0 +1,6 @@
|
||||
.container {
|
||||
width: 75px;
|
||||
z-index: 20;
|
||||
box-shadow: var(--right-shadow);
|
||||
@apply px-4 py-6 h-screen flex flex-col items-center;
|
||||
}
|
||||
18
src/components/builder/right/RightSidebar.js
Normal file
18
src/components/builder/right/RightSidebar.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
import Profile from "../sections/Profile";
|
||||
import RightNavbar from "./RightNavbar";
|
||||
import styles from "./RightSidebar.module.css";
|
||||
|
||||
const RightSidebar = () => {
|
||||
return (
|
||||
<div className="flex">
|
||||
<div className={styles.container}>
|
||||
<Profile />
|
||||
</div>
|
||||
|
||||
<RightNavbar />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RightSidebar;
|
||||
5
src/components/builder/right/RightSidebar.module.css
Normal file
5
src/components/builder/right/RightSidebar.module.css
Normal file
@ -0,0 +1,5 @@
|
||||
.container {
|
||||
z-index: 10;
|
||||
box-shadow: var(--right-shadow);
|
||||
@apply w-full h-screen p-8;
|
||||
}
|
||||
27
src/components/builder/sections/Profile.js
Normal file
27
src/components/builder/sections/Profile.js
Normal file
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import { MdFileUpload } from "react-icons/md";
|
||||
import Heading from "../../shared/Heading";
|
||||
import Input from "../../shared/Input";
|
||||
import styles from "./Profile.module.css";
|
||||
|
||||
const Profile = () => {
|
||||
return (
|
||||
<section>
|
||||
<Heading>Profile</Heading>
|
||||
<div className="flex items-center">
|
||||
<div className={styles.circle}>
|
||||
<MdFileUpload size="22px" className="text-secondary-dark" />
|
||||
</div>
|
||||
|
||||
<Input label="Photograph" className="ml-6" path="profile.photograph" />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<Input label="First Name" path="profile.firstName" />
|
||||
<Input label="Last Name" path="profile.lastName" />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Profile;
|
||||
6
src/components/builder/sections/Profile.module.css
Normal file
6
src/components/builder/sections/Profile.module.css
Normal file
@ -0,0 +1,6 @@
|
||||
.circle {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
flex: 0 0 60px;
|
||||
@apply flex items-center justify-center bg-secondary rounded-full;
|
||||
}
|
||||
@ -12,7 +12,7 @@
|
||||
.resume > .page {
|
||||
max-width: 184px;
|
||||
height: 260px;
|
||||
@apply rounded absolute w-full bg-white;
|
||||
@apply rounded absolute w-full bg-inverse;
|
||||
@apply transition-opacity duration-200 ease-in-out;
|
||||
@apply cursor-pointer absolute text-gray-500 flex justify-center items-center;
|
||||
}
|
||||
|
||||
@ -4,14 +4,14 @@ import moment from "moment";
|
||||
import React, { useContext, useState } from "react";
|
||||
import { MdMoreHoriz, MdOpenInNew } from "react-icons/md";
|
||||
import { toast } from "react-toastify";
|
||||
import DashboardContext from "../../contexts/DashboardContext";
|
||||
import ModalContext from "../../contexts/ModalContext";
|
||||
import ResumeContext from "../../contexts/ResumeContext";
|
||||
import styles from "./ResumePreview.module.css";
|
||||
|
||||
const ResumePreview = ({ resume }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const { createResumeModal } = useContext(ModalContext);
|
||||
const { deleteResume } = useContext(ResumeContext);
|
||||
const { deleteResume } = useContext(DashboardContext);
|
||||
|
||||
const handleOpen = () => navigate(`/app/builder/${resume.id}`);
|
||||
|
||||
|
||||
7
src/components/shared/Heading.js
Normal file
7
src/components/shared/Heading.js
Normal file
@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
const Heading = ({ children }) => {
|
||||
return <h2 className="text-4xl">{children}</h2>;
|
||||
};
|
||||
|
||||
export default Heading;
|
||||
@ -1,11 +1,14 @@
|
||||
import cx from "classnames";
|
||||
import React from "react";
|
||||
import { get } from "lodash";
|
||||
import React, { useContext } from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import ResumeContext from "../../contexts/ResumeContext";
|
||||
import styles from "./Input.module.css";
|
||||
|
||||
const Input = ({
|
||||
label,
|
||||
name,
|
||||
path,
|
||||
label,
|
||||
value,
|
||||
error,
|
||||
onChange,
|
||||
@ -14,6 +17,20 @@ const Input = ({
|
||||
type = "text",
|
||||
}) => {
|
||||
const uuid = uuidv4();
|
||||
const { state, dispatch } = useContext(ResumeContext);
|
||||
|
||||
const inputProps = (path) => ({
|
||||
value: get(state, path),
|
||||
onChange: (e) => {
|
||||
dispatch({
|
||||
type: "on_input",
|
||||
payload: {
|
||||
path,
|
||||
value: e.target.value,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={cx(styles.container, className)}>
|
||||
@ -26,8 +43,9 @@ const Input = ({
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
{...(path && inputProps(path))}
|
||||
/>
|
||||
<p className="mt-1 text-red-600 text-sm">{error}</p>
|
||||
<p>{error}</p>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -7,13 +7,21 @@
|
||||
}
|
||||
|
||||
.container > label > span {
|
||||
@apply mb-1 text-gray-600 font-medium text-sm uppercase;
|
||||
@apply mb-1 text-secondary-dark font-medium text-xs uppercase;
|
||||
}
|
||||
|
||||
.container > label > input {
|
||||
@apply py-4 px-4 rounded bg-gray-200 border border-gray-200;
|
||||
@apply py-3 px-4 rounded bg-secondary text-primary border border-secondary;
|
||||
}
|
||||
|
||||
.container > label > input::placeholder {
|
||||
@apply text-primary opacity-50;
|
||||
}
|
||||
|
||||
.container > label > input:focus {
|
||||
@apply outline-none border-gray-400;
|
||||
@apply outline-none border-secondary-dark;
|
||||
}
|
||||
|
||||
.container > label > p {
|
||||
@apply mt-1 text-red-600 text-xs;
|
||||
}
|
||||
|
||||
81
src/contexts/DashboardContext.js
Normal file
81
src/contexts/DashboardContext.js
Normal file
@ -0,0 +1,81 @@
|
||||
import firebase from "gatsby-plugin-firebase";
|
||||
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { transformCollectionSnapshot } from "../utils";
|
||||
import UserContext from "./UserContext";
|
||||
|
||||
const defaultState = {
|
||||
resumes: [],
|
||||
createResume: async () => {},
|
||||
deleteResume: async () => {},
|
||||
};
|
||||
|
||||
const DashboardContext = createContext(defaultState);
|
||||
|
||||
const DashboardProvider = ({ children }) => {
|
||||
const [resumes, setResumes] = useState([null]);
|
||||
const [collectionRef, setCollectionRef] = useState(null);
|
||||
const { user } = useContext(UserContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
setCollectionRef(`users/${user.uid}/resumes`);
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (collectionRef) {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(collectionRef)
|
||||
.onSnapshot((snapshot) =>
|
||||
transformCollectionSnapshot(snapshot, setResumes)
|
||||
);
|
||||
}
|
||||
}, [collectionRef]);
|
||||
|
||||
const createResume = async ({ name }) => {
|
||||
const id = uuidv4();
|
||||
const createdAt = firebase.firestore.FieldValue.serverTimestamp();
|
||||
await firebase.firestore().collection(collectionRef).doc(id).set({
|
||||
id,
|
||||
name,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
});
|
||||
};
|
||||
|
||||
const updateResume = async (resume) => {
|
||||
const { id, name } = resume;
|
||||
|
||||
if (resumes.find((x) => x.id === id) === resume) return;
|
||||
|
||||
await firebase.firestore().collection(collectionRef).doc(id).update({
|
||||
id,
|
||||
name,
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
});
|
||||
};
|
||||
|
||||
const deleteResume = async (resume) => {
|
||||
const { id } = resume;
|
||||
await firebase.firestore().collection(collectionRef).doc(id).delete();
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardContext.Provider
|
||||
value={{
|
||||
resumes,
|
||||
createResume,
|
||||
updateResume,
|
||||
deleteResume,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DashboardContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardContext;
|
||||
|
||||
export { DashboardProvider };
|
||||
@ -1,76 +1,28 @@
|
||||
import firebase from "gatsby-plugin-firebase";
|
||||
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { transformCollectionSnapshot } from "../utils";
|
||||
import UserContext from "./UserContext";
|
||||
import { set } from "lodash";
|
||||
import React, { createContext, useReducer } from "react";
|
||||
|
||||
const defaultState = {
|
||||
resumes: [],
|
||||
createResume: async () => {},
|
||||
deleteResume: async () => {},
|
||||
const initialState = {
|
||||
profile: {
|
||||
photograph: "",
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
},
|
||||
};
|
||||
|
||||
const ResumeContext = createContext(defaultState);
|
||||
const ResumeContext = createContext(initialState);
|
||||
|
||||
const ResumeProvider = ({ children }) => {
|
||||
const [resumes, setResumes] = useState([null]);
|
||||
const [collectionRef, setCollectionRef] = useState(null);
|
||||
const { user } = useContext(UserContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
setCollectionRef(`users/${user.uid}/resumes`);
|
||||
const [state, dispatch] = useReducer((state, { type, payload }) => {
|
||||
switch (type) {
|
||||
case "on_input":
|
||||
return set({ ...state }, payload.path, payload.value);
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (collectionRef) {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection(collectionRef)
|
||||
.onSnapshot((snapshot) =>
|
||||
transformCollectionSnapshot(snapshot, setResumes)
|
||||
);
|
||||
}
|
||||
}, [collectionRef]);
|
||||
|
||||
const createResume = async ({ name }) => {
|
||||
const id = uuidv4();
|
||||
const createdAt = firebase.firestore.FieldValue.serverTimestamp();
|
||||
await firebase.firestore().collection(collectionRef).doc(id).set({
|
||||
id,
|
||||
name,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
});
|
||||
};
|
||||
|
||||
const updateResume = async (resume) => {
|
||||
const { id, name } = resume;
|
||||
|
||||
if (resumes.find((x) => x.id === id) === resume) return;
|
||||
|
||||
await firebase.firestore().collection(collectionRef).doc(id).update({
|
||||
id,
|
||||
name,
|
||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
});
|
||||
};
|
||||
|
||||
const deleteResume = async (resume) => {
|
||||
const { id } = resume;
|
||||
await firebase.firestore().collection(collectionRef).doc(id).delete();
|
||||
};
|
||||
}, initialState);
|
||||
|
||||
return (
|
||||
<ResumeContext.Provider
|
||||
value={{
|
||||
resumes,
|
||||
createResume,
|
||||
updateResume,
|
||||
deleteResume,
|
||||
}}
|
||||
>
|
||||
<ResumeContext.Provider value={{ state, dispatch }}>
|
||||
{children}
|
||||
</ResumeContext.Provider>
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, createContext } from "react";
|
||||
import React, { createContext, useEffect, useState } from "react";
|
||||
|
||||
const COLOR_CONFIG = {
|
||||
light: {
|
||||
@ -6,12 +6,16 @@ const COLOR_CONFIG = {
|
||||
"--color-primary-dark": "#333",
|
||||
"--color-inverse": "#fff",
|
||||
"--color-inverse-dark": "#f5f5f5",
|
||||
"--color-secondary": "#edf2f7",
|
||||
"--color-secondary-dark": "#718096",
|
||||
},
|
||||
dark: {
|
||||
"--color-primary": "#f5f5f5",
|
||||
"--color-primary-dark": "#eee",
|
||||
"--color-primary-dark": "#eeeeee",
|
||||
"--color-inverse": "#212121",
|
||||
"--color-inverse-dark": "#181818",
|
||||
"--color-secondary": "#444",
|
||||
"--color-secondary-dark": "#888",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@ import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import * as Yup from "yup";
|
||||
import Button from "../components/shared/Button";
|
||||
import Input from "../components/shared/Input";
|
||||
import DashboardContext from "../contexts/DashboardContext";
|
||||
import ModalContext from "../contexts/ModalContext";
|
||||
import ResumeContext from "../contexts/ResumeContext";
|
||||
import { getModalText } from "../utils";
|
||||
import BaseModal from "./BaseModal";
|
||||
|
||||
@ -18,7 +18,7 @@ const CreateResumeModal = ({ data }) => {
|
||||
const modalRef = useRef(null);
|
||||
const [isEditMode, setEditMode] = useState(false);
|
||||
const { createResumeModal } = useContext(ModalContext);
|
||||
const { createResume, updateResume } = useContext(ResumeContext);
|
||||
const { createResume, updateResume } = useContext(DashboardContext);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
import React from "react";
|
||||
import Artboard from "../../components/builder/center/Artboard";
|
||||
import LeftSidebar from "../../components/builder/left/LeftSidebar";
|
||||
import RightSidebar from "../../components/builder/right/RightSidebar";
|
||||
import Wrapper from "../../components/shared/Wrapper";
|
||||
|
||||
const Builder = ({ id }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<div className="h-screen grid grid-cols-12">
|
||||
<div className="h-screen grid grid-cols-11">
|
||||
<div className="col-span-3">
|
||||
<LeftSidebar />
|
||||
</div>
|
||||
<div className="col-span-6"></div>
|
||||
<div className="col-span-3"></div>
|
||||
<div className="col-span-5 bg-inverse-dark flex items-center justify-center">
|
||||
<Artboard />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<RightSidebar />
|
||||
</div>
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import React, { useContext } from "react";
|
||||
import Wrapper from "../../components/shared/Wrapper";
|
||||
import CreateResume from "../../components/dashboard/CreateResume";
|
||||
import ResumePreview from "../../components/dashboard/ResumePreview";
|
||||
import TopNavbar from "../../components/dashboard/TopNavbar";
|
||||
import ResumeContext from "../../contexts/ResumeContext";
|
||||
import Wrapper from "../../components/shared/Wrapper";
|
||||
import DashboardContext from "../../contexts/DashboardContext";
|
||||
|
||||
const Dashboard = () => {
|
||||
const { resumes } = useContext(ResumeContext);
|
||||
const { resumes } = useContext(DashboardContext);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
|
||||
@ -3,4 +3,6 @@
|
||||
--color-primary-dark: #333;
|
||||
--color-inverse: #fff;
|
||||
--color-inverse-dark: #f5f5f5;
|
||||
--color-secondary: #edf2f7;
|
||||
--color-secondary-dark: #718096;
|
||||
}
|
||||
|
||||
@ -24,5 +24,9 @@ a:hover {
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply w-full h-1;
|
||||
@apply w-full border-secondary h-1;
|
||||
}
|
||||
|
||||
section {
|
||||
@apply grid grid-cols-1 gap-8;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
:root {
|
||||
--shadow: 0 0 8px 0 rgba(0, 0, 0, 0.04);
|
||||
--shadow-strong: 0 0 8px 0 rgba(0, 0, 0, 0.08);
|
||||
--left-shadow: 8px 0 8px -4px rgba(0, 0, 0, 0.04);
|
||||
--bottom-shadow: 0 8px 8px -4px rgba(0, 0, 0, 0.04);
|
||||
--shadow: 0 0 6px 0 rgba(0, 0, 0, 0.05);
|
||||
--shadow-strong: 0 0 6px 0 rgba(0, 0, 0, 0.1);
|
||||
--left-shadow: 6px 0 6px -6px rgba(0, 0, 0, 0.05);
|
||||
--right-shadow: -6px 0 6px -6px rgba(0, 0, 0, 0.05);
|
||||
--bottom-shadow: 0 6px 6px -6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ module.exports = {
|
||||
"primary-dark": "var(--color-primary-dark)",
|
||||
inverse: "var(--color-inverse)",
|
||||
"inverse-dark": "var(--color-inverse-dark)",
|
||||
secondary: "var(--color-secondary)",
|
||||
"secondary-dark": "var(--color-secondary-dark)",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user