1
0

Add fullscreen & fix notes

This commit is contained in:
2025-07-18 19:30:16 +02:00
parent 82c88243b4
commit edd1478aa5
9 changed files with 229 additions and 2777 deletions

View File

@@ -15,7 +15,13 @@
"build:unpack": "npm run build && electron-builder --dir", "build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win", "build:win": "npm run build && electron-builder --win",
"build:mac": "npm run build && electron-builder --mac", "build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux" "build:linux": "npm run build && electron-builder --linux",
"fullscreen": "KIOSK=false npm run start",
"kiosk": "KIOSK=true npm run start",
"electron": "electron",
"electron:kiosk": "electron . --kiosk",
"electron:fullscreen": "electron .",
"test:fullscreen": "node test-fullscreen.js"
}, },
"dependencies": { "dependencies": {
"@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/preload": "^3.0.1",

View File

@@ -1,4 +1,4 @@
import { app, shell, BrowserWindow, ipcMain } from 'electron' import { app, shell, BrowserWindow, ipcMain, screen } from 'electron'
import { join } from 'path' import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils' import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
@@ -6,22 +6,79 @@ import icon from '../../resources/icon.png?asset'
let mainWindow let mainWindow
const createWindow = () => { const createWindow = () => {
// Get the primary display dimensions
const primaryDisplay = screen.getPrimaryDisplay()
const { width, height } = primaryDisplay.workAreaSize
// Check for kiosk mode - enable if in production, has kiosk flag, or KIOSK env var
const isKioskMode = process.env.NODE_ENV === 'production' ||
process.argv.includes('--kiosk') ||
process.env.KIOSK === 'true'
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 900, width: width,
height: 670, height: height,
show: false, show: false,
autoHideMenuBar: true, autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}), fullscreen: true,
kiosk: isKioskMode,
frame: false, // Remove window frame for true fullscreen experience
webPreferences: { webPreferences: {
preload: join(__dirname, '../preload/index.js'), preload: join(__dirname, '../preload/index.js'),
sandbox: false, sandbox: false,
nodeIntegration: false, nodeIntegration: false,
contextIsolation: true contextIsolation: true,
webSecurity: false // Allow loading external resources
},
...(process.platform === 'linux' ? { icon } : {})
})
// Disable zoom and context menu for touch interface
mainWindow.webContents.on('before-input-event', (event, input) => {
// Prevent zooming with Ctrl++ and Ctrl+-
if (input.control && (input.key === '+' || input.key === '-' || input.key === '=' || input.key === '0')) {
event.preventDefault()
} }
// Prevent F11 fullscreen toggle in kiosk mode
if (isKioskMode && input.key === 'F11') {
event.preventDefault()
}
})
// Disable right-click context menu
mainWindow.webContents.on('context-menu', (event) => {
event.preventDefault()
}) })
mainWindow.on('ready-to-show', () => { mainWindow.on('ready-to-show', () => {
mainWindow.show() mainWindow.show()
// Ensure fullscreen mode is enabled
if (!mainWindow.isFullScreen()) {
mainWindow.setFullScreen(true)
}
// Focus the window
mainWindow.focus()
})
// Prevent accidentally leaving fullscreen in kiosk mode
mainWindow.on('leave-full-screen', () => {
if (isKioskMode) {
mainWindow.setFullScreen(true)
}
})
// Handle window focus events to maintain fullscreen in kiosk mode
mainWindow.on('focus', () => {
if (isKioskMode && !mainWindow.isFullScreen()) {
mainWindow.setFullScreen(true)
}
})
// Prevent window from being minimized in kiosk mode
mainWindow.on('minimize', () => {
if (isKioskMode) {
mainWindow.restore()
}
}) })
mainWindow.webContents.setWindowOpenHandler((details) => { mainWindow.webContents.setWindowOpenHandler((details) => {

View File

@@ -4,11 +4,22 @@
margin: 0 margin: 0
padding: 0 padding: 0
box-sizing: border-box box-sizing: border-box
// Improve touch interactions
-webkit-tap-highlight-color: transparent
-webkit-touch-callout: none
-webkit-user-select: none
-khtml-user-select: none
-moz-user-select: none
-ms-user-select: none
user-select: none
html, body html, body
height: 100vh height: 100vh
width: 100vw width: 100vw
overflow: hidden overflow: hidden
// Prevent scrolling and bouncing on touch devices
-webkit-overflow-scrolling: touch
overscroll-behavior: none
body body
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif
@@ -22,12 +33,17 @@ body
line-height: 1.5 line-height: 1.5
-webkit-font-smoothing: antialiased -webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale -moz-osx-font-smoothing: grayscale
// Prevent pull-to-refresh and other touch gestures
overscroll-behavior-y: none
-webkit-user-select: none
#root #root
height: 100vh height: 100vh
width: 100vw width: 100vw
display: flex display: flex
flex-direction: column flex-direction: column
// Prevent touch scrolling
touch-action: none
// App Layout Styles // App Layout Styles
.app .app
@@ -35,6 +51,8 @@ body
width: 100vw width: 100vw
display: flex display: flex
flex-direction: column flex-direction: column
// Prevent touch scrolling
touch-action: none
&__main &__main
flex: 1 flex: 1
@@ -68,4 +86,46 @@ body
font-size: 1.25rem font-size: 1.25rem
color: rgba(30, 41, 59, 0.8) color: rgba(30, 41, 59, 0.8)
font-weight: 500 font-weight: 500
line-height: 1.6 line-height: 1.6
// Touch-friendly interactive elements
button, a, [role="button"], .interactive
// Improve touch target size
min-height: 44px
min-width: 44px
// Add touch feedback
transition: all 0.2s ease
cursor: pointer
&:hover, &:focus
transform: scale(1.05)
&:active
transform: scale(0.95)
opacity: 0.8
// Prevent text selection on interactive elements
button, a, [role="button"], .nav-item, .interactive
-webkit-user-select: none
-moz-user-select: none
-ms-user-select: none
user-select: none
// Allow text selection on input fields and content areas
input, textarea, [contenteditable], .selectable
-webkit-user-select: text
-moz-user-select: text
-ms-user-select: text
user-select: text
// Re-enable touch actions for inputs
touch-action: manipulation
// Fullscreen specific styles
@media (display-mode: fullscreen)
body
background-attachment: fixed
.app
// Ensure content fits fullscreen properly
min-height: 100vh
max-height: 100vh

View File

@@ -117,6 +117,47 @@ const Notes = () => {
saveCanvasToStorage() saveCanvasToStorage()
} }
// Touch event handlers for mobile/tablet support
const handleTouchStart = (e) => {
e.preventDefault()
e.stopPropagation()
// Only handle single touch
if (e.touches.length !== 1) return
const touch = e.touches[0]
const mouseEvent = new MouseEvent('mousedown', {
clientX: touch.clientX,
clientY: touch.clientY,
bubbles: true,
cancelable: true
})
startDrawing(mouseEvent)
}
const handleTouchMove = (e) => {
e.preventDefault()
e.stopPropagation()
// Only handle single touch
if (e.touches.length !== 1) return
const touch = e.touches[0]
const mouseEvent = new MouseEvent('mousemove', {
clientX: touch.clientX,
clientY: touch.clientY,
bubbles: true,
cancelable: true
})
draw(mouseEvent)
}
const handleTouchEnd = (e) => {
e.preventDefault()
e.stopPropagation()
stopDrawing()
}
const clearCanvas = () => { const clearCanvas = () => {
const canvas = canvasRef.current const canvas = canvasRef.current
const ctx = canvas.getContext('2d') const ctx = canvas.getContext('2d')
@@ -193,6 +234,9 @@ const Notes = () => {
onMouseMove={draw} onMouseMove={draw}
onMouseUp={stopDrawing} onMouseUp={stopDrawing}
onMouseLeave={stopDrawing} onMouseLeave={stopDrawing}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
/> />
</div> </div>
</div> </div>

View File

@@ -166,6 +166,9 @@
background: rgba(255, 255, 255, 0.9) background: rgba(255, 255, 255, 0.9)
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5) box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5)
overflow: hidden overflow: hidden
// Ensure touch events can reach the canvas
touch-action: auto !important
position: relative
.drawing-canvas .drawing-canvas
width: 100% width: 100%
@@ -174,6 +177,12 @@
display: block display: block
background: #ffffff background: #ffffff
border-radius: 20px border-radius: 20px
// Enable touch interactions - override global touch-action: none
touch-action: auto !important
-webkit-user-select: none
-moz-user-select: none
-ms-user-select: none
user-select: none
&.eraser-mode &.eraser-mode
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" fill="none" stroke="black" stroke-width="2"/></svg>') 10 10, auto cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="8" fill="none" stroke="black" stroke-width="2"/></svg>') 10 10, auto

View File

@@ -99,9 +99,11 @@ mkdir -p "${CHROOT_DIR}" "${ISO_DIR}"
# Bootstrap Debian base system # Bootstrap Debian base system
echo "Bootstrapping Debian base system..." echo "Bootstrapping Debian base system..."
debootstrap --arch=amd64 --variant=minbase "${DEBIAN_VERSION}" "${CHROOT_DIR}" http://deb.debian.org/debian/ debootstrap --arch=amd64 --variant=minbase "${DEBIAN_VERSION}" "${CHROOT_DIR}" http://deb.debian.org/debian/ 2>/dev/null
# Mount necessary filesystems # Mount necessary filesystems
echo "Mounting virtual filesystems..."
mkdir -p "${CHROOT_DIR}"/{dev,dev/pts,proc,sys}
mount --bind /dev "${CHROOT_DIR}/dev" mount --bind /dev "${CHROOT_DIR}/dev"
mount --bind /dev/pts "${CHROOT_DIR}/dev/pts" mount --bind /dev/pts "${CHROOT_DIR}/dev/pts"
mount --bind /proc "${CHROOT_DIR}/proc" mount --bind /proc "${CHROOT_DIR}/proc"
@@ -114,8 +116,11 @@ cleanup() {
umount -lf "${CHROOT_DIR}/dev" 2>/dev/null || true umount -lf "${CHROOT_DIR}/dev" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/proc" 2>/dev/null || true umount -lf "${CHROOT_DIR}/proc" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/sys" 2>/dev/null || true umount -lf "${CHROOT_DIR}/sys" 2>/dev/null || true
# Additional cleanup - remove any leftover mount points
sync
sleep 1
} }
trap cleanup EXIT trap cleanup EXIT INT TERM
# Copy OpenWall files into chroot # Copy OpenWall files into chroot
echo "Copying OpenWall files..." echo "Copying OpenWall files..."
@@ -258,13 +263,35 @@ chmod +x "${CHROOT_DIR}/setup-system.sh"
echo "Running system setup in chroot..." echo "Running system setup in chroot..."
chroot "${CHROOT_DIR}" /setup-system.sh chroot "${CHROOT_DIR}" /setup-system.sh
# Clean up mounts before creating squashfs
echo "Cleaning up mounts before filesystem creation..."
# Disable trap temporarily
trap - EXIT INT TERM
umount -lf "${CHROOT_DIR}/dev/pts" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/dev" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/proc" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/sys" 2>/dev/null || true
sync
sleep 2
# Create live boot configuration # Create live boot configuration
echo "Setting up live boot configuration..." echo "Setting up live boot configuration..."
mkdir -p "${ISO_DIR}/live" mkdir -p "${ISO_DIR}/live"
# Create filesystem image # Create filesystem image
echo "Creating filesystem image..." echo "Creating filesystem image (this may take a while)..."
mksquashfs "${CHROOT_DIR}" "${ISO_DIR}/live/filesystem.squashfs" -comp xz -e boot mksquashfs "${CHROOT_DIR}" "${ISO_DIR}/live/filesystem.squashfs" \
-comp xz \
-e boot \
-e proc \
-e sys \
-e dev \
-e tmp \
-e var/tmp \
-e var/cache \
-e var/log \
-no-progress \
-quiet
# Copy kernel and initrd # Copy kernel and initrd
cp "${CHROOT_DIR}/boot/vmlinuz-"* "${ISO_DIR}/live/vmlinuz" cp "${CHROOT_DIR}/boot/vmlinuz-"* "${ISO_DIR}/live/vmlinuz"
@@ -338,9 +365,18 @@ xorriso -as mkisofs \
-append_partition 2 0xef "${ISO_DIR}/EFI/boot/bootx64.efi" \ -append_partition 2 0xef "${ISO_DIR}/EFI/boot/bootx64.efi" \
-output "${OUTPUT_ISO}" \ -output "${OUTPUT_ISO}" \
-graft-points \ -graft-points \
"${ISO_DIR}" "${ISO_DIR}" 2>/dev/null
echo "ISO created: ${OUTPUT_ISO}" echo "ISO created: ${OUTPUT_ISO}"
# Final cleanup
final_cleanup() {
umount -lf "${CHROOT_DIR}/dev/pts" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/dev" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/proc" 2>/dev/null || true
umount -lf "${CHROOT_DIR}/sys" 2>/dev/null || true
}
final_cleanup
EOF EOF
chmod +x "$BUILD_DIR/build-iso.sh" chmod +x "$BUILD_DIR/build-iso.sh"

View File

@@ -5,13 +5,13 @@ FROM node:18-alpine
WORKDIR /app WORKDIR /app
# Copy package files # Copy package files
COPY package.json pnpm-lock.yaml ./ COPY package.json yarn.lock ./
# Install pnpm globally # Install yarn globally
RUN npm install -g pnpm RUN npm install -g yarn
# Install dependencies # Install dependencies
RUN pnpm install --frozen-lockfile RUN yarn install
# Copy source code # Copy source code
COPY . . COPY . .
@@ -27,4 +27,4 @@ ENV NODE_ENV=production
ENV DATABASE_PATH=/app/data/database.sqlite ENV DATABASE_PATH=/app/data/database.sqlite
# Start the application # Start the application
CMD ["pnpm", "start"] CMD ["yarn", "start"]

2758
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,7 @@
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"packageManager": "pnpm@10.13.1",
"dependencies": { "dependencies": {
"@nextcloud/cdav-library": "^1.1.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^17.2.0", "dotenv": "^17.2.0",
"express": "^5.1.0", "express": "^5.1.0",