453 lines
No EOL
16 KiB
HTML
453 lines
No EOL
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>noted.</title>
|
|
<link rel="icon" href="https://radical.omar-c29.workers.dev/memes/fry.png" type="image/png">
|
|
<link rel="manifest" href="manifest.json">
|
|
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
font-family: 'Roboto Mono', monospace;
|
|
}
|
|
.notepad {
|
|
flex: 1;
|
|
width: 100%;
|
|
font-size:36px;
|
|
padding: 20px;
|
|
box-sizing: border-box;
|
|
border: none;
|
|
outline: none;
|
|
resize: none;
|
|
line-height: 1.5;
|
|
font-family: 'Roboto Mono', monospace;
|
|
color: #000000;
|
|
}
|
|
.canvas-container {
|
|
flex: 1;
|
|
width: 100%;
|
|
display: none;
|
|
position: relative;
|
|
background-color: white;
|
|
}
|
|
#drawing-canvas {
|
|
width: 100%;
|
|
height: 100%;
|
|
cursor: url("https://radical.omar-c29.workers.dev/memes/maccas32.jpg") 12 12, pointer;
|
|
}
|
|
.drawing-controls {
|
|
background-color: #f1f1f1;
|
|
padding: 10px;
|
|
display: none;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
border-top: 1px solid #ddd;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
.controls {
|
|
background-color: #f1f1f1;
|
|
padding: 10px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
border-top: 1px solid #ddd;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
.font-size-control, .font-family-control, .color-control, .pen-control {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
.save-controls {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
button {
|
|
padding: 8px 12px;
|
|
cursor: pointer;
|
|
background-color: #FFD700; /* Halo Yellow */
|
|
color: #000;
|
|
border: none;
|
|
border-radius: 4px;
|
|
position: relative;
|
|
overflow: hidden;
|
|
z-index: 1;
|
|
}
|
|
.active-mode {
|
|
background-color: #FFA500; /* Orange for active mode */
|
|
box-shadow: 0 0 5px rgba(0,0,0,0.3);
|
|
}
|
|
button::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: -20%;
|
|
left: -20%;
|
|
width: 140%;
|
|
height: 140%;
|
|
background: radial-gradient(circle, rgba(255,255,255,0.8) 0%, rgba(255,255,255,0) 70%);
|
|
z-index: -1;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
button:hover::after {
|
|
opacity: 1;
|
|
animation: pulse 1.5s infinite;
|
|
}
|
|
@keyframes pulse {
|
|
0% {
|
|
transform: scale(0.8);
|
|
opacity: 0;
|
|
}
|
|
50% {
|
|
opacity: 0.8;
|
|
}
|
|
100% {
|
|
transform: scale(1.2);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
select, input[type="color"] {
|
|
padding: 8px;
|
|
border-radius: 4px;
|
|
border: 1px solid #ddd;
|
|
}
|
|
input[type="color"] {
|
|
height: 34px;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<textarea class="notepad" id="notepad" placeholder="Start typing here..."></textarea>
|
|
|
|
<div class="canvas-container" id="canvas-container">
|
|
<canvas id="drawing-canvas"></canvas>
|
|
</div>
|
|
|
|
<div class="drawing-controls" id="drawing-controls">
|
|
<div class="pen-control">
|
|
<label for="pen-size">Pen Size:</label>
|
|
<input type="range" id="pen-size" min="1" max="20" value="3">
|
|
<span id="pen-size-value">3px</span>
|
|
</div>
|
|
|
|
<div class="color-control">
|
|
<label for="pen-color">Pen Color:</label>
|
|
<input type="color" id="pen-color" value="#000000">
|
|
</div>
|
|
|
|
<div class="save-controls">
|
|
<button id="clear-canvas-btn">Clear Canvas</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<div class="font-family-control">
|
|
<label for="font-family">Font:</label>
|
|
<select id="font-family">
|
|
<option value="'Roboto Mono', monospace">Roboto Mono</option>
|
|
<option value="'Roboto', sans-serif">Roboto</option>
|
|
<option value="'Open Sans', sans-serif">Open Sans</option>
|
|
<option value="'Courier Prime', monospace">Courier Prime</option>
|
|
<option value="Arial, sans-serif">Arial</option>
|
|
<option value="'Times New Roman', serif">Times New Roman</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="font-size-control">
|
|
<label for="font-size">Size:</label>
|
|
<button id="decrease-font">A-</button>
|
|
<span id="current-size">36px</span>
|
|
<button id="increase-font">A+</button>
|
|
</div>
|
|
|
|
<div class="color-control">
|
|
<label for="text-color">Color:</label>
|
|
<input type="color" id="text-color" value="#000000">
|
|
</div>
|
|
|
|
<div class="save-controls">
|
|
<button id="draw-btn">Draw</button>
|
|
<button id="save-btn">Save</button>
|
|
<button id="clear-btn">Clear</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Get elements
|
|
const notepad = document.getElementById('notepad');
|
|
const canvasContainer = document.getElementById('canvas-container');
|
|
const drawingCanvas = document.getElementById('drawing-canvas');
|
|
const drawingControls = document.getElementById('drawing-controls');
|
|
const saveBtn = document.getElementById('save-btn');
|
|
const clearBtn = document.getElementById('clear-btn');
|
|
const drawBtn = document.getElementById('draw-btn');
|
|
const clearCanvasBtn = document.getElementById('clear-canvas-btn');
|
|
const penSize = document.getElementById('pen-size');
|
|
const penSizeValue = document.getElementById('pen-size-value');
|
|
const penColor = document.getElementById('pen-color');
|
|
const decreaseFont = document.getElementById('decrease-font');
|
|
const increaseFont = document.getElementById('increase-font');
|
|
const currentSize = document.getElementById('current-size');
|
|
const fontFamily = document.getElementById('font-family');
|
|
const textColor = document.getElementById('text-color');
|
|
|
|
// Load saved note from localStorage if available
|
|
window.addEventListener('load', () => {
|
|
const savedNote = localStorage.getItem('browserNotepadContent');
|
|
if (savedNote) {
|
|
notepad.value = savedNote;
|
|
}
|
|
|
|
const savedFontSize = localStorage.getItem('browserNotepadFontSize');
|
|
if (savedFontSize) {
|
|
notepad.style.fontSize = savedFontSize;
|
|
currentSize.textContent = savedFontSize;
|
|
}
|
|
|
|
const savedFontFamily = localStorage.getItem('browserNotepadFontFamily');
|
|
if (savedFontFamily) {
|
|
notepad.style.fontFamily = savedFontFamily;
|
|
fontFamily.value = savedFontFamily;
|
|
}
|
|
|
|
const savedTextColor = localStorage.getItem('browserNotepadTextColor');
|
|
if (savedTextColor) {
|
|
notepad.style.color = savedTextColor;
|
|
textColor.value = savedTextColor;
|
|
}
|
|
|
|
// Set focus to the notepad
|
|
notepad.focus();
|
|
});
|
|
|
|
// Auto-save content every 5 seconds
|
|
setInterval(() => {
|
|
localStorage.setItem('browserNotepadContent', notepad.value);
|
|
}, 5000);
|
|
|
|
// Save button click handler
|
|
saveBtn.addEventListener('click', () => {
|
|
localStorage.setItem('browserNotepadContent', notepad.value);
|
|
alert('Note saved!');
|
|
});
|
|
|
|
// Clear button click handler
|
|
clearBtn.addEventListener('click', () => {
|
|
if (confirm('Are you sure you want to clear the notepad?')) {
|
|
notepad.value = '';
|
|
localStorage.setItem('browserNotepadContent', '');
|
|
}
|
|
});
|
|
|
|
// Font size controls
|
|
decreaseFont.addEventListener('click', () => {
|
|
const currentFontSize = parseInt(window.getComputedStyle(notepad).fontSize);
|
|
if (currentFontSize > 12) {
|
|
const newSize = currentFontSize - 2 + 'px';
|
|
notepad.style.fontSize = newSize;
|
|
currentSize.textContent = newSize;
|
|
localStorage.setItem('browserNotepadFontSize', newSize);
|
|
}
|
|
});
|
|
|
|
increaseFont.addEventListener('click', () => {
|
|
const currentFontSize = parseInt(window.getComputedStyle(notepad).fontSize);
|
|
const newSize = currentFontSize + 2 + 'px';
|
|
notepad.style.fontSize = newSize;
|
|
currentSize.textContent = newSize;
|
|
localStorage.setItem('browserNotepadFontSize', newSize);
|
|
});
|
|
|
|
// Font family control
|
|
fontFamily.addEventListener('change', () => {
|
|
notepad.style.fontFamily = fontFamily.value;
|
|
localStorage.setItem('browserNotepadFontFamily', fontFamily.value);
|
|
});
|
|
|
|
// Text color control
|
|
textColor.addEventListener('input', () => {
|
|
notepad.style.color = textColor.value;
|
|
localStorage.setItem('browserNotepadTextColor', textColor.value);
|
|
});
|
|
|
|
// Ensure text area is focused when clicking on it
|
|
notepad.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
});
|
|
|
|
// Canvas drawing functionality
|
|
let isDrawing = false;
|
|
let ctx;
|
|
|
|
// Initialize canvas
|
|
function initCanvas() {
|
|
// Set canvas dimensions to match container
|
|
function setCanvasDimensions() {
|
|
drawingCanvas.width = canvasContainer.clientWidth;
|
|
drawingCanvas.height = canvasContainer.clientHeight;
|
|
}
|
|
|
|
// Call once and also on resize
|
|
setCanvasDimensions();
|
|
window.addEventListener('resize', setCanvasDimensions);
|
|
|
|
// Get context
|
|
ctx = drawingCanvas.getContext('2d');
|
|
|
|
// Initialize saved drawing if available
|
|
const savedDrawing = localStorage.getItem('browserNotepadDrawing');
|
|
if (savedDrawing) {
|
|
const img = new Image();
|
|
img.onload = function() {
|
|
ctx.drawImage(img, 0, 0);
|
|
};
|
|
img.src = savedDrawing;
|
|
}
|
|
}
|
|
|
|
// Drawing event listeners
|
|
function setupDrawingEvents() {
|
|
// Start drawing
|
|
drawingCanvas.addEventListener('mousedown', (e) => {
|
|
isDrawing = true;
|
|
ctx.beginPath(); // Start a new path when we start drawing
|
|
draw(e);
|
|
});
|
|
|
|
drawingCanvas.addEventListener('touchstart', (e) => {
|
|
isDrawing = true;
|
|
const touch = e.touches[0];
|
|
const mouseEvent = new MouseEvent('mousedown', {
|
|
clientX: touch.clientX,
|
|
clientY: touch.clientY
|
|
});
|
|
drawingCanvas.dispatchEvent(mouseEvent);
|
|
e.preventDefault();
|
|
});
|
|
|
|
// Draw
|
|
drawingCanvas.addEventListener('mousemove', (e) => {
|
|
if (isDrawing) draw(e);
|
|
});
|
|
|
|
drawingCanvas.addEventListener('touchmove', (e) => {
|
|
if (isDrawing) {
|
|
const touch = e.touches[0];
|
|
const mouseEvent = new MouseEvent('mousemove', {
|
|
clientX: touch.clientX,
|
|
clientY: touch.clientY
|
|
});
|
|
drawingCanvas.dispatchEvent(mouseEvent);
|
|
}
|
|
e.preventDefault();
|
|
});
|
|
|
|
// Stop drawing
|
|
window.addEventListener('mouseup', () => {
|
|
if (isDrawing) {
|
|
isDrawing = false;
|
|
ctx.beginPath(); // End the current path
|
|
saveDrawing();
|
|
}
|
|
});
|
|
|
|
window.addEventListener('touchend', () => {
|
|
if (isDrawing) {
|
|
isDrawing = false;
|
|
ctx.beginPath(); // End the current path
|
|
saveDrawing();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Drawing function
|
|
function draw(e) {
|
|
const rect = drawingCanvas.getBoundingClientRect();
|
|
const x = e.clientX - rect.left;
|
|
const y = e.clientY - rect.top;
|
|
|
|
ctx.lineWidth = penSize.value;
|
|
ctx.lineCap = 'round';
|
|
ctx.strokeStyle = penColor.value;
|
|
|
|
if (isDrawing) {
|
|
// Only start a new path when we start drawing
|
|
if (e.type === 'mousedown' || e.type === 'touchstart') {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y);
|
|
} else {
|
|
ctx.lineTo(x, y);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save drawing to localStorage
|
|
function saveDrawing() {
|
|
const dataURL = drawingCanvas.toDataURL();
|
|
localStorage.setItem('browserNotepadDrawing', dataURL);
|
|
}
|
|
|
|
// Toggle between text and drawing modes
|
|
drawBtn.addEventListener('click', () => {
|
|
if (notepad.style.display === 'none') {
|
|
// Switch to text mode
|
|
canvasContainer.style.display = 'none';
|
|
drawingControls.style.display = 'none';
|
|
notepad.style.display = 'block';
|
|
drawBtn.classList.remove('active-mode');
|
|
} else {
|
|
// Switch to drawing mode
|
|
notepad.style.display = 'none';
|
|
canvasContainer.style.display = 'block';
|
|
drawingControls.style.display = 'flex';
|
|
drawBtn.classList.add('active-mode');
|
|
|
|
// Initialize canvas if not already done
|
|
if (!ctx) {
|
|
initCanvas();
|
|
setupDrawingEvents();
|
|
}
|
|
}
|
|
});
|
|
|
|
// Pen size control
|
|
penSize.addEventListener('input', () => {
|
|
penSizeValue.textContent = `${penSize.value}px`;
|
|
});
|
|
|
|
// Clear canvas button
|
|
clearCanvasBtn.addEventListener('click', () => {
|
|
if (confirm('Are you sure you want to clear the canvas?')) {
|
|
ctx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height);
|
|
localStorage.removeItem('browserNotepadDrawing');
|
|
}
|
|
});
|
|
|
|
// Register service worker for PWA functionality
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => {
|
|
navigator.serviceWorker.register('service-worker.js')
|
|
.then(registration => {
|
|
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
|
})
|
|
.catch(err => {
|
|
console.log('ServiceWorker registration failed: ', err);
|
|
});
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |