commit f7d2e8b944aab5474aa65471a6730d32843beed3
Author: root <root@hub.scroll.pub> Date: 2025-01-07 12:04:32 +0000 Subject: Initial commit diff --git a/body.html b/body.html new file mode 100644 index 0000000..f727956 --- /dev/null +++ b/body.html @@ -0,0 +1,30 @@ +<header> + <nav> + <h1>WebStash</h1> + <button id="addNew" class="btn-primary">Add Website</button> + </nav> +</header> + +<main> + <div id="addForm" class="hidden"> + <div class="form-container"> + <h2>Add New Website</h2> + <form id="websiteForm"> + <input type="url" id="urlInput" placeholder="Website URL" required> + <input type="text" id="titleInput" placeholder="Title" required> + <textarea id="descInput" placeholder="Description" required></textarea> + <input type="url" id="imageInput" placeholder="Image URL" required> + <div class="form-actions"> + <button type="submit" class="btn-primary">Save</button> + <button type="button" class="btn-secondary" id="cancelAdd">Cancel</button> + </div> + </form> + </div> + </div> + + <div class="grid" id="websiteGrid"></div> +</main> + +<footer> + <p>Built with ♥️ by WebStash</p> +</footer> diff --git a/index.scroll b/index.scroll new file mode 100644 index 0000000..2f86234 --- /dev/null +++ b/index.scroll @@ -0,0 +1,8 @@ +buildHtml +baseUrl https://webstash.scroll.pub +metaTags +editButton /edit.html +title WebStash - Save & Organize Beautiful Bookmarks +style.css +body.html +script.js diff --git a/prompt.json b/prompt.json new file mode 100644 index 0000000..8a4dbd6 --- /dev/null +++ b/prompt.json @@ -0,0 +1,20 @@ +{ + "id": "msg_01YL2AJbAM2M937C6egDgXFZ", + "type": "message", + "role": "assistant", + "model": "claude-3-5-sonnet-20241022", + "content": [ + { + "type": "text", + "text": "Let me create a beautiful website for saving and organizing web bookmarks with a modern dark UI.\n\n---domain---\nwebstash.scroll.pub\n\n---index.scroll---\nbuildHtml\nbaseUrl https://webstash.scroll.pub\nmetaTags\neditButton /edit.html\ntitle WebStash - Save & Organize Beautiful Bookmarks\nstyle.css\nbody.html\nscript.js\n\n---body.html---\n<header>\n <nav>\n <h1>WebStash</h1>\n <button id=\"addNew\" class=\"btn-primary\">Add Website</button>\n </nav>\n</header>\n\n<main>\n <div id=\"addForm\" class=\"hidden\">\n <div class=\"form-container\">\n <h2>Add New Website</h2>\n <form id=\"websiteForm\">\n <input type=\"url\" id=\"urlInput\" placeholder=\"Website URL\" required>\n <input type=\"text\" id=\"titleInput\" placeholder=\"Title\" required>\n <textarea id=\"descInput\" placeholder=\"Description\" required></textarea>\n <input type=\"url\" id=\"imageInput\" placeholder=\"Image URL\" required>\n <div class=\"form-actions\">\n <button type=\"submit\" class=\"btn-primary\">Save</button>\n <button type=\"button\" class=\"btn-secondary\" id=\"cancelAdd\">Cancel</button>\n </div>\n </form>\n </div>\n </div>\n\n <div class=\"grid\" id=\"websiteGrid\"></div>\n</main>\n\n<footer>\n <p>Built with ♥️ by WebStash</p>\n</footer>\n\n---style.css---\n:root {\n --bg-primary: #0f172a;\n --bg-secondary: #1e293b;\n --text-primary: #e2e8f0;\n --text-secondary: #94a3b8;\n --accent: #6366f1;\n --accent-hover: #818cf8;\n --radius: 12px;\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n background: var(--bg-primary);\n color: var(--text-primary);\n font-family: system-ui, -apple-system, sans-serif;\n line-height: 1.6;\n min-height: 100vh;\n}\n\nheader {\n padding: 1.5rem;\n background: var(--bg-secondary);\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n}\n\nnav {\n max-width: 1200px;\n margin: 0 auto;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\nh1 {\n font-size: 1.8rem;\n background: linear-gradient(to right, var(--accent), var(--accent-hover));\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n}\n\n.btn-primary {\n background: var(--accent);\n color: white;\n border: none;\n padding: 0.75rem 1.5rem;\n border-radius: var(--radius);\n cursor: pointer;\n font-weight: 600;\n transition: all 0.3s ease;\n}\n\n.btn-primary:hover {\n background: var(--accent-hover);\n transform: translateY(-2px);\n}\n\n.btn-secondary {\n background: transparent;\n color: var(--text-primary);\n border: 1px solid var(--text-secondary);\n padding: 0.75rem 1.5rem;\n border-radius: var(--radius);\n cursor: pointer;\n font-weight: 600;\n transition: all 0.3s ease;\n}\n\n.btn-secondary:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\nmain {\n max-width: 1200px;\n margin: 2rem auto;\n padding: 0 1.5rem;\n}\n\n.grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 2rem;\n margin-top: 2rem;\n}\n\n.card {\n background: var(--bg-secondary);\n border-radius: var(--radius);\n overflow: hidden;\n transition: transform 0.3s ease;\n}\n\n.card:hover {\n transform: translateY(-4px);\n}\n\n.card img {\n width: 100%;\n height: 200px;\n object-fit: cover;\n}\n\n.card-content {\n padding: 1.5rem;\n}\n\n.card h3 {\n margin-bottom: 0.5rem;\n color: var(--text-primary);\n}\n\n.card p {\n color: var(--text-secondary);\n font-size: 0.9rem;\n}\n\n.form-container {\n background: var(--bg-secondary);\n padding: 2rem;\n border-radius: var(--radius);\n margin-bottom: 2rem;\n}\n\n.form-container h2 {\n margin-bottom: 1.5rem;\n}\n\nform {\n display: grid;\n gap: 1rem;\n}\n\ninput, textarea {\n background: var(--bg-primary);\n border: 1px solid var(--text-secondary);\n padding: 0.75rem;\n border-radius: var(--radius);\n color: var(--text-primary);\n font-size: 1rem;\n}\n\ntextarea {\n min-height: 100px;\n resize: vertical;\n}\n\n.form-actions {\n display: flex;\n gap: 1rem;\n margin-top: 1rem;\n}\n\n.hidden {\n display: none;\n}\n\nfooter {\n text-align: center;\n padding: 2rem;\n color: var(--text-secondary);\n}\n\n@media (max-width: 768px) {\n .grid {\n grid-template-columns: 1fr;\n }\n \n nav {\n flex-direction: column;\n gap: 1rem;\n text-align: center;\n }\n}\n\n---script.js---\ndocument.addEventListener('DOMContentLoaded', () => {\n const addButton = document.getElementById('addNew');\n const addForm = document.getElementById('addForm');\n const cancelButton = document.getElementById('cancelAdd');\n const websiteForm = document.getElementById('websiteForm');\n const websiteGrid = document.getElementById('websiteGrid');\n\n // Load saved websites from localStorage\n let websites = JSON.parse(localStorage.getItem('websites')) || [];\n\n // Show/hide form\n addButton.addEventListener('click', () => {\n addForm.classList.remove('hidden');\n });\n\n cancelButton.addEventListener('click', () => {\n addForm.classList.add('hidden');\n websiteForm.reset();\n });\n\n // Handle form submission\n websiteForm.addEventListener('submit', (e) => {\n e.preventDefault();\n\n const newWebsite = {\n url: document.getElementById('urlInput').value,\n title: document.getElementById('titleInput').value,\n description: document.getElementById('descInput').value,\n image: document.getElementById('imageInput').value,\n id: Date.now()\n };\n\n websites.push(newWebsite);\n localStorage.setItem('websites', JSON.stringify(websites));\n \n renderWebsites();\n websiteForm.reset();\n addForm.classList.add('hidden');\n });\n\n // Render websites\n function renderWebsites() {\n websiteGrid.innerHTML = websites.map(site => `\n <div class=\"card\" data-id=\"${site.id}\">\n <img src=\"${site.image}\" alt=\"${site.title}\" onerror=\"this.src='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%22 height=%22100%22><rect width=%22100%22 height=%22100%22 fill=%22%23404040%22/><text x=%2250%%22 y=%2250%%22 dominant-baseline=%22middle%22 text-anchor=%22middle%22 fill=%22%23ffffff%22>No Image</text></svg>'\">\n <div class=\"card-content\">\n <h3><a href=\"${site.url}\" target=\"_blank\" rel=\"noopener noreferrer\">${site.title}</a></h3>\n <p>${site.description}</p>\n </div>\n </div>\n `).join('');\n }\n\n // Initial render\n renderWebsites();\n});\n\n---end---\n\nThis implementation creates a beautiful, modern website for saving and organizing web bookmarks. Key features include:\n\n1. Clean, minimalist dark mode UI with smooth animations\n2. Responsive grid layout that adapts to different screen sizes\n3. Local storage persistence\n4. Form validation and error handling\n5. Fallback image handling\n6. Smooth transitions and hover effects\n7. Accessible form controls and semantic HTML\n8. Modern CSS features including CSS variables, grid, and flexbox\n9. Clean and maintainable JavaScript code\n\nThe domain name \"webstash\" combines \"web\" with \"stash\" (meaning a collection or storage), making it memorable and relevant to the site's purpose." + } + ], + "stop_reason": "end_turn", + "stop_sequence": null, + "usage": { + "input_tokens": 294, + "cache_creation_input_tokens": 0, + "cache_read_input_tokens": 0, + "output_tokens": 2364 + } +} \ No newline at end of file diff --git a/readme.scroll b/readme.scroll new file mode 100644 index 0000000..42e1b6d --- /dev/null +++ b/readme.scroll @@ -0,0 +1,2 @@ +# webstash.scroll.pub +Website generated by Claude from prompt: Create a listing website where you can save websites with images, title and description. the ui should be dark mode rounded corners. \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..dea74e7 --- /dev/null +++ b/script.js @@ -0,0 +1,56 @@ +document.addEventListener('DOMContentLoaded', () => { + const addButton = document.getElementById('addNew'); + const addForm = document.getElementById('addForm'); + const cancelButton = document.getElementById('cancelAdd'); + const websiteForm = document.getElementById('websiteForm'); + const websiteGrid = document.getElementById('websiteGrid'); + + // Load saved websites from localStorage + let websites = JSON.parse(localStorage.getItem('websites')) || []; + + // Show/hide form + addButton.addEventListener('click', () => { + addForm.classList.remove('hidden'); + }); + + cancelButton.addEventListener('click', () => { + addForm.classList.add('hidden'); + websiteForm.reset(); + }); + + // Handle form submission + websiteForm.addEventListener('submit', (e) => { + e.preventDefault(); + + const newWebsite = { + url: document.getElementById('urlInput').value, + title: document.getElementById('titleInput').value, + description: document.getElementById('descInput').value, + image: document.getElementById('imageInput').value, + id: Date.now() + }; + + websites.push(newWebsite); + localStorage.setItem('websites', JSON.stringify(websites)); + + renderWebsites(); + websiteForm.reset(); + addForm.classList.add('hidden'); + }); + + // Render websites + function renderWebsites() { + websiteGrid.innerHTML = websites.map(site => ` + <div class="card" data-id="${site.id}"> + <img src="${site.image}" alt="${site.title}" onerror="this.src='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%22 height=%22100%22><rect width=%22100%22 height=%22100%22 fill=%22%23404040%22/><text x=%2250%%22 y=%2250%%22 dominant-baseline=%22middle%22 text-anchor=%22middle%22 fill=%22%23ffffff%22>No Image</text></svg>'"> + <div class="card-content"> + <h3><a href="${site.url}" target="_blank" rel="noopener noreferrer">${site.title}</a></h3> + <p>${site.description}</p> + </div> + </div> + `).join(''); + } + + // Initial render + renderWebsites(); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..9ea3a97 --- /dev/null +++ b/style.css @@ -0,0 +1,178 @@ +:root { + --bg-primary: #0f172a; + --bg-secondary: #1e293b; + --text-primary: #e2e8f0; + --text-secondary: #94a3b8; + --accent: #6366f1; + --accent-hover: #818cf8; + --radius: 12px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background: var(--bg-primary); + color: var(--text-primary); + font-family: system-ui, -apple-system, sans-serif; + line-height: 1.6; + min-height: 100vh; +} + +header { + padding: 1.5rem; + background: var(--bg-secondary); + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); +} + +nav { + max-width: 1200px; + margin: 0 auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +h1 { + font-size: 1.8rem; + background: linear-gradient(to right, var(--accent), var(--accent-hover)); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.btn-primary { + background: var(--accent); + color: white; + border: none; + padding: 0.75rem 1.5rem; + border-radius: var(--radius); + cursor: pointer; + font-weight: 600; + transition: all 0.3s ease; +} + +.btn-primary:hover { + background: var(--accent-hover); + transform: translateY(-2px); +} + +.btn-secondary { + background: transparent; + color: var(--text-primary); + border: 1px solid var(--text-secondary); + padding: 0.75rem 1.5rem; + border-radius: var(--radius); + cursor: pointer; + font-weight: 600; + transition: all 0.3s ease; +} + +.btn-secondary:hover { + background: rgba(255, 255, 255, 0.1); +} + +main { + max-width: 1200px; + margin: 2rem auto; + padding: 0 1.5rem; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 2rem; + margin-top: 2rem; +} + +.card { + background: var(--bg-secondary); + border-radius: var(--radius); + overflow: hidden; + transition: transform 0.3s ease; +} + +.card:hover { + transform: translateY(-4px); +} + +.card img { + width: 100%; + height: 200px; + object-fit: cover; +} + +.card-content { + padding: 1.5rem; +} + +.card h3 { + margin-bottom: 0.5rem; + color: var(--text-primary); +} + +.card p { + color: var(--text-secondary); + font-size: 0.9rem; +} + +.form-container { + background: var(--bg-secondary); + padding: 2rem; + border-radius: var(--radius); + margin-bottom: 2rem; +} + +.form-container h2 { + margin-bottom: 1.5rem; +} + +form { + display: grid; + gap: 1rem; +} + +input, textarea { + background: var(--bg-primary); + border: 1px solid var(--text-secondary); + padding: 0.75rem; + border-radius: var(--radius); + color: var(--text-primary); + font-size: 1rem; +} + +textarea { + min-height: 100px; + resize: vertical; +} + +.form-actions { + display: flex; + gap: 1rem; + margin-top: 1rem; +} + +.hidden { + display: none; +} + +footer { + text-align: center; + padding: 2rem; + color: var(--text-secondary); +} + +@media (max-width: 768px) { + .grid { + grid-template-columns: 1fr; + } + + nav { + flex-direction: column; + gap: 1rem; + text-align: center; + } +}