Skip to content

Commit 18f7414

Browse files
authored
Box shadow CSS generator
Mostly by Claude 3.5 Sonnet: https://twitter.com/simonw/status/1810335524017877240
1 parent 1459a6b commit 18f7414

File tree

2 files changed

+165
-1
lines changed

2 files changed

+165
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- [Arena animated](https://tools.simonwillison.net/arena-animated) animates the progression of the LMSYS Chatbot Arena, inspired by [this visualization](https://public.flourish.studio/visualisation/17992181/) by [Peter Gostev](https://www.linkedin.com/posts/peter-gostev_how-companies-llms-compare-over-the-course-activity-7196899934615257090-zilk) (via [Time-Winter-4319 on Reddit](https://www.reddit.com/r/LocalLLaMA/comments/1bp4j19/gpt4_is_no_longer_the_top_dog_timelapse_of/))
88
- [Compare PDFs](https://tools.simonwillison.net/compare-pdfs) provides a visual comparison of the pages of two PDF files
99
- [Chrome Prompt Playground](https://tools.simonwillison.net/chrome-prompt-playground) is a UI for running prompts through the Google Chrome Canary experimental Gemini Nano LLM and saving the results in local storage
10-
10+
- [Box shadow CSS generator](https://tools.simonwillison.net/chrome-prompt-playground) generates the CSS for a box shadow with interactive settings
1111

1212
On Observable:
1313

box-shadow.html

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Box shadow CSS generator</title>
7+
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
8+
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.22.10/babel.min.js"></script>
10+
<style>
11+
body {
12+
font-family: Arial, sans-serif;
13+
line-height: 1.6;
14+
color: #333;
15+
max-width: 600px;
16+
margin: 0 auto;
17+
padding: 20px;
18+
}
19+
.preview-box {
20+
width: 200px;
21+
height: 200px;
22+
margin: 20px auto;
23+
background-color: white;
24+
display: flex;
25+
align-items: center;
26+
justify-content: center;
27+
border: 1px solid #ccc;
28+
}
29+
.control-group {
30+
margin-bottom: 15px;
31+
}
32+
label {
33+
display: block;
34+
margin-bottom: 5px;
35+
}
36+
input[type="range"], input[type="color"] {
37+
width: 100%;
38+
}
39+
.css-output {
40+
background-color: #f4f4f4;
41+
padding: 10px;
42+
border-radius: 4px;
43+
font-family: monospace;
44+
white-space: pre-wrap;
45+
}
46+
button {
47+
background-color: #4CAF50;
48+
border: none;
49+
color: white;
50+
padding: 10px 20px;
51+
text-align: center;
52+
text-decoration: none;
53+
display: inline-block;
54+
font-size: 16px;
55+
margin: 4px 2px;
56+
cursor: pointer;
57+
border-radius: 4px;
58+
}
59+
</style>
60+
</head>
61+
<body>
62+
<div id="root"></div>
63+
64+
<script type="text/babel">
65+
const BoxShadowTool = () => {
66+
const [horizontalOffset, setHorizontalOffset] = React.useState(0);
67+
const [verticalOffset, setVerticalOffset] = React.useState(4);
68+
const [blurRadius, setBlurRadius] = React.useState(8);
69+
const [spreadRadius, setSpreadRadius] = React.useState(0);
70+
const [color, setColor] = React.useState('#000000');
71+
const [opacity, setOpacity] = React.useState(20);
72+
73+
const boxShadow = `${horizontalOffset}px ${verticalOffset}px ${blurRadius}px ${spreadRadius}px ${color}${Math.round(opacity * 2.55).toString(16).padStart(2, '0')}`;
74+
const cssCode = `box-shadow: ${boxShadow};`;
75+
76+
const copyToClipboard = () => {
77+
navigator.clipboard.writeText(cssCode);
78+
alert('CSS copied to clipboard!');
79+
};
80+
81+
return (
82+
<div>
83+
<h1>Box shadow CSS generator</h1>
84+
<div className="preview-box" style={{ boxShadow }}>
85+
Preview
86+
</div>
87+
88+
<div className="control-group">
89+
<label>Horizontal Offset: {horizontalOffset}px</label>
90+
<input
91+
type="range"
92+
min="-50"
93+
max="50"
94+
value={horizontalOffset}
95+
onChange={(e) => setHorizontalOffset(Number(e.target.value))}
96+
/>
97+
</div>
98+
99+
<div className="control-group">
100+
<label>Vertical Offset: {verticalOffset}px</label>
101+
<input
102+
type="range"
103+
min="-50"
104+
max="50"
105+
value={verticalOffset}
106+
onChange={(e) => setVerticalOffset(Number(e.target.value))}
107+
/>
108+
</div>
109+
110+
<div className="control-group">
111+
<label>Blur Radius: {blurRadius}px</label>
112+
<input
113+
type="range"
114+
min="0"
115+
max="50"
116+
value={blurRadius}
117+
onChange={(e) => setBlurRadius(Number(e.target.value))}
118+
/>
119+
</div>
120+
121+
<div className="control-group">
122+
<label>Spread Radius: {spreadRadius}px</label>
123+
<input
124+
type="range"
125+
min="-50"
126+
max="50"
127+
value={spreadRadius}
128+
onChange={(e) => setSpreadRadius(Number(e.target.value))}
129+
/>
130+
</div>
131+
132+
<div className="control-group">
133+
<label>Color</label>
134+
<input
135+
type="color"
136+
value={color}
137+
onChange={(e) => setColor(e.target.value)}
138+
/>
139+
</div>
140+
141+
<div className="control-group">
142+
<label>Opacity: {opacity}%</label>
143+
<input
144+
type="range"
145+
min="0"
146+
max="100"
147+
value={opacity}
148+
onChange={(e) => setOpacity(Number(e.target.value))}
149+
/>
150+
</div>
151+
152+
<div className="control-group">
153+
<label>CSS Code:</label>
154+
<div className="css-output">{cssCode}</div>
155+
<button onClick={copyToClipboard}>Copy to Clipboard</button>
156+
</div>
157+
</div>
158+
);
159+
};
160+
161+
ReactDOM.render(<BoxShadowTool />, document.getElementById('root'));
162+
</script>
163+
</body>
164+
</html>

0 commit comments

Comments
 (0)