Skip to content

Commit

Permalink
feat: Add support for rendering images instead of circles for snowfla…
Browse files Browse the repository at this point in the history
…ke contents
  • Loading branch information
cahilfoley committed Aug 25, 2022
1 parent 6bd009f commit d0d99e4
Show file tree
Hide file tree
Showing 17 changed files with 384 additions and 168 deletions.
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,36 @@ An optional `color`, `style`, and `snowflakeCount` property can be passed in to
/>
```

## Positioning
## Using Images

Instead of rendering colored circles you can instead pass in an array of image elements
that will be randomly selected and used as the snowflake instead.

> _NOTE_: If the images provided are not square they will be stretched into a 1:1 aspect ratio.
```tsx
const snowflake1 = document.createElement('img')
snowflake1.src = '/assets/snowflake-1.png'
const snowflake2 = document.createElement('img')
snowflake2.src = '/assets/snowflake-2.jpg'

const images = [snowflake1, snowflake2]

const Demo = () => {
return (
<Snowfall
// Applied to the canvas element
style={{ background: '#fff' }}
// Controls the number of snowflakes that are created (default 150)
snowflakeCount={200}
// Pass in the images to be used
images={images}
>
)
}
```

## Positioning

The snowfall container is absolute positioned and has the following default styles (see [the definition](https://github.com/cahilfoley/react-snowfall/blob/a8e865e82cac3221930773cdfd6b90eeb0b34247/src/config.ts#L4-L10)):

Expand All @@ -77,7 +105,7 @@ If you want the component to cover the entire screen then you can change the pos
style={{
position: 'fixed',
width: '100vw',
height: '100vh'
height: '100vh',
}}
/>
```
51 changes: 49 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
"react-snowfall": "*",
"typescript": "^4.7.4"
"typescript": "^4.7.4",
"zustand": "^4.1.1"
},
"scripts": {
"predeploy": "npm run build",
Expand All @@ -39,4 +40,4 @@
"devDependencies": {
"@types/react-color": "^3.0.6"
}
}
}
25 changes: 12 additions & 13 deletions packages/demo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
import { useContext } from 'react'
import Snowfall from 'react-snowfall'
import GithubLink from './components/GithubLink/GithubLink'
import Settings from './components/Settings'
import { SettingsContext } from './context/settings'
import { useSettingsStore } from './settings'
import logo from './logo.png'
import './App.css'

const githubURL = process.env.REACT_APP_GITHUB_URL as string
const packageName = process.env.REACT_APP_PACKAGE_NAME as string

const imageElement = document.createElement('img')
imageElement.src = logo
const snowflake = document.createElement('img')
snowflake.src = logo

const images = [imageElement]
const images = [snowflake]

