diff --git a/README.md b/README.md index fea2c6a..8f5c328 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,9 @@ Available variables: - May specify a self-hosted Lingva instance, powered by either [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api) - List of fallback instances hard-coded in `/.env` - [↗️ List of lingva-translate instances](https://github.com/thedaviddelta/lingva-translate?tab=readme-ov-file#instances) +- `PHANPY_IMG_ALT_API_URL` (optional, no defaults): + - API endpoint for self-hosted instance of [img-alt-api](https://github.com/cheeaun/img-alt-api). + - If provided, a setting will appear for users to enable the image description generator in the composer. Disabled by default. - `PHANPY_GIPHY_API_KEY` (optional, no defaults): - API key for [GIPHY](https://developers.giphy.com/). See [API docs](https://developers.giphy.com/docs/api/). - If provided, a setting will appear for users to enable the GIF picker in the composer. Disabled by default. @@ -205,6 +208,7 @@ These are self-hosted by other wonderful folks. - [phanpy.hear-me.social](https://phanpy.hear-me.social) by [@admin@hear-me.social](https://hear-me.social/@admin) - [phanpy.fulda.social](https://phanpy.fulda.social) by [@Ganneff@fulda.social](https://fulda.social/@Ganneff) - [phanpy.crmbl.uk](https://phanpy.crmbl.uk) by [@snail@crmbl.uk](https://mstdn.crmbl.uk/@snail) +- [halo.mookiesplace.com](https://halo.mookiesplace.com) by [@mookie@mookiesplace.com](https://mookiesplace.com/@mookie) > Note: Add yours by creating a pull request. diff --git a/src/app.css b/src/app.css index db85c3a..6e0242e 100644 --- a/src/app.css +++ b/src/app.css @@ -306,13 +306,20 @@ a[href^='http'][rel*='nofollow']:visited:not(:has(div)) { .timeline { > li:not(.timeline-item-carousel, .timeline-item-container) { &:has(.status-media-first) { - width: fit-content; + @media (min-width: 40em) { + width: fit-content; + max-width: min(480px, 100%); + } + background-color: transparent !important; border: 0 !important; box-shadow: none !important; - max-width: min(480px, 100%); margin-inline: auto !important; + &:not(:first-child) { + margin-block: 32px; + } + &:has(.skeleton) { width: 100%; } @@ -1911,7 +1918,8 @@ body > .szh-menu-container { /* two columns only */ grid-template-columns: repeat(2, 1fr); } -.szh-menu .menu-horizontal:has(> .szh-menu__item:only-child) { +.szh-menu .menu-horizontal:has(> .szh-menu__item:only-child), +.szh-menu .menu-horizontal:has(> .szh-menu__submenu:only-child) { grid-template-columns: 1fr; } .szh-menu .menu-horizontal > .szh-menu__item:not(:only-child):first-child, diff --git a/src/app.jsx b/src/app.jsx index 1b18093..e74246b 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -53,7 +53,7 @@ import { getAccessToken } from './utils/auth'; import focusDeck from './utils/focus-deck'; import states, { initStates, statusKey } from './utils/states'; import store from './utils/store'; -import { getCurrentAccount } from './utils/store-utils'; +import { getCurrentAccount, setCurrentAccountID } from './utils/store-utils'; import './utils/toast-alert'; window.__STATES__ = states; @@ -338,7 +338,7 @@ function App() { window.__IGNORE_GET_ACCOUNT_ERROR__ = true; const account = getCurrentAccount(); if (account) { - store.session.set('currentAccount', account.info.id); + setCurrentAccountID(account.info.id); const { client } = api({ account }); const { instance } = client; // console.log('masto', masto); diff --git a/src/components/account-info.jsx b/src/components/account-info.jsx index f93fcca..49cb427 100644 --- a/src/components/account-info.jsx +++ b/src/components/account-info.jsx @@ -22,7 +22,8 @@ import shortenNumber from '../utils/shorten-number'; import showToast from '../utils/show-toast'; import states, { hideAllModals } from '../utils/states'; import store from '../utils/store'; -import { updateAccount } from '../utils/store-utils'; +import { getCurrentAccountID, updateAccount } from '../utils/store-utils'; +import supports from '../utils/supports'; import AccountBlock from './account-block'; import Avatar from './avatar'; @@ -198,10 +199,7 @@ function AccountInfo({ } } - const isSelf = useMemo( - () => id === store.session.get('currentAccount'), - [id], - ); + const isSelf = useMemo(() => id === getCurrentAccountID(), [id]); useEffect(() => { const infoHasEssentials = !!( @@ -920,7 +918,7 @@ function RelatedActions({ useEffect(() => { if (info) { - const currentAccount = store.session.get('currentAccount'); + const currentAccount = getCurrentAccountID(); let currentID; (async () => { if (sameInstance && authenticated) { @@ -1094,16 +1092,18 @@ function RelatedActions({ Translate bio - { - setShowPrivateNoteModal(true); - }} - > - - - {privateNote ? 'Edit private note' : 'Add private note'} - - + {supports('@mastodon/profile-private-note') && ( + { + setShowPrivateNoteModal(true); + }} + > + + + {privateNote ? 'Edit private note' : 'Add private note'} + + + )} {following && !!relationship && ( <> )} - {currentAuthenticated && isSelf && standalone && ( - <> - - { - setShowEditProfile(true); - }} - > - - Edit profile - - - )} + {currentAuthenticated && + isSelf && + standalone && + supports('@mastodon/profile-edit') && ( + <> + + { + setShowEditProfile(true); + }} + > + + Edit profile + + + )} {import.meta.env.DEV && currentAuthenticated && isSelf && ( <> diff --git a/src/components/compose.css b/src/components/compose.css index cfa4cdd..407f172 100644 --- a/src/components/compose.css +++ b/src/components/compose.css @@ -310,7 +310,7 @@ #compose-container .form-visibility-direct { --yellow-stripes: repeating-linear-gradient( - -45deg, + 135deg, var(--reply-to-faded-color), var(--reply-to-faded-color) 10px, var(--reply-to-faded-color) 10px, diff --git a/src/components/compose.jsx b/src/components/compose.jsx index de3177a..49f9a84 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -124,14 +124,14 @@ const MENTION_RE = new RegExp( // AI-generated, all other regexes are too complicated const HASHTAG_RE = new RegExp( - `(^|[^=\\/\\w])(#[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?)(?![\\/\\w])`, + `(^|[^=\\/\\w])(#[a-z0-9_]+([a-z0-9_.]+[a-z0-9_]+)?)(?![\\/\\w])`, 'ig', ); // https://github.com/mastodon/mastodon/blob/23e32a4b3031d1da8b911e0145d61b4dd47c4f96/app/models/custom_emoji.rb#L31 const SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}'; const SCAN_RE = new RegExp( - `([^A-Za-z0-9_:\\n]|^)(:${SHORTCODE_RE_FRAGMENT}:)(?=[^A-Za-z0-9_:]|$)`, + `(^|[^=\\/\\w])(:${SHORTCODE_RE_FRAGMENT}:)(?=[^A-Za-z0-9_:]|$)`, 'g', ); @@ -988,7 +988,11 @@ function Compose({ } else { try { newStatus = await masto.v1.statuses.create(params, { - idempotencyKey: UID.current, + requestInit: { + headers: { + 'Idempotency-Key': UID.current, + }, + }, }); } catch (_) { // If idempotency key fails, try again without it @@ -1215,22 +1219,30 @@ function Compose({ /> {' '} - {' '} + {/* If maxOptions is not defined or defined and is greater than 1, show poll button */} + {maxOptions == null || + (maxOptions > 1 && ( + <> + {' '} + + ))}