Experimental "cloud" shortcuts settings import/export

This commit is contained in:
Lim Chee Aun 2024-02-26 14:00:53 +08:00
parent a3236ea0f0
commit a8b5c8cd64
6 changed files with 199 additions and 3 deletions

View file

@ -2108,7 +2108,7 @@ meter.donut[hidden] {
:root .toastify {
user-select: none;
padding: 8px 16px;
border-radius: 999px;
border-radius: 44px;
pointer-events: none;
color: var(--button-text-color);
text-shadow: 0 calc(var(--hairline-width) * -1) var(--drop-shadow-color);

View file

@ -1251,6 +1251,27 @@ function RelatedActions({
</MenuItem>
</>
)}
{import.meta.env.DEV && currentAuthenticated && isSelf && (
<>
<MenuDivider />
<MenuItem
onClick={async () => {
const relationships =
await currentMasto.v1.accounts.relationships.fetch({
id: [accountID.current],
});
const { note } = relationships[0] || {};
if (note) {
alert(note);
console.log(note);
}
}}
>
<Icon icon="pencil" />
<span>See note</span>
</MenuItem>
</>
)}
</Menu2>
{!relationship && relationshipUIState === 'loading' && (
<Loader abrupt />

View file

@ -153,6 +153,15 @@
}
#import-export-container section p {
margin: 8px 0;
&.field-button {
display: flex;
gap: 8px;
button {
flex-shrink: 0;
}
}
}
#import-export-container section details > summary {
cursor: pointer;
@ -182,3 +191,14 @@
font-size: 90%;
flex-shrink: 0;
}
#import-export-container {
footer {
font-size: 90%;
color: var(--text-insignificant-color);
.icon {
vertical-align: text-bottom;
}
}
}

View file

