diff --git a/src/app.css b/src/app.css index 6faeeaf6..740ebe67 100644 --- a/src/app.css +++ b/src/app.css @@ -945,6 +945,7 @@ body:has(.status-deck) .media-post-link { transform: translateY(200%); pointer-events: none; user-select: none; + opacity: 0; } #compose-button .icon { transition: transform 0.3s ease-in-out; @@ -963,6 +964,10 @@ body:has(.status-deck) .media-post-link { #compose-button .icon { filter: drop-shadow(0 1px 2px var(--button-bg-color)); } +#app:has(#shortcuts .tab-bar) #compose-button { + bottom: calc(16px + 52px); + bottom: calc(max(16px, env(safe-area-inset-bottom)) + 52px); +} /* SHEET */ @@ -1273,43 +1278,6 @@ meter.donut:is(.danger, .explode):after { /* content-visibility: hidden; */ } -/* TAB BAR */ - -#tab-bar:not([hidden]) { - position: fixed; - bottom: 16px; - bottom: max(16px, env(safe-area-inset-bottom)); - width: calc(100% - 32px); - max-width: calc(var(--main-width) - 32px); - z-index: 100; - display: flex; - background-color: var(--bg-blur-color); - backdrop-filter: blur(16px) saturate(3); - border: var(--hairline-width) solid var(--outline-color); - border-radius: 16px; - box-shadow: 0 8px 32px var(--outline-color); -} -#tab-bar li { - flex-grow: 1; - margin: 0; - padding: 0; - list-style: none; -} -#tab-bar li a { - text-align: center; - padding: 16px 0; - display: block; - color: var(--text-insignificant-color); -} -#tab-bar li a.is-active { - color: var(--link-color); - background-image: radial-gradient( - closest-side at 50% 50%, - var(--bg-blur-color), - transparent 75% - ); -} - /* 404 */ #not-found-page { diff --git a/src/app.jsx b/src/app.jsx index 3f19ae51..e05a40b8 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -286,24 +286,10 @@ function App() { } /> - - {!snapStates.settings.shortcutsColumnsMode && } + {(!snapStates.settings.shortcutsColumnsMode || + snapStates.settings.shortcutsViewMode !== 'multi-column') && ( + + )} {!!snapStates.showCompose && ( (index === 0 ? '/' : '/following'), + id: (_, index) => (index === 0 ? 'home' : 'following'), + title: (_, index) => (index === 0 ? 'Home' : 'Following'), + path: '/', icon: 'home', }, notifications: { + id: 'notifications', title: 'Notifications', path: '/notifications', icon: 'notification', }, list: { + id: 'list', title: mem( async ({ id }) => { const list = await api().masto.v1.lists.fetch(id); @@ -105,17 +108,20 @@ export const SHORTCUTS_META = { icon: 'list', }, public: { + id: 'public', title: ({ local, instance }) => `${local ? 'Local' : 'Federated'} (${instance})`, path: ({ local, instance }) => `/${instance}/p${local ? '/l' : ''}`, icon: ({ local }) => (local ? 'group' : 'earth'), }, search: { + id: 'search', title: ({ query }) => query, path: ({ query }) => `/search?q=${query}`, icon: 'search', }, 'account-statuses': { + id: 'account-statuses', title: mem( async ({ id }) => { const account = await api().masto.v1.accounts.fetch(id); @@ -129,16 +135,19 @@ export const SHORTCUTS_META = { icon: 'user', }, bookmarks: { + id: 'bookmarks', title: 'Bookmarks', path: '/b', icon: 'bookmark', }, favourites: { + id: 'favourites', title: 'Favourites', path: '/f', icon: 'heart', }, hashtag: { + id: 'hashtag', title: ({ hashtag }) => hashtag, path: ({ hashtag }) => `/t/${hashtag.split(/\s+/).join('+')}`, icon: 'hashtag', @@ -201,6 +210,21 @@ function ShortcutsSettings() { button.

