├── README.md ├── src ├── index.html ├── script.js └── style.css ├── dist ├── index.html ├── script.js └── style.css └── LICENSE.txt /README.md: -------------------------------------------------------------------------------- 1 | # Fireproof Homepage Demo 2 | 3 | A Pen created on CodePen.io. Original URL: [https://codepen.io/jchrisa/pen/bGOGvBz](https://codepen.io/jchrisa/pen/bGOGvBz). 4 | 5 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Fireproof Example 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CodePen - Fireproof Homepage Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Fireproof Example 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Chris Anderson (https://codepen.io/jchrisa/pen/bGOGvBz) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/script.js: -------------------------------------------------------------------------------- 1 | db = connect("fireproof"); 2 | 3 | function addItemDb(text) { 4 | db.put({ 5 | text, 6 | done: false, 7 | created: Date.now() 8 | }); 9 | } 10 | 11 | function addItem(e) { 12 | e.preventDefault(); 13 | const input = document.querySelector("form input"); 14 | if (!input.value) return; 15 | addItemDb(input.value); 16 | input.value = ""; 17 | } 18 | window.addItem = addItem; 19 | 20 | function toggleDone(doc) { 21 | doc.done = !doc.done; 22 | doc.updated = Date.now(); 23 | db.put(doc); 24 | } 25 | 26 | async function redraw() { 27 | const result = await db.query("created", { 28 | includeDocs: true, 29 | descending: true, 30 | limit: 10 31 | }); 32 | 33 | document.querySelector("ul").innerHTML = ""; 34 | 35 | for (const row of result.rows) { 36 | const textSpan = document.createElement("span"); 37 | textSpan.innerText = row.doc.text; 38 | 39 | const checkbox = document.createElement("input"); 40 | checkbox.onchange = () => { 41 | toggleDone(row.doc); 42 | }; 43 | if (row.doc.done) { 44 | checkbox.setAttribute("checked", true); 45 | } 46 | checkbox.setAttribute("type", "checkbox"); 47 | 48 | const deleteSpan = document.createElement("span"); 49 | deleteSpan.innerText = "x"; 50 | deleteSpan.style = "text-align:right; color:#999"; 51 | deleteSpan.onclick = function (e) { 52 | e.preventDefault(); 53 | db.del(row.id); 54 | if (result.rows.length <= 1) reset(); 55 | }; 56 | 57 | const li = document.createElement("li"); 58 | li.appendChild(checkbox); 59 | li.appendChild(textSpan); 60 | li.appendChild(deleteSpan); 61 | 62 | document.querySelector("ul").appendChild(li); 63 | } 64 | } 65 | 66 | const fixtures = [ 67 | "Merkle integrity", 68 | "Runs in any cloud", 69 | "End-to-end encryption", 70 | "JSON documents", 71 | "Open-source connectors", 72 | "Commodity storage", 73 | "Serverless architecture", 74 | "Immutable history", 75 | "Self-sovereign auth", 76 | "Cloudless operation", 77 | "Event-driven architecture", 78 | "React state management" 79 | ]; 80 | 81 | function getRandomThree(arr) { 82 | let result = ["Multi-writer CRDT"]; 83 | let clonedArray = [...arr]; 84 | 85 | for (let i = 1; i < 3; i++) { 86 | let randomIndex = Math.floor(Math.random() * clonedArray.length); 87 | result.push(clonedArray[randomIndex]); 88 | clonedArray.splice(randomIndex, 1); 89 | } 90 | 91 | return result; 92 | } 93 | 94 | async function reset(e) { 95 | if (e) e.preventDefault(); 96 | const allDocs = await db.allDocs(); 97 | for (const row of allDocs.rows) { 98 | db.del(row.key); 99 | } 100 | 101 | const puts = getRandomThree(fixtures).map((text) => { 102 | db.put({ 103 | created: Date.now(), 104 | text, 105 | done: true 106 | }); 107 | }); 108 | await Promise.all(puts); 109 | 110 | db.compact(); 111 | } 112 | window.reset = reset; 113 | 114 | window.onload = function initialize() { 115 | db.subscribe(redraw); 116 | redraw(); 117 | // reset() // remove when connected 118 | }; 119 | 120 | function connect(name) { 121 | const db = Fireproof.fireproof(name + 7); 122 | // placeholder until Fireproof Cloud ships 123 | FireproofConnect.connect.partykitS3( 124 | db, 125 | "https://firehouse-chat.jchris.partykit.dev" 126 | ); 127 | return db; 128 | } 129 | 130 | // for another app that syncs live with the same dataset see 131 | // https://replit.com/@jchris5/HTML-CSS-JS-Auto-Refresh#script.js -------------------------------------------------------------------------------- /src/script.js: -------------------------------------------------------------------------------- 1 | db = connect("fireproof"); 2 | 3 | function addItemDb(text) { 4 | db.put({ 5 | text, 6 | done: false, 7 | created: Date.now() 8 | }); 9 | } 10 | 11 | function addItem(e) { 12 | e.preventDefault(); 13 | const input = document.querySelector("form input"); 14 | if (!input.value) return; 15 | addItemDb(input.value); 16 | input.value = ""; 17 | } 18 | window.addItem = addItem; 19 | 20 | function toggleDone(doc) { 21 | doc.done = !doc.done; 22 | doc.updated = Date.now(); 23 | db.put(doc); 24 | } 25 | 26 | async function redraw() { 27 | const result = await db.query("created", { 28 | includeDocs: true, 29 | descending: true, 30 | limit: 10 31 | }); 32 | 33 | document.querySelector("ul").innerHTML = ""; 34 | 35 | for (const row of result.rows) { 36 | const textSpan = document.createElement("span"); 37 | textSpan.innerText = row.doc.text; 38 | 39 | const checkbox = document.createElement("input"); 40 | checkbox.onchange = () => { 41 | toggleDone(row.doc); 42 | }; 43 | if (row.doc.done) { 44 | checkbox.setAttribute("checked", true); 45 | } 46 | checkbox.setAttribute("type", "checkbox"); 47 | 48 | const deleteSpan = document.createElement("span"); 49 | deleteSpan.innerText = "x"; 50 | deleteSpan.style = "text-align:right; color:#999"; 51 | deleteSpan.onclick = function (e) { 52 | e.preventDefault(); 53 | db.del(row.id); 54 | if (result.rows.length <= 1) reset(); 55 | }; 56 | 57 | const li = document.createElement("li"); 58 | li.appendChild(checkbox); 59 | li.appendChild(textSpan); 60 | li.appendChild(deleteSpan); 61 | 62 | document.querySelector("ul").appendChild(li); 63 | } 64 | } 65 | 66 | const fixtures = [ 67 | "Merkle integrity", 68 | "Runs in any cloud", 69 | "End-to-end encryption", 70 | "JSON documents", 71 | "Open-source connectors", 72 | "Commodity storage", 73 | "Serverless architecture", 74 | "Immutable history", 75 | "Self-sovereign auth", 76 | "Cloudless operation", 77 | "Event-driven architecture", 78 | "React state management" 79 | ]; 80 | 81 | function getRandomThree(arr) { 82 | let result = ["Multi-writer CRDT"]; 83 | let clonedArray = [...arr]; 84 | 85 | for (let i = 1; i < 3; i++) { 86 | let randomIndex = Math.floor(Math.random() * clonedArray.length); 87 | result.push(clonedArray[randomIndex]); 88 | clonedArray.splice(randomIndex, 1); 89 | } 90 | 91 | return result; 92 | } 93 | 94 | async function reset(e) { 95 | if (e) e.preventDefault(); 96 | const allDocs = await db.allDocs(); 97 | for (const row of allDocs.rows) { 98 | db.del(row.key); 99 | } 100 | 101 | const puts = getRandomThree(fixtures).map((text) => { 102 | db.put({ 103 | created: Date.now(), 104 | text, 105 | done: true 106 | }); 107 | }); 108 | await Promise.all(puts); 109 | 110 | db.compact(); 111 | } 112 | window.reset = reset; 113 | 114 | window.onload = function initialize() { 115 | db.subscribe(redraw); 116 | redraw(); 117 | // reset() // remove when connected 118 | }; 119 | 120 | function connect(name) { 121 | const db = Fireproof.fireproof(name + 7); 122 | // placeholder until Fireproof Cloud ships 123 | FireproofConnect.connect.partykitS3( 124 | db, 125 | "https://firehouse-chat.jchris.partykit.dev" 126 | ); 127 | return db; 128 | } 129 | 130 | // for another app that syncs live with the same dataset see 131 | // https://replit.com/@jchris5/HTML-CSS-JS-Auto-Refresh#script.js 132 | -------------------------------------------------------------------------------- /dist/style.css: -------------------------------------------------------------------------------- 1 | /* General styles for dark mode */ 2 | body { 3 | background-color: #121212; /* Dark background */ 4 | color: #e0e0e0; /* Light text */ 5 | font-family: Arial, sans-serif; /* Change to your preferred font */ 6 | } 7 | 8 | /* Container Styles */ 9 | .container { 10 | display: flex; /* Use flexbox for alignment */ 11 | flex-direction: column; /* Stack form and list vertically */ 12 | align-items: center; /* Center items horizontally */ 13 | max-width: 600px; /* Limit the maximum width */ 14 | margin: 0 auto; /* Center the container horizontally */ 15 | } 16 | 17 | /* Unordered List Styles */ 18 | ul { 19 | list-style-type: none; /* Remove default bullets */ 20 | padding: 0; 21 | margin: 0; 22 | width: 100%; /* Make the list take the full width of the container */ 23 | } 24 | 25 | /* List Item Styles */ 26 | ul > li { 27 | display: flex; /* Use flexbox for alignment */ 28 | align-items: center; /* Center items vertically */ 29 | background-color: #1e1e1e; /* Slightly lighter background for list items */ 30 | border: 1px solid #333; /* Border to separate items */ 31 | border-radius: 5px; /* Rounded corners */ 32 | padding: 10px; /* Spacing inside list items */ 33 | margin: 5px 0; /* Space between list items */ 34 | transition: background-color 0.3s; /* Smooth background change on hover */ 35 | } 36 | 37 | /* Hover effect */ 38 | ul > li:hover { 39 | background-color: #333; /* Darker background on hover */ 40 | cursor: pointer; /* Pointer cursor on hover */ 41 | } 42 | 43 | /* Optional: Add a subtle shadow */ 44 | ul > li { 45 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */ 46 | } 47 | 48 | /* Optional: Active or selected item */ 49 | ul > li.active { 50 | background-color: #444; /* Different color for active/selected item */ 51 | border-color: #555; /* Slightly different border for active/selected item */ 52 | } 53 | 54 | /* Checkbox Styles */ 55 | ul > li input[type="checkbox"] { 56 | appearance: none; /* Remove default checkbox style */ 57 | background-color: #2a2a2a; /* Dark background */ 58 | border: 2px solid #444; /* Border color */ 59 | border-radius: 4px; /* Rounded corners */ 60 | width: 20px; 61 | height: 20px; 62 | cursor: pointer; /* Pointer cursor */ 63 | position: relative; /* Position relative for checkmark */ 64 | transition: background-color 0.3s, border-color 0.3s; /* Smooth transition */ 65 | margin-right: 10px; /* Space between checkbox and text */ 66 | } 67 | 68 | ul > li input[type="checkbox"]:checked { 69 | background-color: #f58709; /* Green background when checked */ 70 | border-color: #f58709; /* Green border when checked */ 71 | } 72 | 73 | ul > li input[type="checkbox"]:checked::after { 74 | content: "✔"; /* Checkmark */ 75 | color: #fff; /* White checkmark color */ 76 | font-size: 14px; 77 | position: absolute; 78 | top: 50%; 79 | left: 50%; 80 | transform: translate(-50%, -50%); /* Center the checkmark */ 81 | } 82 | 83 | ul > li input[type="checkbox"]:hover { 84 | background-color: #3a3a3a; /* Slightly lighter background on hover */ 85 | border-color: #555; /* Slightly different border on hover */ 86 | } 87 | 88 | /* Text Styles inside List Items */ 89 | ul > li span { 90 | flex-grow: 1; /* Take up remaining space */ 91 | margin-left: 10px; /* Space between checkbox and text */ 92 | } 93 | 94 | /* Form Styles */ 95 | form { 96 | display: flex; /* Use flexbox for alignment */ 97 | align-items: center; /* Center items vertically */ 98 | margin-bottom: 14px; /* Space below the form */ 99 | margin-top: 10px; 100 | width: 100%; /* Make the form take the full width of the container */ 101 | padding: 0 10px; /* Add padding to left and right */ 102 | box-sizing: border-box; /* Include padding in width calculation */ 103 | } 104 | 105 | /* Input Styles */ 106 | form input[type="text"] { 107 | background-color: #2a2a2a; /* Dark background */ 108 | color: #e0e0e0; /* Light text */ 109 | border: 1px solid #444; /* Border color */ 110 | border-radius: 4px; /* Rounded corners */ 111 | padding: 8px; /* Padding inside the input */ 112 | margin-right: 10px; /* Space between input and button */ 113 | flex-grow: 1; /* Take up remaining space */ 114 | box-sizing: border-box; /* Include padding in width calculation */ 115 | } 116 | 117 | /* Button Styles */ 118 | form button { 119 | background-color: #f58709; /* Green background */ 120 | color: #fff; /* White text */ 121 | font-weight: bold; 122 | font-size: 0.8em; 123 | border: none; /* Remove default border */ 124 | border-radius: 4px; /* Rounded corners */ 125 | padding: 8px 12px; /* Padding inside the button */ 126 | cursor: pointer; /* Pointer cursor */ 127 | transition: background-color 0.3s; /* Smooth background change on hover */ 128 | white-space: nowrap; /* Prevent text wrap */ 129 | box-sizing: border-box; /* Include padding in width calculation */ 130 | } 131 | 132 | form button:hover { 133 | background-color: #f16c12; /* Darker green on hover */ 134 | } -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | /* General styles for dark mode */ 2 | body { 3 | background-color: #121212; /* Dark background */ 4 | color: #e0e0e0; /* Light text */ 5 | font-family: Arial, sans-serif; /* Change to your preferred font */ 6 | } 7 | 8 | /* Container Styles */ 9 | .container { 10 | display: flex; /* Use flexbox for alignment */ 11 | flex-direction: column; /* Stack form and list vertically */ 12 | align-items: center; /* Center items horizontally */ 13 | max-width: 600px; /* Limit the maximum width */ 14 | margin: 0 auto; /* Center the container horizontally */ 15 | } 16 | 17 | /* Unordered List Styles */ 18 | ul { 19 | list-style-type: none; /* Remove default bullets */ 20 | padding: 0; 21 | margin: 0; 22 | width: 100%; /* Make the list take the full width of the container */ 23 | } 24 | 25 | /* List Item Styles */ 26 | ul > li { 27 | display: flex; /* Use flexbox for alignment */ 28 | align-items: center; /* Center items vertically */ 29 | background-color: #1e1e1e; /* Slightly lighter background for list items */ 30 | border: 1px solid #333; /* Border to separate items */ 31 | border-radius: 5px; /* Rounded corners */ 32 | padding: 10px; /* Spacing inside list items */ 33 | margin: 5px 0; /* Space between list items */ 34 | transition: background-color 0.3s; /* Smooth background change on hover */ 35 | } 36 | 37 | /* Hover effect */ 38 | ul > li:hover { 39 | background-color: #333; /* Darker background on hover */ 40 | cursor: pointer; /* Pointer cursor on hover */ 41 | } 42 | 43 | /* Optional: Add a subtle shadow */ 44 | ul > li { 45 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Subtle shadow */ 46 | } 47 | 48 | /* Optional: Active or selected item */ 49 | ul > li.active { 50 | background-color: #444; /* Different color for active/selected item */ 51 | border-color: #555; /* Slightly different border for active/selected item */ 52 | } 53 | 54 | /* Checkbox Styles */ 55 | ul > li input[type="checkbox"] { 56 | appearance: none; /* Remove default checkbox style */ 57 | background-color: #2a2a2a; /* Dark background */ 58 | border: 2px solid #444; /* Border color */ 59 | border-radius: 4px; /* Rounded corners */ 60 | width: 20px; 61 | height: 20px; 62 | cursor: pointer; /* Pointer cursor */ 63 | position: relative; /* Position relative for checkmark */ 64 | transition: background-color 0.3s, border-color 0.3s; /* Smooth transition */ 65 | margin-right: 10px; /* Space between checkbox and text */ 66 | } 67 | 68 | ul > li input[type="checkbox"]:checked { 69 | background-color: #f58709; /* Green background when checked */ 70 | border-color: #f58709; /* Green border when checked */ 71 | } 72 | 73 | ul > li input[type="checkbox"]:checked::after { 74 | content: "✔"; /* Checkmark */ 75 | color: #fff; /* White checkmark color */ 76 | font-size: 14px; 77 | position: absolute; 78 | top: 50%; 79 | left: 50%; 80 | transform: translate(-50%, -50%); /* Center the checkmark */ 81 | } 82 | 83 | ul > li input[type="checkbox"]:hover { 84 | background-color: #3a3a3a; /* Slightly lighter background on hover */ 85 | border-color: #555; /* Slightly different border on hover */ 86 | } 87 | 88 | /* Text Styles inside List Items */ 89 | ul > li span { 90 | flex-grow: 1; /* Take up remaining space */ 91 | margin-left: 10px; /* Space between checkbox and text */ 92 | } 93 | 94 | /* Form Styles */ 95 | form { 96 | display: flex; /* Use flexbox for alignment */ 97 | align-items: center; /* Center items vertically */ 98 | margin-bottom: 14px; /* Space below the form */ 99 | margin-top: 10px; 100 | width: 100%; /* Make the form take the full width of the container */ 101 | padding: 0 10px; /* Add padding to left and right */ 102 | box-sizing: border-box; /* Include padding in width calculation */ 103 | } 104 | 105 | /* Input Styles */ 106 | form input[type="text"] { 107 | background-color: #2a2a2a; /* Dark background */ 108 | color: #e0e0e0; /* Light text */ 109 | border: 1px solid #444; /* Border color */ 110 | border-radius: 4px; /* Rounded corners */ 111 | padding: 8px; /* Padding inside the input */ 112 | margin-right: 10px; /* Space between input and button */ 113 | flex-grow: 1; /* Take up remaining space */ 114 | box-sizing: border-box; /* Include padding in width calculation */ 115 | } 116 | 117 | /* Button Styles */ 118 | form button { 119 | background-color: #f58709; /* Green background */ 120 | color: #fff; /* White text */ 121 | font-weight: bold; 122 | font-size: 0.8em; 123 | border: none; /* Remove default border */ 124 | border-radius: 4px; /* Rounded corners */ 125 | padding: 8px 12px; /* Padding inside the button */ 126 | cursor: pointer; /* Pointer cursor */ 127 | transition: background-color 0.3s; /* Smooth background change on hover */ 128 | white-space: nowrap; /* Prevent text wrap */ 129 | box-sizing: border-box; /* Include padding in width calculation */ 130 | } 131 | 132 | form button:hover { 133 | background-color: #f16c12; /* Darker green on hover */ 134 | } 135 | --------------------------------------------------------------------------------