Skip to content

Commit b078584

Browse files
committed
2 parents 05c61ba + 1c9b662 commit b078584

36 files changed

Lines changed: 1679 additions & 1205 deletions

File tree

CHANGELOG.md

Lines changed: 139 additions & 0 deletions
Large diffs are not rendered by default.

app/helpers/context_helper.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module ContextHelper
4444
interaction_policies: {
4545
'gts' => 'https://gotosocial.org/ns#',
4646
'interactionPolicy' => { '@id' => 'gts:interactionPolicy', '@type' => '@id' },
47+
'canFeature' => { '@id' => 'https://w3id.org/fep/7aa9#canFeature', '@type' => '@id' },
4748
'canQuote' => { '@id' => 'gts:canQuote', '@type' => '@id' },
4849
'automaticApproval' => { '@id' => 'gts:automaticApproval', '@type' => '@id' },
4950
'manualApproval' => { '@id' => 'gts:manualApproval', '@type' => '@id' },
@@ -54,6 +55,22 @@ module ContextHelper
5455
'interactingObject' => { '@id' => 'gts:interactingObject', '@type' => '@id' },
5556
'interactionTarget' => { '@id' => 'gts:interactionTarget', '@type' => '@id' },
5657
},
58+
feature_requests: { 'FeatureRequest' => 'https://w3id.org/fep/7aa9#FeatureRequest' },
59+
featured_collections: {
60+
'FeaturedCollection' => 'https://w3id.org/fep/7aa9#FeaturedCollection',
61+
'FeaturedItem' => 'https://w3id.org/fep/7aa9#FeaturedItem',
62+
'FeatureRequest' => 'https://w3id.org/fep/7aa9#FeatureRequest',
63+
'FeatureAuthorization' => 'https://w3id.org/fep/7aa9#FeatureAuthorization',
64+
'topic' => { '@id' => 'https://w3id.org/fep/7aa9#topic', '@type' => '@id' },
65+
'featuredObject' => { '@id' => 'https://w3id.org/fep/7aa9#featuredObject', '@type' => '@id' },
66+
'featureAuthorization' => { '@id' => 'https://w3id.org/fep/7aa9#featureAuthorization', '@type' => '@id' },
67+
},
68+
feature_authorizations: {
69+
'gts' => 'https://gotosocial.org/ns#',
70+
'FeatureAuthorization' => 'https://w3id.org/fep/7aa9#FeatureAuthorization',
71+
'interactingObject' => { '@id' => 'gts:interactingObject', '@type' => '@id' },
72+
'interactionTarget' => { '@id' => 'gts:interactionTarget', '@type' => '@id' },
73+
},
5774
}.freeze
5875

5976
def full_context

