231 lines
5.9 KiB
HTML
231 lines
5.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Pro Sticky Board (Safe Mode)</title>
|
|
<style>
|
|
body {
|
|
background-color: #f0f0f0;
|
|
font-family: sans-serif;
|
|
padding: 20px;
|
|
}
|
|
|
|
#controls {
|
|
margin-bottom: 30px;
|
|
display: flex;
|
|
gap: 10px;
|
|
background: white;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
align-items: center;
|
|
}
|
|
|
|
button {
|
|
padding: 10px 15px;
|
|
cursor: pointer;
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
transition: 0.2s;
|
|
}
|
|
|
|
.add-btn {
|
|
background-color: #4caf50;
|
|
color: white;
|
|
}
|
|
.export-btn {
|
|
background-color: #2196f3;
|
|
color: white;
|
|
}
|
|
.import-btn {
|
|
background-color: #9c27b0;
|
|
color: white;
|
|
}
|
|
|
|
/* The Safety Toggle Button */
|
|
.lock-btn {
|
|
background-color: #ff9800;
|
|
color: white;
|
|
margin-left: auto; /* Push to the right */
|
|
}
|
|
.lock-btn.active {
|
|
background-color: #f44336;
|
|
}
|
|
|
|
.board {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 20px;
|
|
}
|
|
|
|
.sticky-note {
|
|
width: 220px;
|
|
height: 220px;
|
|
padding: 15px;
|
|
background-color: #fff740;
|
|
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: relative;
|
|
}
|
|
|
|
.sticky-note textarea {
|
|
background: transparent;
|
|
border: none;
|
|
resize: none;
|
|
flex-grow: 1;
|
|
font-size: 16px;
|
|
outline: none;
|
|
}
|
|
|
|
/* Hidden by default */
|
|
.delete-btn {
|
|
position: absolute;
|
|
top: 5px;
|
|
right: 8px;
|
|
cursor: pointer;
|
|
color: #d32f2f;
|
|
font-size: 22px;
|
|
display: none;
|
|
background: rgba(255, 255, 255, 0.8);
|
|
border-radius: 50%;
|
|
width: 25px;
|
|
height: 25px;
|
|
text-align: center;
|
|
line-height: 22px;
|
|
}
|
|
|
|
/* Only show when the board has the 'edit-mode' class */
|
|
.board.edit-mode .delete-btn {
|
|
display: block;
|
|
}
|
|
|
|
#fileInput {
|
|
display: none;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="controls">
|
|
<button class="add-btn" onclick="addNote()">+ New Note</button>
|
|
<button class="export-btn" onclick="exportNotes()">Dump JSON</button>
|
|
<button
|
|
class="import-btn"
|
|
onclick="document.getElementById('fileInput').click()"
|
|
>
|
|
Load JSON
|
|
</button>
|
|
<input
|
|
type="file"
|
|
id="fileInput"
|
|
accept=".json"
|
|
onchange="importNotes(event)"
|
|
/>
|
|
|
|
<button id="lockBtn" class="lock-btn" onclick="toggleEditMode()">
|
|
🔓 Enable Deletion
|
|
</button>
|
|
</div>
|
|
|
|
<div class="board" id="board"></div>
|
|
|
|
<script>
|
|
const board = document.getElementById("board");
|
|
const lockBtn = document.getElementById("lockBtn");
|
|
let isEditMode = false;
|
|
|
|
document.addEventListener("DOMContentLoaded", loadFromStorage);
|
|
|
|
function toggleEditMode() {
|
|
isEditMode = !isEditMode;
|
|
board.classList.toggle("edit-mode", isEditMode);
|
|
|
|
if (isEditMode) {
|
|
lockBtn.innerHTML = "🔒 Lock Deletion";
|
|
lockBtn.classList.add("active");
|
|
} else {
|
|
lockBtn.innerHTML = "🔓 Enable Deletion";
|
|
lockBtn.classList.remove("active");
|
|
}
|
|
}
|
|
|
|
function createNoteElement(content) {
|
|
const element = document.createElement("div");
|
|
element.classList.add("sticky-note");
|
|
|
|
const textarea = document.createElement("textarea");
|
|
textarea.value = content;
|
|
textarea.placeholder = "Type here...";
|
|
|
|
const deleteBtn = document.createElement("span");
|
|
deleteBtn.classList.add("delete-btn");
|
|
deleteBtn.innerHTML = "×";
|
|
deleteBtn.onclick = () => {
|
|
if (confirm("Delete this note?")) {
|
|
element.remove();
|
|
saveToStorage();
|
|
}
|
|
};
|
|
|
|
textarea.addEventListener("input", saveToStorage);
|
|
|
|
element.appendChild(deleteBtn);
|
|
element.appendChild(textarea);
|
|
return element;
|
|
}
|
|
|
|
function addNote(text = "") {
|
|
board.appendChild(createNoteElement(text));
|
|
saveToStorage();
|
|
}
|
|
|
|
function saveToStorage() {
|
|
const notes = Array.from(
|
|
document.querySelectorAll(".sticky-note textarea")
|
|
).map((n) => n.value);
|
|
localStorage.setItem("sticky-notes", JSON.stringify(notes));
|
|
}
|
|
|
|
function loadFromStorage() {
|
|
const notes = JSON.parse(localStorage.getItem("sticky-notes") || "[]");
|
|
notes.forEach((text) => board.appendChild(createNoteElement(text)));
|
|
}
|
|
|
|
function exportNotes() {
|
|
const notes = Array.from(
|
|
document.querySelectorAll(".sticky-note textarea")
|
|
).map((n) => n.value);
|
|
const blob = new Blob([JSON.stringify(notes, null, 2)], {
|
|
type: "application/json",
|
|
});
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = `my-notes-${new Date().toISOString().slice(0, 10)}.json`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
function importNotes(event) {
|
|
const file = event.target.files[0];
|
|
if (!file) return;
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
try {
|
|
const notes = JSON.parse(e.target.result);
|
|
if (confirm("Replace current board?")) {
|
|
board.innerHTML = "";
|
|
notes.forEach((text) => addNote(text));
|
|
}
|
|
} catch (err) {
|
|
alert("Invalid JSON file.");
|
|
}
|
|
};
|
|
reader.readAsText(file);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|