+ +

+ {/*

Experimental Multi-column mode @@ -216,7 +240,7 @@ function ShortcutsSettings() { Show shortcuts in multiple columns instead of the floating button.
-

+

*/} {shortcuts.length > 0 ? (
    {shortcuts.map((shortcut, i) => { diff --git a/src/components/shortcuts.css b/src/components/shortcuts.css index 851a9d05..3baae5c7 100644 --- a/src/components/shortcuts.css +++ b/src/components/shortcuts.css @@ -44,3 +44,114 @@ transform: translateY(-200%); } } + +/* TAB BAR */ + +#shortcuts .tab-bar:not([hidden]) { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 100; + background-color: var(--bg-blur-color); + backdrop-filter: blur(16px) saturate(3); + border-top: var(--hairline-width) solid var(--outline-color); + box-shadow: 0 -8px 16px -8px var(--drop-shadow-color); + overflow: auto; + transition: all 0.3s ease-in-out; + padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) + env(safe-area-inset-left); +} +#shortcuts .tab-bar ul { + display: flex; + margin: 0; + padding: 0; +} +#shortcuts .tab-bar li { + flex-grow: 1; + margin: 0; + padding: 0; + list-style: none; + display: flex; +} +#shortcuts .tab-bar li a { + padding: 16px 0; + display: block; + color: var(--text-insignificant-color); + font-size: 10px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + padding: 8px; + text-decoration: none; + text-shadow: 0 var(--hairline-width) var(--bg-color); + max-width: max(44px, 20vw); +} +#shortcuts .tab-bar li a:active { + transform: scale(0.95); + transition: none; +} +#shortcuts .tab-bar li a * { + pointer-events: none; +} +#shortcuts .tab-bar li a span { + width: 100%; + text-align: center; + display: block; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} +#shortcuts .tab-bar li a.is-active { + color: var(--link-color); + background-image: radial-gradient( + closest-side at 50% 50%, + var(--bg-color), + transparent + ); +} +#app:has(header[hidden]) #shortcuts .tab-bar, +shortcuts .tab-bar[hidden] { + transform: translateY(200%); + pointer-events: none; + user-select: none; +} + +@media (min-width: calc(40em)) { + .timeline-deck { + margin-top: 44px; + } + .timeline-deck > header { + --margin-top: calc(44px + 8px); + } + #shortcuts .tab-bar:not([hidden]) { + top: 0; + bottom: auto; + padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 + env(safe-area-inset-left); + background-color: var(--bg-faded-blur-color); + border: 0; + box-shadow: none; + border-bottom: var(--hairline-width) solid var(--bg-faded-color); + } + #shortcuts .tab-bar ul { + justify-content: center; + } + #shortcuts .tab-bar li { + flex-grow: 0; + } + #shortcuts .tab-bar li a { + padding: 0 16px; + flex-direction: row; + font-size: 14px; + height: 44px; + gap: 4px; + } + #app:has(header[hidden]) #shortcuts .tab-bar, + shortcuts .tab-bar[hidden] { + transform: translateY(-150%); + pointer-events: none; + user-select: none; + } +} diff --git a/src/components/shortcuts.jsx b/src/components/shortcuts.jsx index 19c8d338..b8ab396d 100644 --- a/src/components/shortcuts.jsx +++ b/src/components/shortcuts.jsx @@ -11,6 +11,7 @@ import states from '../utils/states'; import AsyncText from './AsyncText'; import Icon from './icon'; +import Link from './Link'; import MenuLink from './MenuLink'; function Shortcuts() { @@ -29,8 +30,11 @@ function Shortcuts() { .map((pin, i) => { const { type, ...data } = pin; if (!SHORTCUTS_META[type]) return null; - let { path, title, icon } = SHORTCUTS_META[type]; + let { id, path, title, icon } = SHORTCUTS_META[type]; + if (typeof id === 'function') { + id = id(data); + } if (typeof path === 'function') { path = path(data, i); } @@ -42,6 +46,7 @@ function Shortcuts() { } return { + id, path, title, icon, @@ -65,47 +70,83 @@ function Shortcuts() { return (
    - { - // Close menu if the button disappears - try { - const { target } = e; - if (getComputedStyle(target).pointerEvents === 'none') { - menuRef.current?.closeMenu?.(); - } - } catch (e) {} - }} - > - - - } - > - {formattedShortcuts.map(({ path, title, icon }, i) => { - return ( - - {' '} - - {title} - - - {i + 1} - - - ); - })} - + {snapStates.settings.shortcutsViewMode === 'tab-menu-bar' ? ( + + ) : ( + { + // Close menu if the button disappears + try { + const { target } = e; + if (getComputedStyle(target).pointerEvents === 'none') { + menuRef.current?.closeMenu?.(); + } + } catch (e) {} + }} + > + + + } + > + {formattedShortcuts.map(({ path, title, icon }, i) => { + return ( + + {' '} + + {title} + + + {i + 1} + + + ); + })} + + )}
    ); } diff --git a/src/components/timeline.jsx b/src/components/timeline.jsx index 53b0a60d..fa6d055d 100644 --- a/src/components/timeline.jsx +++ b/src/components/timeline.jsx @@ -262,7 +262,7 @@ function Timeline({ {headerStart !== null && headerStart !== undefined ? ( headerStart ) : ( - + )} diff --git a/src/pages/account-statuses.jsx b/src/pages/account-statuses.jsx index 346d4fe2..5561849f 100644 --- a/src/pages/account-statuses.jsx +++ b/src/pages/account-statuses.jsx @@ -97,7 +97,7 @@ function AccountStatuses() { } - id="account_statuses" + id="account-statuses" instance={instance} emptyText="Nothing to see here yet." errorText="Unable to load statuses" diff --git a/src/pages/hashtag.jsx b/src/pages/hashtag.jsx index 6219c0c3..7bba1ebe 100644 --- a/src/pages/hashtag.jsx +++ b/src/pages/hashtag.jsx @@ -104,7 +104,7 @@ function Hashtags(props) { ) } - id="hashtags" + id="hashtag" instance={instance} emptyText="No one has posted anything with this tag yet." errorText="Unable to load posts with this tag" diff --git a/src/pages/home.jsx b/src/pages/home.jsx index 3b1aea92..4cd84d98 100644 --- a/src/pages/home.jsx +++ b/src/pages/home.jsx @@ -28,7 +28,8 @@ function Home() { return ( <> - {snapStates.settings.shortcutsColumnsMode && + {(snapStates.settings.shortcutsColumnsMode || + snapStates.settings.shortcutsViewMode === 'multi-column') && !!snapStates.shortcuts?.length ? ( ) : ( @@ -40,7 +41,7 @@ function Home() { headerEnd={ { diff --git a/src/utils/states.js b/src/utils/states.js index a42bc6bd..44ca5119 100644 --- a/src/utils/states.js +++ b/src/utils/states.js @@ -37,6 +37,7 @@ const states = proxy({ shortcuts: store.account.get('shortcuts') ?? [], // Settings settings: { + shortcutsViewMode: store.account.get('settings-shortcutsViewMode') ?? null, shortcutsColumnsMode: store.account.get('settings-shortcutsColumnsMode') ?? false, boostsCarousel: store.account.get('settings-boostsCarousel') ?? true, @@ -58,6 +59,9 @@ subscribe(states, (v) => { if (path.join('.') === 'settings.shortcutsColumnsMode') { store.account.set('settings-shortcutsColumnsMode', !!value); } + if (path.join('.') === 'settings.shortcutsViewMode') { + store.account.set('settings-shortcutsViewMode', value); + } if (path?.[0] === 'shortcuts') { store.account.set('shortcuts', states.shortcuts); }