app/javascript/flavours/glitch/components/hotkeys/index.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ const hotkeyMatcherMap = {
110110
mention: just('m'),
111111
open: any('enter', 'o'),
112112
openProfile: just('p'),
113-
moveDown: just('j'),
114-
moveUp: just('k'),
113+
moveDown: any('j', 'pagedown'),
114+
moveUp: any('k', 'pageup'),
115115
moveToTop: just('0'),
116116
toggleHidden: just('x'),
117117
toggleSensitive: just('h'),
@@ -148,9 +148,15 @@ const hotkeyMatcherMap = {
148148

149149
type HotkeyName = keyof typeof hotkeyMatcherMap;
150150

151-
export type HandlerMap = Partial<
152-
Record<HotkeyName, (event: KeyboardEvent) => void>
153-
>;
151+
type HandlerFunction =
152+
// When a handler returns a boolean, it should indicate whether the
153+
// hotkey was handled (i.e. it resulted in an action).
154+
// If `false` is returned, `preventDefault` and `stopPropagation`
155+
// will not be called on the keyboard event, restoring the key's
156+
// native behaviour.
157+
((event: KeyboardEvent) => boolean) | ((event: KeyboardEvent) => void);
158+
159+
export type HandlerMap = Partial<Record<HotkeyName, HandlerFunction>>;
154160

155161
export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
156162
const ref = useRef<T>(null);
@@ -185,7 +191,7 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
185191
const matchCandidates: {
186192
// A candidate will be have an undefined handler if it's matched,
187193
// but handled in a parent component rather than this one.
188-
handler: ((event: KeyboardEvent) => void) | undefined;
194+
handler: HandlerFunction | undefined;
189195
priority: number;
190196
}[] = [];
191197

@@ -210,9 +216,11 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
210216

211217
const bestMatchingHandler = matchCandidates.at(0)?.handler;
212218
if (bestMatchingHandler) {
213-
bestMatchingHandler(event);
214-
event.stopPropagation();
215-
event.preventDefault();
219+
const wasHandled = bestMatchingHandler(event);
220+
if (wasHandled !== false) {
221+
event.stopPropagation();
222+
event.preventDefault();
223+
}
216224
}
217225

218226
// Add last keypress to buffer

app/javascript/flavours/glitch/features/about/components/rules.tsx

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
66

77
import { createSelector } from '@reduxjs/toolkit';
88

9+
import type { ApiRuleJSON } from '@/flavours/glitch/api_types/instance';
910
import type { SelectItem } from '@/flavours/glitch/components/dropdown_selector';
1011
import { Select } from '@/flavours/glitch/components/form_fields';
1112
import type { RootState } from '@/flavours/glitch/store';
@@ -104,13 +105,13 @@ export const RulesSection: FC<RulesSectionProps> = ({ isLoading = false }) => {
104105
defaultMessage='Language'
105106
/>
106107
</label>
107-
<Select onChange={handleLocaleChange} id='language-select'>
108+
<Select
109+
onChange={handleLocaleChange}
110+
id='language-select'
111+
value={selectedLocale}
112+
>
108113
{localeOptions.map((option) => (
109-
<option
110-
key={option.value}
111-
value={option.value}
112-
selected={option.value === selectedLocale}
113-
>
114+
<option key={option.value} value={option.value}>
114115
{option.text}
115116
</option>
116117
))}
@@ -121,15 +122,10 @@ export const RulesSection: FC<RulesSectionProps> = ({ isLoading = false }) => {
121122
);
122123
};
123124

124-
const selectRules = (state: RootState) => {
125-
const rules = state.server.server.item?.rules;
126-
127-
if (!rules) {
128-
return [];
129-
}
130-
131-
return rules;
132-
};
125+
const selectRules = createSelector(
126+
[(state: RootState) => state.server.server.item],
127+
(item) => item?.rules ?? [],
128+
);
133129

134130
const rulesSelector = createSelector(
135131
[selectRules, (_state, locale: string) => locale],
@@ -142,18 +138,19 @@ const rulesSelector = createSelector(
142138
return rule;
143139
}
144140

141+
const translatedRule: ApiRuleJSON = { ...rule };
145142
const partialLocale = locale.split('-')[0];
146143
if (partialLocale && translations[partialLocale]) {
147-
rule.text = translations[partialLocale].text;
148-
rule.hint = translations[partialLocale].hint;
144+
translatedRule.text = translations[partialLocale].text;
145+
translatedRule.hint = translations[partialLocale].hint;
149146
}
150147

151148
if (translations[locale]) {
152-
rule.text = translations[locale].text;
153-
rule.hint = translations[locale].hint;
149+
translatedRule.text = translations[locale].text;
150+
translatedRule.hint = translations[locale].hint;
154151
}
155152

156-
return rule;
153+
return translatedRule;
157154
});
158155
},
159156
);

