diff --git a/bun.lock b/bun.lock index 23a3a85..d3f2578 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "item-extractor-solid", "dependencies": { + "@solidjs/router": "^0.15.4", "@tailwindcss/typography": "^0.5.19", "lucide-solid": "^0.577.0", "solid-element": "^1.9.1", @@ -171,6 +172,8 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g=="], + "@solidjs/router": ["@solidjs/router@0.15.4", "", { "peerDependencies": { "solid-js": "^1.8.6" } }, "sha512-WOpgg9a9T638cR+5FGbFi/IV4l2FpmBs1GpIMSPa0Ce9vyJN7Wts+X2PqMf9IYn0zUj2MlSJtm1gp7/HI/n5TQ=="], + "@tailwindcss/node": ["@tailwindcss/node@4.2.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.1" } }, "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.1", "@tailwindcss/oxide-darwin-arm64": "4.2.1", "@tailwindcss/oxide-darwin-x64": "4.2.1", "@tailwindcss/oxide-freebsd-x64": "4.2.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", "@tailwindcss/oxide-linux-x64-musl": "4.2.1", "@tailwindcss/oxide-wasm32-wasi": "4.2.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" } }, "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw=="], diff --git a/index.html b/index.html index 382fa22..9dd3c18 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ - +
diff --git a/package.json b/package.json index 9e7b1ea..c818cb4 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "@solidjs/router": "^0.15.4", "@tailwindcss/typography": "^0.5.19", "lucide-solid": "^0.577.0", "solid-element": "^1.9.1", diff --git a/src/AppContainer.tsx b/src/AppContainer.tsx new file mode 100644 index 0000000..0274fd3 --- /dev/null +++ b/src/AppContainer.tsx @@ -0,0 +1,49 @@ +import type { Component } from 'solid-js'; +import { A } from '@solidjs/router'; + +interface AppContainerProps { + children?: any; +} + +const AppContainer: Component = (props) => { + return ( +
+ {/* Top Navigation Bar */} +
+
+
+ +
+
+
+ + {/* Main Content Area */} +
+ {props.children} +
+
+ ); +}; + +export default AppContainer; diff --git a/src/ItemExtractor.tsx b/src/ItemExtractor.tsx index cdc64c7..8162e8a 100644 --- a/src/ItemExtractor.tsx +++ b/src/ItemExtractor.tsx @@ -1,6 +1,6 @@ import type { Component } from 'solid-js'; import { createSignal, Show } from 'solid-js'; -import { customElement, noShadowDOM } from 'solid-element'; + import FileUpload from './components/FileUpload'; import EstimateBuilder from './components/EstimateBuilder'; import IgnoredLinesList from './components/IgnoredLinesList'; @@ -15,7 +15,7 @@ interface ItemExtractorProps { } const ItemExtractor: Component = () => { - noShadowDOM(); + const [items, setItems] = createSignal([]); const [ignoredLines, setIgnoredLines] = createSignal([]); const [showToast] = createSignal(false); @@ -77,7 +77,4 @@ const ItemExtractor: Component = () => { ); }; -// Register as Custom Element -customElement('item-extractor', { onItemsExtracted: undefined, onCopy: undefined }, ItemExtractor); - export default ItemExtractor; diff --git a/src/components/template/TemplateItemList.tsx b/src/components/template/TemplateItemList.tsx new file mode 100644 index 0000000..f6ed677 --- /dev/null +++ b/src/components/template/TemplateItemList.tsx @@ -0,0 +1,49 @@ +import type { Component } from 'solid-js'; +import { For } from 'solid-js'; +import { Plus } from 'lucide-solid'; +import type { TemplateItem } from '../../types'; +import TemplateItemRow from './TemplateItemRow'; + +interface TemplateItemListProps { + items: TemplateItem[]; + onUpdateItem: (id: string, updates: Partial) => void; + onDeleteItem: (id: string) => void; + onAddItem: () => void; +} + +const TemplateItemList: Component = (props) => { + return ( +
+
+

Template Items

+ +
+ +
+ + {(item) => ( + + )} + + + {props.items.length === 0 && ( +
+

No items added yet. Click "Add Item" to start building this template.

+
+ )} +
+
+ ); +}; + +export default TemplateItemList; diff --git a/src/components/template/TemplateItemRow.tsx b/src/components/template/TemplateItemRow.tsx new file mode 100644 index 0000000..9439587 --- /dev/null +++ b/src/components/template/TemplateItemRow.tsx @@ -0,0 +1,97 @@ +import type { Component } from 'solid-js'; +import { createSignal, createEffect } from 'solid-js'; +import { Trash2, GripVertical } from 'lucide-solid'; +import type { TemplateItem } from '../../types'; + +interface TemplateItemRowProps { + item: TemplateItem; + onUpdate: (id: string, updates: Partial) => void; + onDelete: (id: string) => void; +} + +const TemplateItemRow: Component = (props) => { + let descriptionRef: HTMLTextAreaElement | undefined; + const [isEditing, setIsEditing] = createSignal(false); + const [localDescription, setLocalDescription] = createSignal(props.item.description); + + createEffect(() => { + if (!isEditing()) { + setLocalDescription(props.item.description); + } + }); + + const handleBlur = () => { + const currentDesc = localDescription(); + if (currentDesc !== props.item.description) { + props.onUpdate(props.item.id, { description: currentDesc }); + } + setIsEditing(false); + }; + + return ( +
+ +
+ +
+ +
+