I am trying to dynamically assign a background color to a div using gatsby JS. Everything works well in development but after running a build, the page is static and does not change styles dynamically anymore (same with classes). Please take a quick look at this:
let currentTime = new Date().toTimeString()
return (
<React.Fragment>
<div
style={{
background: parseInt(currentTime[7]) % 2 == 0 ? "green" : "yellow",
}}
>
{currentTime}
</div>
</React.Fragment>
)
When built, the text renders the current Time correctly, however the style of the div stays static to whatever style gatsby assigned based on the time in the moment of building.
The UseCase for this will be to have a traffic light system to display if a shop is currently open (by comparing opening times to current time)
I am very thankful for any help. :)
Import { newGlobalColor } from "styled-components"
const changeDivColor = newGlobalColor`
body {
color : ${props => (props.theme ? "yellow" : "green")};
}`
let currentTime = parseInt( new Date().toTimeString()[7])%2;
let return (
<React.Fragment>
<changeDivColor theme={{currentTime}} />
<div>{currentTime}</div>
</React.Fragment>
)
According to docs, it should work with styled-components (https://www.gatsbyjs.org/docs/css-in-js/).
Additionally, you could try to do your magic in gatsby-browser config. (https://www.gatsbyjs.org/docs/api-files-gatsby-browser/)
Related
I came across the Component Composition Design Pattern in React, which is said by the tutor to be analogue to inheritance in OOP.
My question is, if I want to extend the defined props of the Button, how do you do this?!
SIDE NOTE: I know you would do this with CSS in the first place, but I
ran outta ideas to customize the tutor's example.
In the second code snippet I tried adding both, borderColor: "blue" and color="red" to the style attribute of the BigSuccessButton to try different approaches of appending stuff.
But with the style attribute the entire content defined in the Button Component will be killed. So I will only see blue borders.
So I thought of adding a new prop and using it.
But if last mentioned is the way to do this, how can I append this thing?
Those are the Composition Components, with Button being the Super Class:
export const Button = ({ size, bgColor, text, ...props }) => {
console.log(props);
return (
<button
style={{
padding: size === "large" ? "32px" : "8px",
fontSize: size === "large" ? "32px" : "16px",
backgroundColor: bgColor,
}}
{...props}
>
{text}
</button>
);
};
export const DangerButton = (props) => {
return <Button {...props} bgColor="red" />;
};
export const BigSuccessButton = (props) => {
return (
<Button
{...props}
size="large"
bgColor="green"
/>
);
};
Here I wanna add text color to BigSuccessButton:
import { BigSuccessButton, DangerButton } from "./Composition";
function App_FuncProg() {
return (
<>
{/* <RecursiveComponent data={nestedObject} /> */}
<DangerButton text="Danger" />
<BigSuccessButton text="Yippieh!" style={{borderColor: "blue"}} color="red" />
</>
);
}
export default App_FuncProg;
You've kind of mixed two patterns -- passing props and mapping them into styles; and trying to override the style prop. Passing props probably isnt the way because you dont want to end up having to map new props to the style object every single time you want to customize a new property (though design system libraries like Chakra do do this internally, but its comprehensive and you don't want to reinvent the whole wheel here).
That said, your mapping of size is more acceptable because it actually has semantic meaning, it actually does something (picking the pixel size of fontSize and padding). So I kept that part.
What you really want here I think is to add support for merging the style prop.
This sort of "pass through" approach gives you a high degree of flexibility at low cost by exposing the entire style CSS api to the parents; whilst at the same time, retaining the default styling. The downside is its maybe a little more ugly. Sometimes, if you want more control, you'd go purely with the mapping approach and add specific support via dev-defined props for the things you want exposed. Like you did with the size prop. It really depends on what you want your component API to look like.
A smaller thing: you really want to spread the props after the default ones if you want them to be overridable. The order matters.
export const Button = ({ text, size, style, ...props }) => {
console.log(props);
return (
<button
style={{
padding: size === "large" ? "32px" : "8px",
fontSize: size === "large" ? "32px" : "16px",
...style,
}}
{...props}
>
{text}
</button>
);
};
export const DangerButton = ({style, ...props}) => {
return <Button style={{backgroundColor: 'red', ...style}} {...props}/>;
};
export const BigSuccessButton = ({style, ...props}) => {
return (
<Button
size="large"
style={{backgroundColor: 'green', ...style}}
{...props}
/>
);
};
import { BigSuccessButton, DangerButton } from "./Composition";
function App_FuncProg() {
return (
<>
{/* <RecursiveComponent data={nestedObject} /> */}
<DangerButton text="Danger" />
<BigSuccessButton text="Yippieh!" style={{borderColor: "blue", color: 'red'}} />
</>
);
}
export default App_FuncProg;
An example of the opposing "first class props styling api" approach is Chakras api: https://chakra-ui.com/docs/styled-system/style-props. But again, this is obviously a very complete third party library and theyve spent a lot of time making this nice to use and expose every single option.
SIDE NOTE: I know you would do this with CSS in the first place, but I ran outta ideas to customize the tutor's example.
To be honest, in react, you don't usually go with separate CSS files like this. "CSS-in-JS" is now the norm. So inline styling like this is actually quite normal and not frowned on. There's whole libraries built around the philosophy (not necessarily using style attribute, but embedding the CSS in the component -- these things are complex and inject CSS into the DOM and then dynamically create class attributes). Have a look at styled-components and emotion. And Chakra etc has their own baked in based on things like emotion also.
I have a lot of components I need to get a value called "values" from the SideBarBlurChange component to the SideBar component. I drew a diagram of my components so you can navigate easier
I read articles and how I understood there are two main options, the first is "Lifting State Up" and the second is "Redux" or "Context". I tried to apply these approaches but I failed.
The main problem is that inside the SideBarBlurChange component, I cannot import anything, since my entire project is collapsing. In addition to all this, I will leave a link to this project in the github if you want to see GitHub Project
Now I want to explain my problem in more detail.
Please pay attention to the changing number I showed with the mouse this number and there is a value with the name "values". I need to apply this value to the SideBar component to adjust the blur of the Sidebar.
And finally, before I demonstrate my code, I imported the SideBar inside the SideBarBlurChange, took out a value called "values" and applied it to the SideBar component like this <div style = {{backdropFilter: blur(${props.values}px)}}...
Now look my project has collapsed, I mean that there is a catastrophe for my components, but I got "values" and everything works for me.
Now I think that the problem is understandable, in order not to confuse you, I will show you three SideBar components, SideBarBlurChange and DraggableDialog where I imported SideBarBlurChange, + delete all personal code and show only the most important thing, but if you need to look at all the other components, I will remind you that I left a link to project in github, or as a last resort, tell me I will edit my question and show what you need in advance. I want to thank you for taking the time to solve my problem
SideBar.jsx
export default function SideBar(props) {
return (
<div style={{backdropFilter: "blur(60px)"}}>
// jsx code
</div>
);
}
SideBarBlurChange.jsx
const MIN = 0;
const MAX = 100;
export default function SideBarBlurChange(props) {
const ls = parseInt(window.localStorage.getItem('values'));
const [values, SetValues] = useState(ls ? [ls] : [20]);
const SaveChanges = () => {
localStorage.setItem('values', values);
}
return (
<>
<div>
<Range
// code
/>
<output style={{ marginTop: "30px" }} id="output">
{values[0].toFixed(1)}
</output>
<button onClick={() => SaveChanges()}>Save</button>
</div>
</>
);
}
DraggableDialog.jsx
const DraggableDialog = (props) => {
return (
<>
<div>
<SideBarBlurChange {...props}/>
</div>
</>
);
};
export default DraggableDialog;
I removed a lot of code from these three components, I left only the most important. Sorry in advance, I don't know English, I wrote it all with the help of translate
I'm building a site in Hugo. I'm using the hello friend ng theme. I want to add a svg image to the main site, but I want it to change depending on whether the selected theme is light or dark.
That theme toggle is handled by theme.js:
const theme = window.localStorage && window.localStorage.getItem("theme");
const themeToggle = document.querySelector(".theme-toggle");
const isDark = theme === "dark";
var metaThemeColor = document.querySelector("meta[name=theme-color]");
if (theme !== null) {
document.body.classList.toggle("dark-theme", isDark);
isDark
? metaThemeColor.setAttribute("content", "#252627")
: metaThemeColor.setAttribute("content", "#fafafa");
}
themeToggle.addEventListener("click", () => {
document.body.classList.toggle("dark-theme");
window.localStorage &&
window.localStorage.setItem(
"theme",
document.body.classList.contains("dark-theme") ? "dark" : "light"
);
document.body.classList.contains("dark-theme")
? metaThemeColor.setAttribute("content", "#252627")
: metaThemeColor.setAttribute("content", "#fafafa");
});
But i don't know how to access the variable it's using.
I didn't manage to do exactly that, but I found a workaround which satisfies my needs, so I'm posting it in case someone finds it valuable.
Rather than using <img> with links to different svg images, I decided to use <svg> and copy the content of my image there, since it's just xml. Then, I removed properties such as stroke and fill, wrapped that <svg> in a <div with a custom class that I then control by css.
I'm not sure if that's the best approach but it seems to work for me.
I'm doing my first bigger React project, and I have already spent a day on this seemingly easy problem. Please excuse mistakes in my terminology.
So I have about a hundred svgs, each put into functions. Since they're so many, I'd rather not touch this file, but if's the only solution, at this point I'm willing to do anything. They're all formatted as such below, except with a lot more svg code, formatted for JSX.
export function Example(props) {
return (
<svg viewBox='0 0 100 100' {...props}>
<g fill='#000000'>
<path d='long path here' />
</g>
</svg>
);
}
These are put in a picker, that in itself took a whole day to figure it. The problem is, I'm trying to map through them to have one icon selected, and for them to render after being the mapping, but I cannot figure out how.
{icons.map((icon, index) => {
return (
<IconMap
key={index}
onClick={() => {
selectIcon(icon);
}}
>
< Example>
</IconMap>
);
})}
So they render if I just write , but not with <{icon /> or just {icon}. How can I get the icon being mapped to render out? I'm also quite sure they're "there" so to speak, because I can hover over where they should be, and about the right amount change background color on hover.
I have tried various means, and something that would work would be if I changed my icons file to instead return the svg data as a variable, and then I'd have a separate icon component that rendered it, so I'd essentially write , but it feels like it should be an easier way, where I don't have to re-write hundreds of icons?
And, it's possible that this is an entirely separate question, but as it is something I've been looking into in relation to solving this problem, I'm including it. I'm using reactstrap for this project, and if it would be possible to make a "picker" in reactstrap, such as a dropdown button or a form where the options would show up in a table rather than a list (a vertical list of 100+ icons is a lot of scrolling), I'd gladly hardcode the entire thing just to have it work in reactstrap with the rest of my code.
Thank you so much, and cheers!
Not sure if I understood your question correctly, are you trying to generate the icons dynamically? If so this is one way you can do it
import Icon1 from 'icons/icon1.svg';
import Icon2 from 'icons/icon2.svg';
const Icon = (props) => {
const getIcon = name => {
return {
icon1: Icon1,
icon2: Icon2,
}
}
const IconComponent = getIcon(props.name);
return (
<IconComponent />
);
}
Then you use it in your component like this
{icons.map((icon, index) => {
return (
<IconMap
key={index}
onClick={() => {
selectIcon(icon);
}}
>
<Icon name={icon.name}>
</IconMap>
);
})}
First off, let me provide a little background on my use case for react-virtualized. I am using it together with the v2.0 beta version of react-pdf in order to build a pdf viewer that can handle displaying/rendering pdf documents with a lot of pages more efficiently. An important requirement is that the pdf viewer is fully responsive and can handle documents that have pages that possibly have differing heights.
I have managed to combine both packages (there are a couple of minor react-pdf related hickups), but there are a couple of things that don't quite work like I would expect. Most noticeably, scrolling to a specific row (i.e. page) doesn't really work too well. To give an example, if I attempt to scroll to page index 81 (approximately the middle of my 152 page test pdf) from page index 0, I end up somewhere midway between the desired page and the next page. If I attempt to scroll to the last page index (p.i. 151) I end up at the next to last page.
I am using a combination of WindowScroller, AutoSizer, CellMeasurer and List to create my viewer (I have omitted parts that don't matter directly):
class Viewer extends Component {
constructor(props) {
super(props);
this.state = {pdf: null, scale: 1.2};
this._cache = new CellMeasurerCache({defaultHeight: 768, fixedWidth: true});
}
...
handleResize() {
this._cache.clearAll(); // Reset the cached measurements for all cells
}
updatePageIndex(index) {
this._cache.clearAll();
this._list.scrollToRow(index);
}
rowRenderer({key, index, style, parent}) {
return (
<CellMeasurer cache={this._cache} columnIndex={0} key={key} parent={parent} rowIndex={index}>
{
({measure}) => (
<div style={style}>
<Page
onLoadSuccess={measure}
renderTextLayer={false}
pdf={this.state.pdf}
pageNumber={index + 1}
scale={this.state.scale} />
</div>
)
}
</CellMeasurer>
);
}
render() {
...
<Document
file="./some_pdf_document.pdf"
loading={<Loader />}
error={this.renderError()}
onLoadSuccess={this.onDocumentLoadSuccess.bind(this)}
>
<WindowScroller onResize={this.handleResize.bind(this)}>
{
({height, isScrolling, onChildScroll, scrollTop}) => (
<AutoSizer disableHeight>
{
({width}) => (
<List
autoheight
height={height}
width={width}
isScrolling={isScrolling}
onScroll={onChildScroll}
scrollToAlignment="start"
scrollTop={scrollTop}
overscanRowCount={5}
rowCount={this.state.pdf.numPages}
deferredMeasurementCache={this._cache}
rowHeight={this._cache.rowHeight}
rowRenderer={this.rowRenderer.bind(this)}
style={{outline: 'none'}}
ref={ref => this._list = ref} />
)
}
</AutoSizer>
)
}
</WindowScroller>
</Document>
}
}
...
Is what I do in updatePageIndex() correct or is there still something missing?
I think there's a misunderstanding or two above. Firstly, calling cache.clearAll() will erase all measurements- requiring CellMeasurer to recompute them all on the next render. Unless something has changed that invalidates these measurements- (which doesn't seem to be the case from your description)- then you wouldn't want to do this. This method should only be called if a measurement may be invalid due to a change like a browser width resize that might affect the height of wrapping text content, etc.
Secondly, if you do need to call cache.clearAll() then you will also want to call list.recomputeRowHeights(). CellMeasurer caches measurements (sizes) and List caches positions (offsets). This lets data be re-ordered (eg sorted) without requiring re-measurement. All that's needed after a sort is for List to recompute its positions.
Check out this code snippet from a Twitter-like demo app I built with react-virtualized for an example of how this is done.
If the above info doesn't help you resolve matters, leave a comment and a repro on CodeSandbox or similar and I'll take a look.
The only way I got this to work properly (i.e. scroll to the right page) was to use the scrollToIndex property of the List component. Setting that to a certain row index strangely enough does scroll to the right page.
Only problem with using scrollToIndex is that it doesn't allow you to scroll back up past the scroll index. My workaround is to set the index back to -1 after the scroll has completed. However, if I do this too quick, scrollToIndex also scrolls to the wrong row. The only way I managed to get around this is to set the index to -1 using setTimeout(). Very hacky, but it does the trick. I tried other ways using componentDidUpdate() and a promise, but none of them worked for me.