123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import { getGradientFirstParam } from '.';
- import React from 'react';
- import styled from 'styled-components';
- import { breakpoints } from '~/components/layout';
- import { ColorType, useInputStore } from '~/components/store';
- export const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g;
- export const rgbToString = ({ r, g, b, a }: ColorType) => `rgba(${r},${g},${b},${a})`;
- const Output: React.FC = () => {
- const [svgProps, cssProps, filterProps] = useInputStore((state) => [
- state.svgProps,
- state.cssProps,
- state.filterProps,
- ]);
- const { size, baseFrequency, numOctaves } = svgProps;
- const { gradients, showTransparency } = cssProps;
- const { brightness, contrast, invert } = filterProps;
- const svgString = `<!-- svg: first layer -->
- <svg viewBox='0 0 ${size} ${size}' xmlns='http://www.w3.org/2000/svg'>
- <filter id='noiseFilter'>
- <feTurbulence
- type='fractalNoise'
- baseFrequency='${baseFrequency}'
- numOctaves='${numOctaves}'
- stitchTiles='stitch'/>
- </filter>
-
- <rect width='100%' height='100%' filter='url(#noiseFilter)'/>
- </svg>`;
- const gradientsString = gradients
- .filter((grad) => grad.isVisible)
- .map(
- (grad) =>
- `${grad.type}-gradient(${getGradientFirstParam(grad)}, ${rgbToString(
- grad.stops[0].color
- )}, ${rgbToString(grad.stops[1].color)})`
- );
- const gradientCss = `/* css gradient: second layer */
- {
- width: 250px;
- height: 250px;
- background: ${gradientsString.join(', ')} ${showTransparency ? ', url(/checkers.png)' : ''};
- /* filter: contrast(${contrast}%) brightness(${brightness}%)${invert ? ' invert(100%)' : ''}; */
- }`;
- const liveCss = `
- width: 250px;
- height: 250px;
- background: ${gradientsString.join(', ')}, url("data:image/svg+xml,${svgString.replace(
- symbols,
- encodeURIComponent
- )}");
- filter: contrast(${contrast}%) brightness(${brightness}%)${invert ? ' invert(100%)' : ''};
- `;
- return (
- <Container>
- <OutputSection>
- <Noise size={size} code={svgString} />
- </OutputSection>
- <OutputSection>
- <Gradient css={gradientCss} />
- </OutputSection>
- <OutputSection>
- <FilterShadow />
- <Filter css={liveCss} />
- </OutputSection>
- </Container>
- );
- };
- export default Output;
- // hacking it for essentially flex-direction: column; which does not work
- const Container = styled.div`
- height: 100vh;
- display: flex;
- overflow-y: scroll;
- flex-wrap: wrap;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- @media screen and (max-width: ${breakpoints.md - 1}px) {
- background-color: #fff;
- position: fixed;
- bottom: 0;
- height: 280px;
- overflow-x: scroll;
- flex-wrap: nowrap;
- justify-content: flex-start;
- width: 100vw;
- border-top: 2px solid #333;
- }
- `;
- type NoiseProps = {
- size: number;
- code: string;
- };
- // prettier-ignore
- const Noise = styled.div<NoiseProps>`
- width: ${(p) => p.size}px;
- height: ${(p) => p.size}px;
- background: url("data:image/svg+xml,${(p) => p.code.replace(symbols, encodeURIComponent)}");
- box-shadow: rgb(50 50 93 / 23%) 0px 30px 60px -15px, rgb(0 0 0 / 32%) 0px 18px 36px -18px;
- `;
- type GradientProps = {
- css: string;
- };
- const Gradient = styled.div<GradientProps>`
- ${(p) => p.css}
- box-shadow: rgb(50 50 93 / 23%) 0px 30px 60px -15px, rgb(0 0 0 / 32%) 0px 18px 36px -18px;
- `;
- const OutputSection = styled.div`
- position: relative;
- display: flex;
- justify-content: center;
- width: calc(100vw * 2 / 3);
- margin: 10px;
- @media screen and (max-width: ${breakpoints.md - 1}px) {
- width: auto;
- }
- `;
- // have to create a new layer, or the filter affects box-shadow
- const FilterShadow = styled.div`
- position: absolute;
- top: 0;
- width: 250px;
- height: 250px;
- box-shadow: rgb(50 50 93 / 23%) 0px 30px 60px -15px, rgb(0 0 0 / 32%) 0px 18px 36px -18px;
- `;
- type FilterProps = {
- css: string;
- };
- const Filter = styled.div<FilterProps>`
- ${(p) => p.css}
- `;
|