Allow instance-based hashtags

Also change design a little
pull/97/head
Lim Chee Aun 2023-04-08 20:42:38 +08:00
rodzic eebb55ba38
commit 959ac468d8
5 zmienionych plików z 117 dodań i 40 usunięć

Wyświetl plik

@ -26,6 +26,8 @@
#shortcuts-settings-container .shortcuts-list li .shortcut-text {
flex-grow: 1;
min-width: 0;
line-height: 1;
word-break: break-word;
}
#shortcuts-settings-container .shortcuts-list li .shortcut-actions {
flex-shrink: 0;

Wyświetl plik

@ -94,6 +94,13 @@ const TYPE_PARAMS = {
placeholder: 'e.g. PixelArt (Max 5, space-separated)',
pattern: '[^#]+',
},
{
text: 'Instance',
name: 'instance',
type: 'text',
placeholder: 'Optional, e.g. mastodon.social',
notRequired: true,
},
],
};
export const SHORTCUTS_META = {
@ -131,14 +138,15 @@ export const SHORTCUTS_META = {
},
public: {
id: 'public',
title: ({ local, instance }) =>
`${local ? 'Local' : 'Federated'} (${instance})`,
title: ({ local }) => (local ? 'Local' : 'Federated'),
subtitle: ({ instance }) => instance,
path: ({ local, instance }) => `/${instance}/p${local ? '/l' : ''}`,
icon: ({ local }) => (local ? 'group' : 'earth'),
},
trending: {
id: 'trending',
title: 'Trending',
subtitle: ({ instance }) => instance,
path: ({ instance }) => `/${instance}/trending`,
icon: 'chart',
},
@ -177,6 +185,7 @@ export const SHORTCUTS_META = {
hashtag: {
id: 'hashtag',
title: ({ hashtag }) => hashtag,
subtitle: ({ instance }) => instance,
path: ({ hashtag }) => `/t/${hashtag.split(/\s+/).join('+')}`,
icon: 'hashtag',
},
@ -307,10 +316,13 @@ function ShortcutsSettings() {
const key = i + Object.values(shortcut);
const { type } = shortcut;
if (!SHORTCUTS_META[type]) return null;
let { icon, title } = SHORTCUTS_META[type];
let { icon, title, subtitle } = SHORTCUTS_META[type];
if (typeof title === 'function') {
title = title(shortcut, i);
}
if (typeof subtitle === 'function') {
subtitle = subtitle(shortcut, i);
}
if (typeof icon === 'function') {
icon = icon(shortcut, i);
}
@ -319,6 +331,12 @@ function ShortcutsSettings() {
<Icon icon={icon} />
<span class="shortcut-text">
<AsyncText>{title}</AsyncText>
{subtitle && (
<>
{' '}
<small class="ib insignificant">{subtitle}</small>
</>
)}
</span>
<span class="shortcut-actions">
<button
@ -468,13 +486,17 @@ function ShortcutForm({
</label>
</p>
{TYPE_PARAMS[currentType]?.map?.(
({ text, name, type, placeholder, pattern }) => {
({ text, name, type, placeholder, pattern, notRequired }) => {
if (currentType === 'list') {
return (
<p>
<label>
<span>List</span>
<select name="id" required disabled={disabled}>
<select
name="id"
required={!notRequired}
disabled={disabled}
>
{lists.map((list) => (
<option value={list.id}>{list.title}</option>
))}
@ -492,7 +514,7 @@ function ShortcutForm({
type={type}
name={name}
placeholder={placeholder}
required={type === 'text'}
required={type === 'text' && !notRequired}
disabled={disabled}
list={
currentType === 'hashtag'

Wyświetl plik

@ -134,6 +134,14 @@ shortcuts .tab-bar[hidden] {
#app[data-shortcuts-view-mode='tab-menu-bar'] .deck-container {
padding-bottom: 52px;
}
#shortcuts .tab-bar li a.has-subtitle .icon,
#shortcuts .tab-bar li a.has-subtitle .icon svg {
width: 14px !important;
height: 14px !important;
}
#shortcuts .tab-bar li a span {
line-height: 1;
}
}
@media (min-width: 40em) {
@ -172,6 +180,10 @@ shortcuts .tab-bar[hidden] {
height: 44px;
gap: 4px;
}
#shortcuts .tab-bar li a span {
text-align: left;
line-height: 1;
}
#app:has(#home-page):not(:has(#home-page ~ .deck-container)):has(
header[hidden]
)

Wyświetl plik

@ -30,7 +30,7 @@ function Shortcuts() {
.map((pin, i) => {
const { type, ...data } = pin;
if (!SHORTCUTS_META[type]) return null;
let { id, path, title, icon } = SHORTCUTS_META[type];
let { id, path, title, subtitle, icon } = SHORTCUTS_META[type];
if (typeof id === 'function') {
id = id(data, i);
@ -41,6 +41,9 @@ function Shortcuts() {
if (typeof title === 'function') {
title = title(data, i);
}
if (typeof subtitle === 'function') {
subtitle = subtitle(data, i);
}
if (typeof icon === 'function') {
icon = icon(data, i);
}
@ -49,6 +52,7 @@ function Shortcuts() {
id,
path,
title,
subtitle,
icon,
};
})
@ -73,35 +77,44 @@ function Shortcuts() {
{snapStates.settings.shortcutsViewMode === 'tab-menu-bar' ? (
<nav class="tab-bar">
<ul>
{formattedShortcuts.map(({ id, path, title, icon }, i) => {
return (
<li key={i + title}>
<Link
to={path}
onClick={(e) => {
if (e.target.classList.contains('is-active')) {
e.preventDefault();
const page = document.getElementById(`${id}-page`);
console.log(id, page);
if (page) {
page.scrollTop = 0;
const updatesButton =
page.querySelector('.updates-button');
if (updatesButton) {
updatesButton.click();
{formattedShortcuts.map(
({ id, path, title, subtitle, icon }, i) => {
return (
<li key={i + title}>
<Link
class={subtitle ? 'has-subtitle' : ''}
to={path}
onClick={(e) => {
if (e.target.classList.contains('is-active')) {
e.preventDefault();
const page = document.getElementById(`${id}-page`);
console.log(id, page);
if (page) {
page.scrollTop = 0;
const updatesButton =
page.querySelector('.updates-button');
if (updatesButton) {
updatesButton.click();
}
}
}
}
}}
>
<Icon icon={icon} size="xl" alt={title} />
<span>
<AsyncText>{title}</AsyncText>
</span>
</Link>
</li>
);
})}
}}
>
<Icon icon={icon} size="xl" alt={title} />
<span>
<AsyncText>{title}</AsyncText>
{subtitle && (
<>
<br />
<small>{subtitle}</small>
</>
)}
</span>
</Link>
</li>
);
},
)}
</ul>
</nav>
) : (
@ -132,12 +145,20 @@ function Shortcuts() {
</button>
}
>
{formattedShortcuts.map(({ path, title, icon }, i) => {
{formattedShortcuts.map(({ path, title, subtitle, icon }, i) => {
return (
<MenuLink to={path} key={i + title} class="glass-menu-item">
<Icon icon={icon} size="l" />{' '}
<span class="menu-grow">
<AsyncText>{title}</AsyncText>
<span>
<AsyncText>{title}</AsyncText>
</span>
{subtitle && (
<>
{' '}
<small class="more-insignificant">{subtitle}</small>
</>
)}
</span>
<span class="menu-shortcut hide-until-focus-visible">
{i + 1}

Wyświetl plik

@ -32,8 +32,10 @@ function Hashtags(props) {
hashtags.sort();
hashtag = hashtags[0];
const { masto, instance } = api({ instance: params.instance });
const { authenticated } = api();
const { masto, instance, authenticated } = api({
instance: props?.instance || params.instance,
});
const { authenticated: currentAuthenticated } = api();
const hashtagTitle = hashtags.map((t) => `#${t}`).join(' ');
const title = instance ? `${hashtagTitle} on ${instance}` : hashtagTitle;
useTitle(title, `/:instance?/t/:hashtag`);
@ -99,7 +101,7 @@ function Hashtags(props) {
return (
<Timeline
key={hashtagTitle}
key={instance + hashtagTitle}
title={title}
titleComponent={
!!instance && (
@ -232,6 +234,7 @@ function Hashtags(props) {
{hashtags.map((t, i) => (
<MenuItem
key={t}
disabled={hashtags.length === 1}
onClick={(e) => {
hashtags.splice(i, 1);
hashtags.sort();
@ -252,7 +255,7 @@ function Hashtags(props) {
</MenuGroup>
<MenuDivider />
<MenuItem
disabled={!authenticated}
disabled={!currentAuthenticated}
onClick={() => {
const shortcut = {
type: 'hashtag',
@ -281,6 +284,23 @@ function Hashtags(props) {
>
<Icon icon="shortcut" /> <span>Add to Shorcuts</span>
</MenuItem>
<MenuItem
onClick={() => {
let newInstance = prompt(
'Enter a new instance e.g. "mastodon.social"',
);
if (!/\./.test(newInstance)) {
if (newInstance) alert('Invalid instance');
return;
}
if (newInstance) {
newInstance = newInstance.toLowerCase().trim();
navigate(`/${newInstance}/t/${hashtags.join('+')}`);
}
}}
>
<Icon icon="bus" /> <span>Go to another instance</span>
</MenuItem>
</Menu>
}
/>