added claude design's ui framework
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="_ds/organic-9b68eb3f-20a3-40f4-b132-a5a6542b5b19/styles.css">
|
||||
<script src="pansy-theme.js"></script>
|
||||
<script src="_ds/organic-9b68eb3f-20a3-40f4-b132-a5a6542b5b19/_ds_bundle.js"></script>
|
||||
<style>
|
||||
:root{--p-field:#efe3c9;--p-grid-ink:#201e1d;--p-ink-strong:#474238;--p-ink-soft:#645c50;--p-ink-mute:#82796a;--p-bed-fill:#e3d0ac;--p-bed-stroke:#b5a37f;--p-ing-fill:#d6bf98;--p-ing-stroke:#b1a07c;--p-path-fill:#ece1cb;--p-path-stroke:#cabfa6;--p-bag-fill:#d8c5a2;--p-bag-stroke:#a99677;--p-bkt-fill:#cfc3ad;--p-bkt-stroke:#9a8d76;--p-tree-fill:#dce9c6;--p-tree-stroke:#8fa073;--p-str-fill:#d9cfbc;--p-str-stroke:#a3947c}
|
||||
html,body{margin:0;min-height:100%}
|
||||
a{color:var(--color-accent)} a:hover{color:var(--color-accent-600)}
|
||||
</style>
|
||||
</helmet>
|
||||
<div data-screen-label="Plants" style="min-height:100vh;background:var(--color-bg);font-family:var(--font-body);color:var(--color-text)">
|
||||
<nav class="nav">
|
||||
<span class="nav-brand" style="display:flex;align-items:center;gap:8px">
|
||||
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent-2-600)" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M7 20h10"></path><path d="M10 20c5.5-2.5.8-6.4 3-10"></path><path d="M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z"></path><path d="M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z"></path></svg>
|
||||
pansy
|
||||
</span>
|
||||
<a href="Pansy Gardens.dc.html">Gardens</a>
|
||||
<a href="Pansy Plants.dc.html" aria-current="page">Plants</a>
|
||||
<span style="margin-left:auto;display:flex;align-items:center;gap:10px">
|
||||
<button class="btn btn-icon btn-secondary" style="border-radius:999px" onClick="{{ onTheme }}" title="{{ themeTitle }}">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="{{ themeD1 }}"></path><path d="{{ themeD2 }}"></path><path d="{{ themeD3 }}"></path></svg>
|
||||
</button>
|
||||
<a href="Pansy Settings.dc.html" class="btn btn-icon btn-secondary" style="border-radius:999px" title="Settings">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0 2-2z"></path></svg>
|
||||
</a>
|
||||
<a href="Pansy Login.dc.html" style="width:32px;height:32px;border-radius:999px;background:var(--color-accent-2-300);color:var(--color-accent-2-800);display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:14px;text-decoration:none">S</a>
|
||||
</span>
|
||||
</nav>
|
||||
<div style="max-width:1080px;margin:0 auto;padding:28px 24px 56px">
|
||||
<div style="display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-bottom:18px">
|
||||
<h2 style="margin:0">Plants</h2>
|
||||
<span style="font-size:14px;color:var(--p-ink-mute);font-weight:600">The built-ins plus everything you've added</span>
|
||||
<span style="margin-left:auto;display:flex;gap:8px">
|
||||
<button class="btn btn-secondary" style="border-radius:999px" onClick="{{ onScan }}">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"></path><circle cx="12" cy="13" r="3"></circle></svg>
|
||||
Scan a packet
|
||||
</button>
|
||||
<button class="btn btn-primary" style="border-radius:999px" onClick="{{ onAdd }}">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round"><path d="M5 12h14"></path><path d="M12 5v14"></path></svg>
|
||||
Add a plant
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:20px">
|
||||
<input class="input" style="border-radius:999px;max-width:260px" placeholder="Find a plant…" value="{{ q }}" onChange="{{ onQ }}">
|
||||
<sc-for list="{{ cats }}" as="c">
|
||||
<button onClick="{{ c.onClick }}" style="{{ c.style }}">{{ c.label }}</button>
|
||||
</sc-for>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px">
|
||||
<sc-for list="{{ cardsR }}" as="p" hint-placeholder-count="8">
|
||||
<div onClick="{{ p.onClick }}" style="{{ p.cardStyle }}" style-hover="box-shadow:var(--shadow-md)">
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<svg width="40" height="40" style="flex:none"><circle cx="20" cy="20" r="20" fill="{{ p.color }}"></circle></svg>
|
||||
<span style="position:absolute;width:40px;text-align:center;color:#fffaf1;font-family:var(--font-heading);font-size:17px;pointer-events:none">{{ p.letter }}</span>
|
||||
<span style="display:flex;flex-direction:column;gap:1px;min-width:0">
|
||||
<span style="font-family:var(--font-heading);font-size:16.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ p.name }}</span>
|
||||
<span style="font-size:12px;color:var(--p-ink-mute);font-weight:600">{{ p.sub }}</span>
|
||||
</span>
|
||||
<sc-if value="{{ p.builtin }}" hint-placeholder-val="{{ false }}"><span class="tag tag-neutral" style="border-radius:999px;margin-left:auto;flex:none">built-in</span></sc-if>
|
||||
</div>
|
||||
<div style="font-size:12.5px;color:var(--p-ink-soft);margin-top:10px">{{ p.lotText }}</div>
|
||||
<sc-if value="{{ p.open }}" hint-placeholder-val="{{ false }}">
|
||||
<div style="margin-top:10px;display:flex;flex-direction:column;gap:8px">
|
||||
<sc-for list="{{ p.lots }}" as="l" hint-placeholder-count="1">
|
||||
<div style="background:var(--color-bg);border:1px solid var(--color-divider);border-radius:var(--radius-md);padding:10px 13px">
|
||||
<div style="display:flex;gap:6px;align-items:center">
|
||||
<span style="font-size:12.5px;font-weight:700">{{ l.vendor }}</span>
|
||||
<span style="font-size:11.5px;color:var(--p-ink-mute);margin-left:auto">packed for {{ l.year }}</span>
|
||||
</div>
|
||||
<div style="font-size:12px;color:var(--p-ink-soft);margin-top:3px">{{ l.detail }}</div>
|
||||
</div>
|
||||
</sc-for>
|
||||
<sc-if value="{{ p.noLots }}"><div style="font-size:12.5px;color:var(--p-ink-mute)">No seed lots yet — scan a packet to add one.</div></sc-if>
|
||||
</div>
|
||||
</sc-if>
|
||||
</div>
|
||||
</sc-for>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<sc-if value="{{ dlgScan }}" hint-placeholder-val="{{ false }}">
|
||||
<div style="position:fixed;inset:0;background:color-mix(in srgb, #201e1d 40%, transparent);display:flex;align-items:center;justify-content:center;padding:20px;z-index:50" onClick="{{ onCloseDlg }}">
|
||||
<div style="background:var(--color-neutral-100);border-radius:var(--radius-lg);box-shadow:var(--shadow-lg);padding:26px;width:min(560px,100%);display:flex;flex-direction:column;gap:14px" onClick="{{ stop }}">
|
||||
<h3 style="margin:0;font-size:22px">Scan a seed packet</h3>
|
||||
<sc-if value="{{ scanStep0 }}" hint-placeholder-val="{{ true }}">
|
||||
<div style="border:2px dashed var(--color-neutral-400);border-radius:var(--radius-lg);padding:36px 20px;display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center">
|
||||
<svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent-2-600)" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"></path><circle cx="12" cy="13" r="3"></circle></svg>
|
||||
<div style="font-size:14px;font-weight:600">Photograph the packet — front is enough</div>
|
||||
<div style="font-size:12.5px;color:var(--p-ink-mute);max-width:36ch">The vision model reads it into fields. It only reads; nothing is saved until you confirm.</div>
|
||||
<button class="btn btn-primary" style="border-radius:999px;margin-top:4px" onClick="{{ onScanGo }}">Use a sample photo</button>
|
||||
</div>
|
||||
</sc-if>
|
||||
<sc-if value="{{ scanStep1 }}" hint-placeholder-val="{{ false }}">
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
|
||||
<div class="field"><label>Variety</label><input class="input" style="border-radius:999px" value="Garlic — Music"></div>
|
||||
<div class="field"><label>Vendor</label><input class="input" style="border-radius:999px" value="Keene Organics"></div>
|
||||
<div class="field"><label>Packed for</label><input class="input" style="border-radius:999px" value="2026"></div>
|
||||
<div class="field"><label>Quantity</label><input class="input" style="border-radius:999px" value="50 cloves"></div>
|
||||
</div>
|
||||
<div style="font-size:12.5px;font-weight:700;color:var(--p-ink-soft);margin-top:2px">Match it to your catalog — nothing is auto-created:</div>
|
||||
<sc-for list="{{ matches }}" as="m">
|
||||
<button onClick="{{ m.onClick }}" style="{{ m.style }}">
|
||||
<span style="font-size:13.5px;font-weight:700">{{ m.label }}</span>
|
||||
<span style="font-size:12px;color:var(--p-ink-mute);margin-left:auto">{{ m.sub }}</span>
|
||||
</button>
|
||||
</sc-for>
|
||||
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:4px">
|
||||
<button class="btn btn-secondary" style="border-radius:999px" onClick="{{ onCloseDlg }}">Cancel</button>
|
||||
<button class="btn btn-primary" style="border-radius:999px" onClick="{{ onConfirmScan }}">Add the lot</button>
|
||||
</div>
|
||||
</sc-if>
|
||||
</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ dlgAdd }}" hint-placeholder-val="{{ false }}">
|
||||
<div style="position:fixed;inset:0;background:color-mix(in srgb, #201e1d 40%, transparent);display:flex;align-items:center;justify-content:center;padding:20px;z-index:50" onClick="{{ onCloseDlg }}">
|
||||
<div style="background:var(--color-neutral-100);border-radius:var(--radius-lg);box-shadow:var(--shadow-lg);padding:26px;width:min(420px,100%);display:flex;flex-direction:column;gap:14px" onClick="{{ stop }}">
|
||||
<h3 style="margin:0;font-size:22px">A new plant</h3>
|
||||
<div class="field"><label>Name</label><input class="input" style="border-radius:999px" value="{{ aName }}" onChange="{{ onAName }}" placeholder="Delicata squash"></div>
|
||||
<div style="display:flex;gap:10px">
|
||||
<div class="field" style="flex:1"><label>Category</label>
|
||||
<select class="input" style="border-radius:999px" value="{{ aCat }}" onChange="{{ onACat }}">
|
||||
<option value="vegetable">Vegetable</option><option value="herb">Herb</option><option value="flower">Flower</option><option value="fruit">Fruit</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field" style="flex:1"><label>Spacing (in)</label><input class="input" style="border-radius:999px" type="number" value="{{ aSp }}" onChange="{{ onASp }}"></div>
|
||||
</div>
|
||||
<div class="field"><label>Marker color</label>
|
||||
<div style="display:flex;gap:8px">
|
||||
<sc-for list="{{ swatches }}" as="sw">
|
||||
<button onClick="{{ sw.onClick }}" style="{{ sw.style }}" title="{{ sw.hex }}"></button>
|
||||
</sc-for>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;justify-content:flex-end">
|
||||
<button class="btn btn-secondary" style="border-radius:999px" onClick="{{ onCloseDlg }}">Never mind</button>
|
||||
<button class="btn btn-primary" style="border-radius:999px" onClick="{{ onCreatePlant }}">Add it</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script>
|
||||
class Component extends DCLogic {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
q: '', cat: 'all', openId: null, dlg: null, scanStep: 0, matchSel: 1,
|
||||
aName: '', aCat: 'vegetable', aSp: 12, aColor: '#97a97c',
|
||||
plants: [
|
||||
{ id: 1, name: 'Garlic', letter: 'G', color: '#97a97c', cat: 'vegetable', spacing: '6″', days: 240, builtin: true, lots: [{ vendor: 'Johnny\u2019s \u2014 Music', year: 2025, detail: '50 cloves \u00b7 ~14 left after this season\u2019s beds' }] },
|
||||
{ id: 2, name: 'Tomato — Cherokee Purple', letter: 'T', color: '#c8553d', cat: 'vegetable', spacing: '24″', days: 80, builtin: false, lots: [{ vendor: 'Baker Creek', year: 2026, detail: '25 seeds \u00b7 95% germination \u00b7 ~22 left' }] },
|
||||
{ id: 3, name: 'Cucumber — Marketmore', letter: 'C', color: '#6f8f4f', cat: 'vegetable', spacing: '12″', days: 65, builtin: false, lots: [] },
|
||||
{ id: 4, name: 'Watermelon — Sugar Baby', letter: 'W', color: '#46683c', cat: 'fruit', spacing: '36″', days: 78, builtin: false, lots: [{ vendor: 'Ferry-Morse', year: 2025, detail: '20 seeds \u00b7 ~16 left' }] },
|
||||
{ id: 5, name: 'Basil — Genovese', letter: 'B', color: '#5f8f45', cat: 'herb', spacing: '10″', days: 60, builtin: true, lots: [] },
|
||||
{ id: 6, name: 'Pepper — Jalapeño', letter: 'P', color: '#b2622d', cat: 'vegetable', spacing: '18″', days: 75, builtin: false, lots: [] },
|
||||
{ id: 7, name: 'Marigold', letter: 'Ma', color: '#d9912f', cat: 'flower', spacing: '8″', days: 50, builtin: true, lots: [] },
|
||||
{ id: 8, name: 'Melon — Hale\u2019s Best', letter: 'Me', color: '#c2913a', cat: 'fruit', spacing: '36″', days: 85, builtin: false, lots: [] },
|
||||
{ id: 9, name: 'Carrot — Danvers', letter: 'Cr', color: '#d07a2e', cat: 'vegetable', spacing: '3″', days: 70, builtin: true, lots: [] },
|
||||
{ id: 10, name: 'Bush bean — Provider', letter: 'Bn', color: '#7c9a55', cat: 'vegetable', spacing: '6″', days: 55, builtin: true, lots: [] },
|
||||
{ id: 11, name: 'Zinnia', letter: 'Z', color: '#c65a4e', cat: 'flower', spacing: '10″', days: 60, builtin: true, lots: [] },
|
||||
{ id: 12, name: 'Thyme', letter: 'Th', color: '#6d7f5a', cat: 'herb', spacing: '8″', days: 90, builtin: true, lots: [] },
|
||||
],
|
||||
};
|
||||
this.nid = 100;
|
||||
}
|
||||
componentDidMount() { this.themeMount(); }
|
||||
componentWillUnmount() { this._unwatchTheme && this._unwatchTheme(); }
|
||||
themeMount() {
|
||||
const PT = window.PansyTheme; if (!PT) return;
|
||||
this.setState({ themePref: PT.get() });
|
||||
this._unwatchTheme = PT.watch(() => { if ((this.state.themePref || 'system') === 'system') PT.apply(PT.isDark('system')); });
|
||||
}
|
||||
cycleTheme = () => { const PT = window.PansyTheme; if (!PT) return; const p = PT.next(this.state.themePref || 'system'); PT.set(p); PT.apply(PT.isDark(p)); this.setState({ themePref: p }); };
|
||||
themeVals() {
|
||||
const p = this.state.themePref || 'system';
|
||||
const d = window.PansyTheme ? window.PansyTheme.icon(p) : ['', '', ''];
|
||||
return { themeD1: d[0], themeD2: d[1], themeD3: d[2], onTheme: this.cycleTheme, themeTitle: 'Theme: ' + p };
|
||||
}
|
||||
renderVals() {
|
||||
const st = this.state;
|
||||
const ql = st.q.trim().toLowerCase();
|
||||
const catList = [['all', 'All'], ['vegetable', 'Vegetables'], ['herb', 'Herbs'], ['flower', 'Flowers'], ['fruit', 'Fruit']];
|
||||
const shown = st.plants.filter(p => (st.cat === 'all' || p.cat === st.cat) && (!ql || p.name.toLowerCase().includes(ql)));
|
||||
return {
|
||||
...this.themeVals(),
|
||||
q: st.q, onQ: (e) => this.setState({ q: e.target.value }),
|
||||
cats: catList.map(([id, label]) => ({
|
||||
key: id, label,
|
||||
style: { cursor: 'pointer', border: '1px solid ' + (st.cat === id ? 'var(--color-accent-400)' : 'var(--color-divider)'), borderRadius: '999px', padding: '7px 16px', fontFamily: 'var(--font-body)', fontSize: '13px', fontWeight: 700, background: st.cat === id ? 'var(--color-accent-200)' : 'transparent', color: st.cat === id ? 'var(--color-accent-800)' : 'var(--p-ink-soft)' },
|
||||
onClick: () => this.setState({ cat: id }),
|
||||
})),
|
||||
cardsR: shown.map(p => ({
|
||||
key: p.id, name: p.name, letter: p.letter, color: p.color, builtin: p.builtin,
|
||||
sub: p.cat[0].toUpperCase() + p.cat.slice(1) + ' · ' + p.spacing + ' spacing · ' + p.days + ' days',
|
||||
lotText: p.lots.length ? p.lots.length + (p.lots.length === 1 ? ' seed lot' : ' seed lots') + ' · click to see' : 'No seed lots · click to expand',
|
||||
open: st.openId === p.id,
|
||||
lots: p.lots.map((l, i) => ({ key: i, ...l })),
|
||||
noLots: !p.lots.length,
|
||||
cardStyle: { background: 'var(--color-neutral-100)', border: '1px solid ' + (st.openId === p.id ? 'var(--color-accent-400)' : 'var(--color-divider)'), borderRadius: 'var(--radius-lg)', padding: '16px 18px', cursor: 'pointer', position: 'relative' },
|
||||
onClick: () => this.setState(s2 => ({ openId: s2.openId === p.id ? null : p.id })),
|
||||
})),
|
||||
dlgScan: st.dlg === 'scan', dlgAdd: st.dlg === 'add',
|
||||
scanStep0: st.scanStep === 0, scanStep1: st.scanStep === 1,
|
||||
onScan: () => this.setState({ dlg: 'scan', scanStep: 0, matchSel: 1 }),
|
||||
onAdd: () => this.setState({ dlg: 'add', aName: '', aCat: 'vegetable', aSp: 12, aColor: '#97a97c' }),
|
||||
onCloseDlg: () => this.setState({ dlg: null }),
|
||||
stop: (e) => e.stopPropagation(),
|
||||
onScanGo: () => this.setState({ scanStep: 1 }),
|
||||
matches: [
|
||||
{ label: 'Garlic (built-in)', sub: 'existing plant \u2014 lot attaches to it' },
|
||||
{ label: 'Garlic \u2014 Music (yours)', sub: 'best match \u00b7 spacing 6\u2033' },
|
||||
{ label: 'Create a new plant', sub: 'from the extracted fields' },
|
||||
].map((m, i) => ({
|
||||
key: i, ...m,
|
||||
style: { display: 'flex', alignItems: 'center', gap: '8px', textAlign: 'left', cursor: 'pointer', borderRadius: '999px', padding: '10px 16px', fontFamily: 'var(--font-body)', background: st.matchSel === i ? 'var(--color-accent-200)' : 'var(--color-bg)', border: st.matchSel === i ? '1px solid var(--color-accent-400)' : '1px solid var(--color-divider)' },
|
||||
onClick: () => this.setState({ matchSel: i }),
|
||||
})),
|
||||
onConfirmScan: () => this.setState(s2 => ({
|
||||
dlg: null,
|
||||
plants: s2.plants.map(p => p.id === 1 ? { ...p, lots: [...p.lots, { vendor: 'Keene Organics \u2014 Music', year: 2026, detail: '50 cloves \u00b7 untouched' }] } : p),
|
||||
openId: 1,
|
||||
})),
|
||||
aName: st.aName, onAName: (e) => this.setState({ aName: e.target.value }),
|
||||
aCat: st.aCat, onACat: (e) => this.setState({ aCat: e.target.value }),
|
||||
aSp: st.aSp, onASp: (e) => this.setState({ aSp: e.target.value }),
|
||||
swatches: ['#97a97c', '#c8553d', '#5f8f45', '#d9912f', '#b2622d', '#6d7f5a'].map(hex => ({
|
||||
key: hex, hex,
|
||||
style: { width: '30px', height: '30px', borderRadius: '999px', cursor: 'pointer', background: hex, border: st.aColor === hex ? '3px solid var(--color-accent)' : '3px solid transparent' },
|
||||
onClick: () => this.setState({ aColor: hex }),
|
||||
})),
|
||||
onCreatePlant: () => this.setState(s2 => ({
|
||||
dlg: null,
|
||||
plants: [...s2.plants, { id: this.nid++, name: s2.aName.trim() || 'New plant', letter: (s2.aName.trim()[0] || 'N').toUpperCase(), color: s2.aColor, cat: s2.aCat, spacing: s2.aSp + '″', days: 70, builtin: false, lots: [] }],
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user