Remove unused `previousValue`, `lastChange`, and `changed` properties from ChatInputComponent constructor that were causing state desynchronization. Refactor `resolveAutoComplete` method to return null on multiple matches instead of silently picking the last one, and add `expiryTimer` property for future timeout management. Clean up formatting inconsistencies across the component.
Add asyncio import and loop property to BaseMapper, introduce run_in_executor helper method, and convert all blocking database operations (find_one, exists, count, upsert, find) to async wrappers that offload work to the default executor thread pool
Implement embed_url function that fetches remote pages, extracts Open Graph and Twitter Card metadata (title, description, image, video, site name), and renders embedded preview cards for links in chat messages. Add LRU-cached HTTP fetching via requests, parse head meta tags with BeautifulSoup, and append embed HTML after anchor elements. Include responsive CSS for embed containers with max-height 400px media, rounded top corners, and styled text elements for site name, page title, description, and link.
- Changed body layout from flexbox to CSS grid with explicit grid-template-areas for header, sidebar, and chat-area
- Added `height: 100%` to html element and changed body height from `100vh` to `100%` to prevent mobile browser chrome issues
- Updated viewport meta tag with `interactive-widget=resizes-content` to handle virtual keyboard resizing on mobile
- Moved main element after sidebar in DOM order and assigned grid-area to main and header
- Added `.chat-messages` flex container and fixed indentation inconsistencies across CSS selectors
- Changed umami analytics script from `defer` to `async defer` for non-blocking loading
The fix addresses a race condition where pressing Enter to send a message while live typing was active would trigger both the submit handler and the live typing update, resulting in the same message being sent twice. The solution reorders the cleanup sequence in the submit handler to clear the input value before calling updateMessage, and conditionally assigns the messageUid only when live typing is enabled in the sendMessage callback.
Add `.message:has(+ .message.long-time)` selector to show time display when a message is followed by one with a date gap exceeding 20 minutes. Set `.time` opacity to 1 for both this case and the last message to override any inherited lower opacity. In the JavaScript, track `previousDate` alongside `previousUser` and add/remove `long-time` class based on a 20-minute threshold between consecutive messages' `created_at` timestamps.
The bug caused incorrect extraction of the numeric value from timestamp strings ending with 's' (e.g., "30s"). Previously, the code sliced `start_time[:-1]` (the list) instead of `t[:-1]` (the individual string element), resulting in the entire list being sliced rather than removing the trailing 's' character from each timestamp. This fix ensures proper parsing of YouTube embed start times by applying the slice operation to the correct variable.
- Replace avatar opacity-only hiding with max-height:0 and overflow:hidden for collapsed state
- Remove .time from the display:none rule shared with .author
- Add CSS rule to fade .time to opacity:0 when message row is not hovered, focused, or active
- Restore max-height:unset on .avatar when message is hovered to ensure smooth reveal
- Refactor embed_youtube to use urlparse and parse_qs for robust YouTube link detection
across multiple hostnames (youtu.be, youtube.com, youtube-nocookie.com) and path variants
- Add missing file existence check in ChannelAttachmentView to return 404 when attachment
file is not found on disk
- Improve image saving in attachment view with quality=100, optimize=True, save_all=True
- Set Content-Type header from original format in attachment download response
Add Pillow and pillow-heif dependencies to pyproject.toml, implement image format conversion and dimension resizing in ChannelAttachmentView.get() using query parameters 'format', 'width', and 'height', and update markdown rendering to support strikethrough, spoiler, and URL plugins. Also fix uvloop import to gracefully fall back on Windows, clean up unused imports in sssh.py, and change upload markdown syntax from image to link format in web template.
Revert commit 17c6124a57 which minified all Python source files, restoring original multi-line formatting, expanded variable names, and proper indentation in __main__.py, app.py, docs/app.py, dump.py, form/login.py, and form/register.py
Implement file upload via clipboard paste events in the web textarea input, reading non-text clipboard items as blobs and feeding them into the existing upload-button component. Also add drag-and-drop event listeners to handle dropped files, enabling direct file uploads without manual file selection.
Create a new polyfill script at src/snek/static/polyfills/Promise.withResolvers.js that provides a fallback implementation of Promise.withResolvers for environments lacking native support. Include the polyfill as a module script in both app.html and base.html templates, ensuring it is loaded before app.js to guarantee availability at runtime.
Convert all JavaScript classes in app.js and schedule.js to ES module exports, add import statements in inline scripts, and update all script tags across templates to use type="module" attribute. This enables proper module scoping and dependency management for the frontend codebase.
Create new shared.css with consistent input/textarea focus outline and placeholder transition effects. Import shared.css into both base.css and style.css to apply the unified input styling across all pages, replacing previously scattered per-page implementations.
Add `preloaded-structure` attribute to `<generic-form>` elements in both `login.html` and `register.html`, passing the serialized form JSON from the view. In `generic-form.js`, normalize CSS indentation from 10-space to 2-space tabs. This enables server-side form definition to be rendered immediately on page load without an initial JSON fetch, and the autofocus behavior targets the first input element in the preloaded structure.
- Create back-form.css with grid layout for back button and form overlay
- Add border-radius: 20px to images, videos, iframes, and divs in message-content
- Add focus outline and placeholder transition to GenericField inputs
- Dispatch change event on Enter key in GenericField
- Add meta tags, title blocks, and head blocks to base.html, login.html, and register.html
- Wrap login/register forms in back-form div for consistent layout