app/javascript/flavours/glitch/features/keyboard_shortcuts/index.jsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
7272
<td><FormattedMessage id='keyboard_shortcuts.bookmark' defaultMessage='to bookmark' /></td>
7373
</tr>
7474
<tr>
75-
<td><kbd>enter</kbd>, <kbd>o</kbd></td>
75+
<td><FormattedMessage id='keyboard_shortcuts.keys.enter' defaultMessage='Enter' tagName='kbd' />, <kbd>o</kbd></td>
7676
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open status' /></td>
7777
</tr>
7878
<tr>
@@ -92,11 +92,11 @@ class KeyboardShortcuts extends ImmutablePureComponent {
9292
<td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>
9393
</tr>
9494
<tr>
95-
<td><kbd>k</kbd></td>
95+
<td><kbd>k</kbd>, <FormattedMessage id='keyboard_shortcuts.keys.page_up' defaultMessage='Page Up' tagName='kbd' /></td>
9696
<td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>
9797
</tr>
9898
<tr>
99-
<td><kbd>j</kbd></td>
99+
<td><kbd>j</kbd>, <FormattedMessage id='keyboard_shortcuts.keys.page_down' defaultMessage='Page Down' tagName='kbd' /></td>
100100
<td><FormattedMessage id='keyboard_shortcuts.down' defaultMessage='to move down in the list' /></td>
101101
</tr>
102102
<tr>
@@ -116,15 +116,15 @@ class KeyboardShortcuts extends ImmutablePureComponent {
116116
<td><FormattedMessage id='keyboard_shortcuts.compose' defaultMessage='to focus the compose textarea' /></td>
117117
</tr>
118118
<tr>
119-
<td><kbd>alt</kbd>+<kbd>n</kbd></td>
119+
<td><FormattedMessage id='keyboard_shortcuts.keys.alt' defaultMessage='Alt' tagName='kbd' />+<kbd>n</kbd></td>
120120
<td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new post' /></td>
121121
</tr>
122122
<tr>
123-
<td><kbd>alt</kbd>+<kbd>x</kbd></td>
123+
<td><FormattedMessage id='keyboard_shortcuts.keys.alt' defaultMessage='Alt' tagName='kbd' />+<kbd>x</kbd></td>
124124
<td><FormattedMessage id='keyboard_shortcuts.spoilers' defaultMessage='to show/hide CW field' /></td>
125125
</tr>
126126
<tr>
127-
<td><kbd>backspace</kbd></td>
127+
<td><FormattedMessage id='keyboard_shortcuts.keys.backspace' defaultMessage='Backspace' tagName='kbd' /></td>
128128
<td><FormattedMessage id='keyboard_shortcuts.back' defaultMessage='to navigate back' /></td>
129129
</tr>
130130
<tr>
@@ -136,7 +136,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
136136
<td><FormattedMessage id='keyboard_shortcuts.secondary_toot' defaultMessage='to send toot using secondary privacy setting' /></td>
137137
</tr>
138138
<tr>
139-
<td><kbd>esc</kbd></td>
139+
<td><FormattedMessage id='keyboard_shortcuts.keys.esc' defaultMessage='Esc' tagName='kbd' /></td>
140140
<td><FormattedMessage id='keyboard_shortcuts.unfocus' defaultMessage='to un-focus compose textarea/search' /></td>
141141
</tr>
142142
<tr>

app/javascript/flavours/glitch/features/ui/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,8 @@ class UI extends PureComponent {
557557
if (currentItemIndex === -1) {
558558
focusColumn(1);
559559
} else {
560-
focusItemSibling(currentItemIndex, -1);
560+
const wasHandled = focusItemSibling(currentItemIndex, -1);
561+
return wasHandled;
561562
}
562563
};
563564

@@ -566,7 +567,8 @@ class UI extends PureComponent {
566567
if (currentItemIndex === -1) {
567568
focusColumn(1);
568569
} else {
569-
focusItemSibling(currentItemIndex, 1);
570+
const wasHandled = focusItemSibling(currentItemIndex, 1);
571+
return wasHandled;
570572
}
571573
};
572574

app/javascript/flavours/glitch/features/ui/util/focusUtils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,12 @@ export function focusItemSibling(index: number, direction: 1 | -1) {
159159
);
160160

161161
if (!siblingItem) {
162-
return;
162+
return false;
163163
}
164164

165165
// If sibling element is empty, we skip it
166166
if (siblingItem.matches(':empty')) {
167-
focusItemSibling(index + direction, direction);
168-
return;
167+
return focusItemSibling(index + direction, direction);
169168
}
170169

171170
// Check if the sibling is a post or a 'follow suggestions' widget
@@ -184,5 +183,8 @@ export function focusItemSibling(index: number, direction: 1 | -1) {
184183
});
185184

186185
targetElement.focus();
186+
return true;
187+
} else {
188+
return false;
187189
}
188190
}

app/javascript/flavours/glitch/main.tsx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { me, reduceMotion } from 'flavours/glitch/initial_state';
1010
import ready from 'flavours/glitch/ready';
1111
import { store } from 'flavours/glitch/store';
1212

13-
import { isProduction, isDevelopment } from './utils/environment';
13+
import { isDevelopment, isProduction } from './utils/environment';
1414

1515
function main() {
1616
perf.start('main()');
@@ -41,29 +41,30 @@ function main() {
4141
);
4242
store.dispatch(setupBrowserNotifications());
4343

44-
if (isProduction() && me && 'serviceWorker' in navigator) {
45-
const { Workbox } = await import('workbox-window');
46-
const wb = new Workbox(
47-
isDevelopment() ? '/packs-dev/dev-sw.js?dev-sw' : '/sw.js',
48-
{ type: 'module', scope: '/' },
49-
);
50-
let registration;
51-
52-
try {
53-
registration = await wb.register();
54-
} catch (err) {
55-
console.error(err);
44+
if (
45+
me &&
46+
'serviceWorker' in navigator &&
47+
(isDevelopment() || isProduction()) // Disallow testing environment
48+
) {
49+
let swPath = '/sw.js';
50+
if (isDevelopment()) {
51+
const { default: swDevUrl } =
52+
await import('@/flavours/glitch/service_worker/sw?url');
53+
swPath = swDevUrl;
5654
}
5755

58-
if (
59-
registration &&
60-
'Notification' in window &&
61-
Notification.permission === 'granted'
62-
) {
63-
const registerPushNotifications =
64-
await import('flavours/glitch/actions/push_notifications');
56+
await navigator.serviceWorker.register(swPath, {
57+
scope: '/',
58+
type: 'module',
59+
});
60+
61+
if (isProduction()) {
62+
if ('Notification' in window && Notification.permission === 'granted') {
63+
const registerPushNotifications =
64+
await import('flavours/glitch/actions/push_notifications');
6565

66-
store.dispatch(registerPushNotifications.register());
66+
store.dispatch(registerPushNotifications.register());
67+
}
6768
}
6869
}
6970

0 commit comments

Comments
 (0)