const App = () => {
const settings = useContext(SettingsContext)
const { color, snowflakeCount, radius, speed, wind, useImages } = useSettingsStore()

return (
<div className="app">
<Snowfall
color={settings.color}
snowflakeCount={settings.snowflakeCount}
radius={settings.radius}
speed={settings.speed}
wind={settings.wind}
// images={images}
color={color}
snowflakeCount={snowflakeCount}
radius={radius}
speed={speed}
wind={wind}
images={useImages ? images : undefined}
/>
<a className="title" href={githubURL} style={{ color: settings.color }}>
<a className="title" href={githubURL} style={{ color }}>
<img src={logo} alt="Snowflake Logo" />
<h1>{packageName}</h1>
</a>
Expand Down
157 changes: 105 additions & 52 deletions packages/demo/src/components/Settings/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { useContext } from 'react'
import { CirclePicker } from 'react-color'
import Box from '@mui/material/Box'
import Checkbox from '@mui/material/Checkbox'
import Chip, { ChipProps } from '@mui/material/Chip'
import FormControlLabel from '@mui/material/FormControlLabel'
import Paper from '@mui/material/Paper'
import Typography from '@mui/material/Typography'
import Slider from '@mui/material/Slider'
import { SettingsContext, SnowfallSettings } from '../../context/settings'
import Stack from '@mui/material/Stack'
import Typography from '@mui/material/Typography'
import { CirclePicker } from 'react-color'
import { useSettingsStore } from '../../settings'
import { ThemeProvider } from './theme'

import './Settings.css'

const ValueChip = (props: ChipProps) => {
return <Chip {...props} sx={{ ml: 1 }} size="small" component="span" />
}

const colors = [
'#dee4fd',
'#e91e63',
Expand All @@ -31,58 +38,104 @@ const colors = [
]

const Settings = () => {
const settings = useContext(SettingsContext) as SnowfallSettings
const settings = useSettingsStore()

return (
<ThemeProvider>
<Paper className="settings-container">
<Typography gutterBottom>Snowflake Count - {settings.snowflakeCount}</Typography>
<Slider
value={settings.snowflakeCount}
min={0}
max={750}
step={1}
onChange={(_, value) => settings.setSnowflakeCount(value as number)}
/>
<Typography gutterBottom>
Speed - Min {settings?.speed?.[0]} Max {settings?.speed?.[1]}
</Typography>
<Slider
value={settings.speed}
min={0}
max={10}
step={0.5}
onChange={(_, value) => settings.setSpeed(value as [number, number])}
/>
<Typography gutterBottom>
Wind - Min {settings?.wind?.[0]} Max {settings?.wind?.[1]}
</Typography>
<Slider
value={settings.wind}
min={-1}
max={10}
step={0.5}
onChange={(_, value) => settings.setWind(value as [number, number])}
/>
<Typography gutterBottom>
Radius - Min {settings?.radius?.[0]} Max {settings?.radius?.[1]}
</Typography>
<Slider
value={settings.radius}
min={0.5}
max={30}
step={0.5}
onChange={(_, value) => settings.setRadius(value as [number, number])}
/>
<Box my={2}>
<Typography gutterBottom>Color - {settings.color}</Typography>
<CirclePicker
colors={colors}
width="100%"
color={settings.color}
onChangeComplete={(value) => settings.setColor(value.hex)}
/>
</Box>
<Stack spacing={1}>
<div>
<Typography gutterBottom>
Snowflake Count <ValueChip label={settings.snowflakeCount} />
</Typography>
<Slider
value={settings.snowflakeCount}
min={0}
max={750}
step={1}
onChange={(_, value) => settings.update({ snowflakeCount: value as number })}
/>
</div>
<div>
<Typography gutterBottom>
Speed <ValueChip label={`Min ${settings?.speed?.[0]}`} />
<ValueChip label={`Max ${settings?.speed?.[1]}`} />
</Typography>
<Slider
value={settings.speed}
min={0}
max={10}
step={0.5}
onChange={(_, value) => settings.update({ speed: value as [number, number] })}
/>
</div>
<div>
<Typography gutterBottom>
Wind <ValueChip label={`Min ${settings?.wind?.[0]}`} />{' '}
<ValueChip label={`Max ${settings?.wind?.[1]}`} />
</Typography>
<Slider
value={settings.wind}
min={-1}
max={10}
step={0.5}
onChange={(_, value) => settings.update({ wind: value as [number, number] })}
/>
</div>
<div>
<Typography gutterBottom>
Radius <ValueChip label={`Min ${settings?.radius?.[0]}`} />
<ValueChip label={`Max ${settings?.radius?.[1]}`} />
</Typography>
<Slider
value={settings.radius}
min={0.5}
max={30}
step={0.5}
onChange={(_, value) => settings.update({ radius: value as [number, number] })}
/>
</div>
<div>
<FormControlLabel
control={
<Checkbox
checked={settings.useImages}
onChange={(event) => settings.setUseImages(event.target.checked)}
/>
}
label="Use Images"
/>
</div>
{settings.useImages ? (
<div>
<Typography gutterBottom>
Rotation Speed <ValueChip label={`Min ${settings?.rotationSpeed?.[0]}`} />
<ValueChip label={`Max ${settings?.rotationSpeed?.[1]}`} />
</Typography>
<Slider
value={settings.rotationSpeed}
min={-5}
max={10}
step={0.5}
onChange={(_, value) =>
settings.update({ rotationSpeed: value as [number, number] })
}
/>
</div>
) : (
<Box my={2}>
<Typography gutterBottom>
Color <ValueChip label={settings.color} />
</Typography>
<CirclePicker
colors={colors}
width="100%"
color={settings.color}
onChangeComplete={(value) => settings.update({ color: value.hex })}
/>
</Box>
)}
</Stack>
</Paper>
</ThemeProvider>
)
Expand Down
Loading

0 comments on commit d0d99e4

Please sign in to comment.