1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* This app displays a thick horizontal line with a color gradient from dark red to yellow to light green.
* Below each section, there's a text input field. Each color section can have up to 8 values.
* It uses React for the UI and CSS for styling the gradient line and inputs.
* It includes a reorder functionality for the items in each section and an expandable "Learn more" section.
*/
/** @jsxImportSource https://esm.sh/react */
import React, { useState } from "https://esm.sh/react";
import { createRoot } from "https://esm.sh/react-dom/client";
function App() {
const [redItems, setRedItems] = useState<string[]>([]);
const [yellowItems, setYellowItems] = useState<string[]>([]);
const [greenItems, setGreenItems] = useState<string[]>([]);
const [isReordering, setIsReordering] = useState(false);
const [isLearnMoreExpanded, setIsLearnMoreExpanded] = useState(false);
const addItem = (color: string, item: string) => {
if (item.trim() === "") return;
switch (color) {
case "red": {
if (redItems.length < 8) setRedItems([...redItems, item.trim()]);
(document.querySelector('input[placeholder="Add red item"]') as HTMLInputElement).value = '';
break;
}
case "yellow": {
if (yellowItems.length < 8) setYellowItems([...yellowItems, item.trim()]);
(document.querySelector('input[placeholder="Add yellow item"]') as HTMLInputElement).value = '';
break;
}
case "green": {
if (greenItems.length < 8) setGreenItems([...greenItems, item.trim()]);
(document.querySelector('input[placeholder="Add green item"]') as HTMLInputElement).value = '';
break;
}
}
};
const removeItem = (color: string, index: number) => {
switch (color) {
case "red":
setRedItems(redItems.filter((_, i) => i !== index));
break;
case "yellow":
setYellowItems(yellowItems.filter((_, i) => i !== index));
break;
case "green":
setGreenItems(greenItems.filter((_, i) => i !== index));
break;
}
};
const moveItem = (color: string, index: number, direction: 'up' | 'down') => {
const setter = color === 'red' ? setRedItems : color === 'yellow' ? setYellowItems : setGreenItems;
const items = color === 'red' ? redItems : color === 'yellow' ? yellowItems : greenItems;
if ((direction === 'up' && index > 0) || (direction === 'down' && index < items.length - 1)) {
const newItems = [...items];
const [removed] = newItems.splice(index, 1);
newItems.splice(direction === 'up' ? index - 1 : index + 1, 0, removed);
setter(newItems);
}
};
const toggleReorder = () => {
setIsReordering(!isReordering);
};
const toggleLearnMore = () => {
setIsLearnMoreExpanded(!isLearnMoreExpanded);
};
const exportData = async () => {
const markdownText = `# Know Your Boundaries
## Intolerable
${redItems.map((item, index) => `${index + 1}. ${item}`).join('\n')}
## Pushing Limits
${yellowItems.map((item, index) => `${index + 1}. ${item}`).join('\n')}
## Flourishing
${greenItems.map((item, index) => `${index + 1}. ${item}`).join('\n')}
`;
try {
await navigator.clipboard.writeText(markdownText);
alert('Exported data has been copied to your clipboard!');
} catch (err) {
console.error('Failed to copy text: ', err);
alert('Failed to copy to clipboard. Please try again.');
}
};
const renderItems = (items: string[], color: string) => {
return items.map((item, index) => (
<li key={index}>
{item}
{isReordering ? (
<div className="reorder-buttons">