From 0bc009140e977b39b0c36175ace2ee20a6dacb1c Mon Sep 17 00:00:00 2001
From: Lim Chee Aun
Date: Mon, 27 Feb 2023 23:59:41 +0800
Subject: [PATCH] It's time to bring back the tab bar
---
src/app.css | 42 ++-------
src/app.jsx | 22 +----
src/components/shortcuts-settings.jsx | 30 ++++++-
src/components/shortcuts.css | 111 +++++++++++++++++++++++
src/components/shortcuts.jsx | 125 +++++++++++++++++---------
src/components/timeline.jsx | 2 +-
src/pages/account-statuses.jsx | 2 +-
src/pages/hashtag.jsx | 2 +-
src/pages/home.jsx | 5 +-
src/utils/states.js | 4 +
10 files changed, 240 insertions(+), 105 deletions(-)
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 (
-
+ {snapStates.settings.shortcutsViewMode === 'tab-menu-bar' ? (
+
+ ) : (
+
+ )}
);
}
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);
}