feat(app): recipe ideas

This commit is contained in:
rektdeckard
2023-03-11 01:25:42 -07:00
parent 675c4fc364
commit 46ed0bc300
9 changed files with 248 additions and 2 deletions

View File

@@ -8,6 +8,7 @@ import IconGrid from "@/components/IconGrid";
import Footer from "@/components/Footer";
import ErrorBoundary from "@/components/ErrorBoundary";
import Notice from "@/components/Notice";
import Recipes from "@/components/Recipes";
import {
useIconParameters,
usePersistSettings,
@@ -47,6 +48,7 @@ const App: React.FC<any> = () => {
</Suspense>
</ErrorBoundary>
</main>
<Recipes />
<Footer />
</Fragment>
);

View File

@@ -0,0 +1,22 @@
import { ArrowCircleUpRight } from "@phosphor-icons/react";
export type RecipeProps = {
title: string;
url: string;
Example: () => JSX.Element;
};
const Recipe = ({ title, url, Example }: RecipeProps) => {
return (
<a className="recipe card" href={url}>
{/* <h1>{title}</h1> */}
<div className="recipe-linkout">
<span>Open on StackBlitz</span>
<ArrowCircleUpRight weight="fill" size={32} />
</div>
<Example />
</a>
);
};
export default Recipe;

View File

@@ -0,0 +1,39 @@
.recipes {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(184px, 1fr));
gap: 16px;
padding-block: 32px;
}
a.recipe {
position: relative;
color: initial;
padding: 16px;
display: grid;
place-items: center;
}
.recipe-linkout {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
background-color: var(--soft);
border-radius: 8px;
z-index: 1;
opacity: 0;
transition: opacity 200ms ease;
}
.recipe-linkout:hover {
opacity: 1;
}
.example {
display: grid;
grid-template-columns: 64px 64px;
gap: 12px;
place-items: center;
}

View File

@@ -0,0 +1,29 @@
import { IconContext } from "@phosphor-icons/react";
import Recipe from "./Recipe";
import items from "./items";
import "./Recipes.css";
const Recipes = () => {
return (
<>
<div className="toolbar">
<div className="toolbar-contents">
<h2>Recipes</h2>
<p>Cool stuff to do with Phosphor</p>
</div>
</div>
<div className="grid-container">
<IconContext.Provider value={{ size: 64 }}>
<div className="recipes grid">
{items.map((itemProps) => (
<Recipe key={itemProps.title} {...itemProps} />
))}
</div>
</IconContext.Provider>
</div>
</>
);
};
export default Recipes;

View File

@@ -0,0 +1 @@
export { default } from "./Recipes";

View File

@@ -0,0 +1,83 @@
import { Cube } from "@phosphor-icons/react";
import { RecipeProps } from "../Recipe";
const recipe: RecipeProps = {
title: "SVG Wizardry",
url: "https://stackblitz.com/edit/react-ts-f7q7gs?file=App.tsx,style.css",
Example() {
return (
<div className="example">
<Cube
color="darkorchid"
weight="duotone"
style={{ fill: "url(#star)" }}
>
<defs>
<pattern id="star" viewBox="0,0,10,10" width="10%" height="10%">
<polygon
points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2"
fill="darkOrchid"
/>
</pattern>
</defs>
</Cube>
<Cube
color="darkorchid"
weight="duotone"
style={{ filter: "url(#emboss)" }}
>
<filter id="emboss">
<feConvolveMatrix
kernelMatrix="
5 0 0
0 0 0
0 0 -3
"
/>
</filter>
</Cube>
<Cube color="darkorchid" weight="duotone">
<animate
attributeName="opacity"
values="0;1;0"
dur="4s"
repeatCount="indefinite"
></animate>
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
dur="5s"
from="0 0 0"
to="360 0 0"
repeatCount="indefinite"
></animateTransform>
</Cube>
<Cube
color="darkorchid"
weight="duotone"
style={{ filter: "url(#displacementFilter)" }}
>
<filter id="displacementFilter">
<feTurbulence
type="turbulence"
baseFrequency="0.01"
numOctaves="3"
result="turbulence"
/>
<feDisplacementMap
in2="turbulence"
in="SourceGraphic"
scale="20"
xChannelSelector="B"
yChannelSelector="G"
/>
</filter>
</Cube>
</div>
);
},
};
export default recipe;

View File

@@ -0,0 +1,63 @@
import { useMemo } from "react";
import {
Icon,
IconProps,
Barricade,
GasCan,
IceCream,
FlyingSaucer,
} from "@phosphor-icons/react";
import { RecipeProps } from "../Recipe";
type DuocolorProps = Omit<IconProps, "weight"> & {
Icon: Icon;
duocolor?: string;
};
function Duocolor({ Icon, duocolor, ...iconProps }: DuocolorProps) {
const [uuid, style] = useMemo(() => {
// UUID to make sure the inline stylesheet is "scoped" to this icon only.
// Could also easily be implemented with a regular CSS selector.
const uuid = "ph-" + Math.floor(Math.random() * 1_000_000).toString(16);
// const uuid = "ph-" + crypto.randomUUID();
return [uuid, !duocolor ? null : createDuocolorStyle(uuid, duocolor)];
}, [duocolor]);
return (
<>
{style}
<Icon {...iconProps} weight="duotone" data-ph={uuid} />
</>
);
}
function createDuocolorStyle(id: string, color: string) {
return (
<style>
{`
[data-ph="${id}"] [opacity="0.2"] {
opacity: 1;
fill: ${color};
}
`}
</style>
);
}
const recipe: RecipeProps = {
title: "Duocolor",
url: "https://stackblitz.com/edit/react-ts-kvdzu1?file=App.tsx",
Example() {
return (
<div className="example">
<Duocolor Icon={FlyingSaucer} duocolor="darkcyan" />
<Duocolor Icon={Barricade} color="darkgray" duocolor="orange" />
<Duocolor Icon={IceCream} color="saddlebrown" duocolor="lightpink" />
<Duocolor Icon={GasCan} duocolor="indianred" />
</div>
);
},
};
export default recipe;

View File

@@ -0,0 +1,6 @@
import animation from "./Animation";
import duocolor from "./Duocolor";
import { RecipeProps } from "../Recipe";
const items: RecipeProps[] = [animation, duocolor, duocolor, animation];
export default items;

View File

@@ -1,9 +1,10 @@
nav.toolbar {
.toolbar {
position: -webkit-sticky;
position: sticky;
top: -1px;
padding: 0;
margin: 0;
color: white;
background-color: var(--eggplant);
z-index: 2;
display: flex;