@ -17,6 +17,7 @@ import { fetchFollowedTags } from '../utils/followed-tags';
import pmem from '../utils/pmem';
import showToast from '../utils/show-toast';
import states from '../utils/states';
import store from '../utils/store';
import AsyncText from './AsyncText';
import Icon from './icon';
@ -716,6 +717,7 @@ function ShortcutForm({
}
function ImportExport({ shortcuts, onClose }) {
const { masto } = api();
const shortcutsStr = useMemo(() => {
if (!shortcuts) return '';
if (!shortcuts.filter(Boolean).length) return '';
@ -754,6 +756,8 @@ function ImportExport({ shortcuts, onClose }) {
}, [importShortcutStr]);
const hasCurrentSettings = states.shortcuts.length > 0;
const shortcutsImportFieldRef = useRef();
return (
<div id="import-export-container" class="sheet">
{!!onClose && (
@ -772,8 +776,9 @@ function ImportExport({ shortcuts, onClose }) {
<Icon icon="arrow-down-circle" size="l" class="insignificant" />{' '}
<span>Import</span>
</h3>
<p>
<p class="field-button">
<input
ref={shortcutsImportFieldRef}
type="text"
name="import"
placeholder="Paste shortcuts here"
@ -782,6 +787,53 @@ function ImportExport({ shortcuts, onClose }) {
setImportShortcutStr(e.target.value);
}}
/>
{states.settings.shortcutSettingsCloudImportExport && (
<button
type="button"
class="plain2 small"
disabled={importUIState === 'cloud-downloading'}
onClick={async () => {
setImportUIState('cloud-downloading');
const currentAccount = store.session.get('currentAccount');
showToast(
'Downloading saved shortcuts from instance server…',
);
try {
const relationships =
await masto.v1.accounts.relationships.fetch({
id: [currentAccount],
});
const relationship = relationships[0];
if (relationship) {
const { note = '' } = relationship;
if (
/<phanpy-shortcuts-settings>(.*)<\/phanpy-shortcuts-settings>/.test(
note,
)
) {
const settings = note.match(
/<phanpy-shortcuts-settings>(.*)<\/phanpy-shortcuts-settings>/,
)[1];
const { v, dt, data } = JSON.parse(settings);
shortcutsImportFieldRef.current.value = data;
shortcutsImportFieldRef.current.dispatchEvent(
new Event('input'),
);
}
}
setImportUIState('default');
} catch (e) {
console.error(e);
setImportUIState('error');
showToast('Unable to download shortcuts');
}
}}
title="Download shortcuts from instance server"
>
<Icon icon="cloud" />
<Icon icon="arrow-down" />
</button>
)}
</p>
{!!parsedImportShortcutStr &&
Array.isArray(parsedImportShortcutStr) && (
@ -991,8 +1043,64 @@ function ImportExport({ shortcuts, onClose }) {
<Icon icon="share" /> <span>Share</span>
</button>
)}{' '}
{states.settings.shortcutSettingsCloudImportExport && (
<button
type="button"
class="plain2"
disabled={importUIState === 'cloud-uploading'}
onClick={async () => {
setImportUIState('cloud-uploading');
const currentAccount = store.session.get('currentAccount');
try {
const relationships =
await masto.v1.accounts.relationships.fetch({
id: [currentAccount],
});
const relationship = relationships[0];
if (relationship) {
const { note = '' } = relationship;
// const newNote = `${note}\n\n\n$<phanpy-shortcuts-settings>{shortcutsStr}</phanpy-shortcuts-settings>`;
let newNote = '';
if (
/<phanpy-shortcuts-settings>(.*)<\/phanpy-shortcuts-settings>/.test(
note,
)
) {
const settingsJSON = JSON.stringify({
v: '1', // version
dt: Date.now(), // datetime stamp
data: shortcutsStr, // shortcuts settings string
});
newNote = note.replace(
/<phanpy-shortcuts-settings>(.*)<\/phanpy-shortcuts-settings>/,
`<phanpy-shortcuts-settings>${settingsJSON}</phanpy-shortcuts-settings>`,
);
} else {
newNote = `${note}\n\n\n<phanpy-shortcuts-settings>${settingsJSON}</phanpy-shortcuts-settings>`;
}
showToast('Saving shortcuts to instance server…');
await masto.v1.accounts
.$select(currentAccount)
.note.create({
comment: newNote,
});
setImportUIState('default');
showToast('Shortcuts saved');
}
} catch (e) {
console.error(e);
setImportUIState('error');
showToast('Unable to save shortcuts');
}
}}
title="Sync to instance server"
>
<Icon icon="cloud" />
<Icon icon="arrow-up" />
</button>
)}{' '}
{shortcutsStr.length > 0 && (
<small class="insignificant">
<small class="insignificant ib">
{shortcutsStr.length} characters
</small>
)}
@ -1008,6 +1116,14 @@ function ImportExport({ shortcuts, onClose }) {
</details>
)}
</section>
{states.settings.shortcutSettingsCloudImportExport && (
<footer>
<p>
<Icon icon="cloud" /> Import/export settings from/to instance
server (Very experimental)
</p>
</footer>
)}
</main>
</div>
);

View file

@ -464,6 +464,39 @@ function Settings({ onClose }) {
</div>
</li>
)}
{authenticated && (
<li>
<label>
<input
type="checkbox"
checked={
snapStates.settings.shortcutSettingsCloudImportExport
}
onChange={(e) => {
states.settings.shortcutSettingsCloudImportExport =
e.target.checked;
}}
/>{' '}
"Cloud" import/export for shortcuts settings{' '}
<Icon icon="cloud" class="more-insignificant" />
</label>
<div class="sub-section insignificant">
<small>
Very experimental.
<br />
Stored in your own profiles notes. Profile (private) notes
are mainly used for other profiles, and hidden for own
profile.
</small>
</div>
<div class="sub-section insignificant">
<small>
Note: This feature uses currently-logged-in instance server
API.
</small>
</div>
</li>
)}
<li>
<label>
<input

View file

@ -65,6 +65,7 @@ const states = proxy({
contentTranslationTargetLanguage: null,
contentTranslationHideLanguages: [],
contentTranslationAutoInline: false,
shortcutSettingsCloudImportExport: false,
mediaAltGenerator: false,
cloakMode: false,
},
@ -94,6 +95,8 @@ export function initStates() {
store.account.get('settings-contentTranslationHideLanguages') || [];
states.settings.contentTranslationAutoInline =
store.account.get('settings-contentTranslationAutoInline') ?? false;
states.settings.shortcutSettingsCloudImportExport =
store.account.get('settings-shortcutSettingsCloudImportExport') ?? false;
states.settings.mediaAltGenerator =
store.account.get('settings-mediaAltGenerator') ?? false;
states.settings.cloakMode = store.account.get('settings-cloakMode') ?? false;
@ -121,6 +124,9 @@ subscribe(states, (changes) => {
if (path.join('.') === 'settings.contentTranslationAutoInline') {
store.account.set('settings-contentTranslationAutoInline', !!value);
}
if (path.join('.') === 'settings.shortcutSettingsCloudImportExport') {
store.account.set('settings-shortcutSettingsCloudImportExport', !!value);
}
if (path.join('.') === 'settings.contentTranslationTargetLanguage') {
console.log('SET', value);
store.account.set('settings-contentTranslationTargetLanguage', value);