The theme I’m working on can be found here.
Inspired by the great work of @Segun on their Chakra UI Frontity Theme, I decided that I wanted to better abstract aspects of my theme to variables set in it’s settings.
So in src/index.js there is the theme JS object:
import Theme from "./components";
import image from "@frontity/html2react/processors/image";
const desertJackalope = {
name: "desert-jackalope",
roots: {
// In Frontity, any package can add React components to the site.
// We use roots for that, scoped to the "theme" namespace.
theme: Theme
},
state: {
// State is where the packages store their default settings and other
// relevant state. It is scoped to the "theme" namespace.
theme: {
isBlog: false,
colors: {
primary: {
default: "#2657eb",
heavy: "#1f38c5"
}
}
}
},
// Actions are functions that modify the state or deal with other parts of
// Frontity like libraries.
actions: {
theme: {}
},
libraries: {
html2react: {
// Add a processor to html2react so it processes the <img> tags
// inside the content HTML. You can add your own processors too.
processors: [image]
}
}
};
export default desertJackalope;
As you can see I have added a couple of key-value pairs to the theme object. isBlog
determines whether or not the website is set to “blog” mode or if it’s set to “case study mode”. I also set some default theme colors.
isBlog
works fine, and as intended which you can see an example of it’s use in src/components/archive/archive.js:
import React from "react";
import { connect } from "frontity";
import BlogArchive from "./BlogArchive";
import CaseStudyArchive from "./CaseStudyArchive";
const Archive = ({ state, data }) => {
// check whether or not blog or case study presentation
return (
<>
{state.theme.isBlog ? (
<BlogArchive data={data} />
) : (
<CaseStudyArchive data={data} />
)}
</>
);
};
export default connect(Archive);
However when I try to add the colors to my global css in src/components/index.js, I get a result of undefined. This is how the code currently looks. You can see my commented out attempts at directly importing desertJackalope (the name of the JS object in my src/index.js file) and my attempt at setting the value of desertJackalope.theme.colors.primary.default
to the const primaryColor
.
import React from "react";
import { Global, css, connect, styled } from "frontity";
import Header from "./Header";
import Archive from "./Archive";
import Post from "./Post";
import Page404 from "./Page404";
import Page from "./Page";
import Loading from "./Loading";
import { useTransition, animated } from "react-spring";
import Meta from "./Meta";
import { colors } from "../theme";
import Footer from "./Footer";
//import desertJackalope from "../index";
//const primaryColor = desertJackalope.theme.colors.primary.default;
const Theme = ({ state }) => {
const transitions = useTransition(state.router.link, link => link, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
});
return (
<>
<Meta />
<Global styles={globalStyles} />
<Header />
{transitions.map(({ item, props, key }) => {
const data = state.source.get(item);
return (
<animated.div key={key} style={props}>
<Absolute>
{(data.isFetching && <Loading />) ||
(data.isArchive && <Archive data={data} />) ||
(data.isPage && <Page data={data} />) ||
(data.isPostType && <Post data={data} />) ||
(data.is404 && <Page404 />)}
</Absolute>
</animated.div>
);
})}
{/* <Footer /> */}
</>
);
};
export default connect(Theme);
//- GLOBAL STYLES CSS
//- Color vars
const primaryColor = colors.primary.default;
const heavyprimaryColor = colors.primary.heavy;
const accentColor = colors.accent;
const darkColor = colors.dark[100];
const darkColor90 = colors.dark[90];
const darkColor80 = colors.dark[80];
const darkColor30 = colors.dark[30];
// set global styles
const globalStyles = css`
@import url("https://fonts.googleapis.com/css?family=Space+Mono:400,400i,700,700i&display=swap");
:root {
--primary-heavy: ${heavyprimaryColor};
--primary: ${primaryColor};
--snappy: cubic-bezier(0.075, 0.82, 0.165, 1);
--heavy-snap: cubic-bezier(0.6, -0.28, 0.735, 0.045);
--accent: ${accentColor};
--dark: ${darkColor};
--dark90: ${darkColor90};
--dark80: ${darkColor80};
--dark30: ${darkColor30};
*::selection {
background: var(--primary);
color: white;
}
}
body {
margin: 0;
font-family: "Space Mono", "Segoe UI", Roboto, "Droid Sans",
"Helvetica Neue", Helvetica, Arial, sans-serif;
box-sizing: border-box;
}
a,
a:visited {
color: inherit;
text-decoration: none;
}
`;
//- Page Transition stuff
const Absolute = styled.div`
position: absolute;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
`;
Directly referencing the desertJackalope.state.theme.colors.primary.default
value does not work. It does work when inserted into a component, because all components created inherit state, but trying to set desertJackalope.state.theme.colors.primary.default
to const primaryColor
and then setting the css variable in global state root to ${primaryColor}
results in a react error saying that “primaryColor is undefined”.
If instead I create a JS object in src/theme.js called “colors” and I set it such that colors.primary.default is my default color, and then import the colors object to src/index.js and set const primaryColor
to colors.primary.default
, I can then set the css global root variable to ${primaryColor}
then it works no problem… and I’m not clear why.
Setting all my theme color settings in src/theme.js isn’t too bad but it does mean that I can’t have the option of setting default color settings in my src/index.js file with the option of being overridden by the frontity.settings.js file (as I can do with the isBlog value very easily).
Segun sets his colors in his src/index.js file but he passes all colors to his components via prop drilling. So it works because those components inherit state. But for some reason when I try passing the contents of desertJackalope.state.theme etc to a const and pass that into CSS variables it does not work.
I find prop drilling messy, and I would prefer to abstract/alias my theme colors via my custom src/theme.js file than have to muck up my component markup with a bunch of color variables.
I assume this problem is caused by how frontity is handling the src/index.js object. Clearly the object gets some kind of interaction as the default state set in that file can be overridden by frontity.settings.js but I’m not clear how, and if however it is doing it is preventing me from aliasing and including my theme colors the way that I want to.
Does this make sense?