Releases: amelandri/Mastofoto
Releases · amelandri/Mastofoto
Release list
0.5.5
Changed
- Revamped the login page: a bolder headline, a feature checklist highlighting what the app does, and the connect form now sits in its own visually distinct panel instead of blending into the surrounding text. On desktop the checklist and the connect form sit side by side; on mobile they stack as before.
- The instance-domain field is now marked up as a URL field (
type="url",inputmode="url", autocapitalize/autocorrect/spellcheck disabled, URL autocomplete), so mobile keyboards offer their standard URL-typing tools instead of a generic text keyboard.
0.5.4
Changed
- Replaced the "Load more" button with automatic lazy loading: older posts now load on their own as you scroll near the bottom, including automatically paging past any page that happened to contain no photos. Coordinated with pull-to-refresh so the two never race or interfere with each other.
- Posts with more than one photo now display them in a uniform grid (2 or 3 columns depending on the count) with every tile cropped to the same 4:3 aspect ratio, instead of stacking photos at their natural, mismatched heights. Single-photo posts are unchanged.
- The post header's "New" badge and timestamp are now positioned by anchoring each directly to a fixed point (the badge to the card's own corner, the timestamp to the header row) instead of a flex column that relied on a different hand-tuned offset per screen size. This also fixes the badge landing in a different spot on boosted posts than on plain ones — it's now always in the same corner of the card either way.
- On mobile, a list member's handle now shows below their display name instead of next to it, fixing a layout overflow when both were long enough to make the combined row too wide for the screen.
Fixed
- The "Home Page" link in Settings and Info now switches views instantly instead of reloading the whole page, removing the brief lag (and refetching the timeline from scratch) that a full reload caused.
- Corrected avatar display in Timeline members list so border radius is identical to the one used in post header
0.5.3
0.5.2
Added
- The Settings screen's timeline picker now offers "Home timeline" as an option alongside your Mastodon lists — no extra permission needed, since it's covered by the same
readscope already requested. Choosing it skips the list-members preview (there's no "membership" to show), and it's remembered per-instance for next time just like a list choice. - Custom emoji (
:shortcode:) now render as actual images instead of literal text — in post text and content-warning summaries, in author display names (post header, "boosted" banner, list-members preview). Handled with the same security-conscious pattern as every other external URL in the app: each emoji's image URL is validated before use, and an unrecognized or unsafe shortcode is just left as plain text. - On a post with multiple photos, the lightbox can now move between them: swipe left/right on touch, or use the arrow keys on a keyboard. Navigation clamps at the first/last photo rather than wrapping around.
Changed
- The post date now shows a 2-digit year (
31/08/26instead of31/08/2026). - On mobile, the post date now sits on the same row as the author's username (right-aligned), the same layout already used on desktop, instead of wrapping onto its own full-width line below. To guarantee the username never overlaps the date now that they share a row,
.usernamegets a fixed width on mobile with a fade-to-transparent effect on truncated text, instead of the usual ellipsis. The "New" badge keeps its own separate behavior: pinned to the card's top-right corner regardless of the header's content, same as before — only the date moved. - Various Improvements to icons and text positioning
Fixed
- Logging in failed with "crypto.randomUUID is not a function" when testing from a real phone over a plain
http://<lan-ip>:portaddress instead ofhttp://localhost—crypto.randomUUID()requires a secure context (HTTPS, orlocalhost), which a LAN IP over plain HTTP isn't. The OAuthstatevalue now falls back to building a UUID fromcrypto.getRandomValues()(which has no such restriction) whencrypto.randomUUIDisn't available.
0.5.1
Fixed
- A "Load failed" timeline error stayed on screen even after a subsequent load succeeded (e.g. pulling to refresh once the connection came back), because only
selectList()cleared it — pull-to-refresh callsloadTimeline()directly and skipped that step. The error is now cleared at the top ofloadTimeline()itself, so every caller is covered. - Reloading the page while already logged in briefly flashed the login screen before the photo feed appeared, because
login-viewwas the only view visible by default in the static HTML — it stayed on screen for the moment it tookstartSession()'s network round-trip to verify the stored session and switch views.login-viewnow starts hidden like the other three views, and the bootstrap explicitly shows it only when there's actually no session to resume.
Changed
- Improved informations about source code and selfhosting
0.5.0
Added
- Dark theme, switchable from a new "Theme" setting on the renamed Settings screen. Defaults to the OS/browser's
prefers-color-schemewhen no explicit choice has been saved; the pick persists inlocalStorageand applies instantly, including updating the mobile/PWAtheme-color. - The About/Info page is now reachable from the login screen too (previously only from the header once logged in), via a new link in the login page's short disclosure text.
- The header's info button is now always visible, including when logged out — previously it lived inside the same container as "Settings"/"Log out" and was hidden along with them until login.
- A visible close button on the photo lightbox, and full keyboard support: photos are focusable and open with Enter/Space (previously mouse/touch only), and closing the lightbox returns focus to the photo that opened it.
- A service worker (
sw.js) caches the static app shell (HTML/CSS/JS/manifest/icons) so the app still loads when offline or on a flaky connection — network-first with cache fallback, and scoped to same-origin requests only, so it never touches Mastodon API responses. - Photos now show a blurred placeholder (decoded from Mastodon's
blurhashdata, no library) while the full-resolution image loads, instead of empty space. - A test suite (
pure.test.mjs, run withnode --test/npm test) coveringpure.mjs's functions, including a regression test for thejavascript:URI issue fixed in 0.4.1.
Changed
- The mobile/PWA home-screen icon (
apple-touch-iconandmanifest.json's icon) now uses a newassets/app-icon.pnginstead of the plain transparentfavicon.png: same blue "M", composited over a subtle dark diagonal gradient (#232a32to#12151a, centered on the app's own dark-theme background) so it reads as a proper opaque icon once a phone's launcher places it over an arbitrary wallpaper, rather than looking inconsistent with a transparent background. The browser-tab favicon (favicon.ico/favicon.png) is unchanged. Contrast of the "M" against the gradient was checked with the same WCAG relative-luminance formula used elsewhere (≥4.2:1 at every point). - Updated the About/Info page and README to catch up with everything shipped since they were last written: the Features list now mentions the theme picker, PWA installability, pull-to-refresh, offline app-shell caching, and jumping to the original post; Security & data now discloses the service worker's scope (app files only, never Mastodon data) and, honestly, that some deployments (including the maintainer's own) may run basic anonymous analytics — the code in this repository carries none.
- Replaced the login page's long bulleted "Some info about Mastofoto" disclosure with a short sentence and a link to the Info page for the full detail.
- The header's "Settings", "Log out", and info buttons no longer look like buttons (no background/border) — restyled as colored text links with an underline on hover, using the same
--linkblue as other links. They're still real<button>elements under the hood (kept for native keyboard support), just visually plain-link. The link color's contrast was checked without the previous opacity dimming, since that alone was enough to drop it back under 4.5:1 in light mode. - Renamed "List Management" to "Settings", reorganizing the screen into a "List" section (unchanged content) and a new "Appearance" section (the theme picker).
- Every remaining color in
style.css(brand blue, button text, card shadows, the lightbox overlay) moved into the light/dark CSS variables, so none are hardcoded outside the two:rootpalette blocks. - Redesigned the "New" badge and timestamp on desktop: instead of sharing one line pushed to the right, they now stack in a right-aligned column, with the badge vertically lined up with the author's name and the date with their handle.
- On mobile, the "New" badge no longer sits inline with the wrapped date — it's now pinned to the top-right corner of the post card, while the date stays under the author info as before.
- Added explicit
aria-labels to the "List Management" and "Log out" header buttons, matching the existing info button, so screen readers announce them correctly once their text labels collapse to icon-only on mobile. isHttpUrl,hasPhoto, andparseNextMaxIdmoved out ofapp.jsinto a newpure.mjsmodule, withapp.jsnow loaded as<script type="module">importing them. A minimalpackage.json("type": "module", no dependencies) was added so Node resolves the sameimportfor testing.- Replaced every emoji icon (header Settings/Info/Log out, and the feed's Favourite/Reblog/View post buttons and "boosted" banner) with small inline flat SVG icons using
stroke="currentColor"/fill="currentColor", so they automatically pick up the surrounding text color — including the active/pressed state on the favourite and reblog buttons, and both themes — without needing separate light/dark image assets. Being inline markup rather than image files, they add effectively no extra page weight. Removed the now-unused.icon-btnCSS rules left over from the header buttons' earlier emoji-based styling.
Fixed
- Logging out while viewing the About/Info page left it visible behind the login form, since the logout handler never hid it — every view-switching handler now goes through a single
showView()helper that always hides all four views before showing one, so this whole class of "forgot to hide X" bug can't recur. - Renamed the login page's
.privacy-notediv to.app-disclosure— the old name matched generic cosmetic-filtering rules used by some content/ad blockers (notably on iOS Safari), which hid the whole section even though it's not a cookie/tracking notice at all.
Accessibility
- Found and fixed several real WCAG contrast failures (measured, not eyeballed):
--text-tertiary(2.85:1 in light mode),--border-strongon inputs/buttons (1.55:1), and white text on--accent-active(2.27:1) all fell short of the required 4.5:1 (text) / 3:1 (UI components) — all three now pass in both themes. - Added a visually-hidden
<h1>Mastofoto</h1>in the header, giving every view a proper heading hierarchy starting from one<h1>(previously the page had none — headings jumped straight to<h2>). #list-selecthad no accessible name at all (the "List" heading nearby isn't programmatically associated with it) — added a visually-hidden<label>.- The Favourite/Reblog buttons briefly had an
aria-label("Favourite"/"Reblog") added alongside their new SVG icons, which overrides an element's whole accessible name and so silently dropped the visible count from what's announced to screen readers. Replaced with a visually-hidden.sr-onlylabel next to the visible count instead, so the announced name is "Favourite, 5" rather than just "Favourite". - Photo images lacking an author-provided description now get a fallback
alt("Photo without a description") instead of an empty one, so screen readers announce that a photo exists rather than skipping it entirely. - Error/status messages (
#login-error,#list-setup-error,#timeline-error,#no-list-message) now userole="alert"/aria-live="polite"so they're announced automatically instead of requiring the user to find them manually. - The lightbox now has
role="dialog"/aria-modal="true", and moves focus to its close button on open and back to the triggering photo on close. - Split the brand blue from an accessible one:
#2b90d9measured only ~3.45:1 as text/button-label color, so it's now reserved for non-text branding (the logo/favicon/theme-color) only. Links use a new--linktoken (#1a6699light /#5aa9e6dark — brighter in dark mode since a link's background is the page surface, which changes per theme), and solid buttons/the "New" badge/the active favourite-reblog state use--btn-primary-bg(#1c69a0, same in both themes since a button's own fill is its immediate background regardless of page theme). Both pass 4.5:1+ with their paired text color.
0.4.1
Security
- The avatar and display-name links on each post (added after 0.3's profile-link feature) only HTML-escaped
account.url, unlike the existing@usernamelink — a remote account could set ajavascript:URI as its profile URL and get it executed when a viewer clicked the avatar or name. All three profile links now share oneisHttpUrl()scheme check.
0.4.0
Added
- Pull-to-refresh on the timeline: dragging down from the top of the feed reloads the current list. Implemented natively (touch events + CSS, no library), since standalone/home-screen mode on iOS and Android has no built-in reload gesture the way a regular browser tab does.
Fixed
- On mobile, every post's wrapped timestamp used
flex-basis: 100%together withmargin-left: 50pxto indent it under the author info — the margin added on top of the already-100%-wide box pushed each post 50px past the edge of the screen, forcing the whole page to scroll horizontally. Switched topadding-left(included in the width underbox-sizing: border-box) so the indent no longer adds extra width.
0.3.3
Several mobile-experience improvements, refining the responsive work started in 0.3.2.
Changed
- On narrow (mobile) viewports, the post timestamp now wraps onto its own line below the author's name/username instead of sharing the top row, indented to align under the author info.
- Reduced header and content padding on narrow viewports, and tightened the spacing between post cards, so more of the feed fits on a phone screen.
- All mobile-specific styling was consolidated into a single
@media (max-width: 480px)block at the end ofstyle.css, instead of being spread across the file.
0.3.2
Added
- A web app manifest (
manifest.json) plusapple-touch-icon/theme-colortags, so the existing favicon PNG is used as the home-screen icon when the app is installed/added to the home screen on mobile.
Changed
- On narrow (mobile) viewports, the "List Management" and "Log out" buttons collapse to icon-only circular buttons (matching the existing info button style), hiding their text labels to save header space.
- Reworded the login and About page descriptions to make explicit that Mastofoto shows the posts of a Mastodon list and filters out anything that isn't a photo post — user feedback showed the previous, more abstract wording ("distraction-free photo feed") didn't convey either point clearly.
Fixed
- On narrow screens, a long display name or username in a post header could force the row wider than the card, pushing the timestamp outside the post box. The author block now shrinks and truncates with an ellipsis instead, keeping the date always visible.