diff --git a/package-lock.json b/package-lock.json index d4c57a50..5011df4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1321,6 +1321,11 @@ "stream-shift": "1.0.0" } }, + "eases-jsnext": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/eases-jsnext/-/eases-jsnext-1.0.10.tgz", + "integrity": "sha512-1bO1+FIuqtOZpcyoIJuTnw8PU9X+RHHA248mZ1m+CPiiKFGCiNLWecITlhO4DXe7whZmBoJyfKwUoMW0KK5mNw==" + }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -6779,6 +6784,11 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-1.51.0.tgz", "integrity": "sha512-lqa9eAZ4ZQLMWsoyynAogUtib7HhHnrJJaS93uRgZU5cfXquBVR+FkKVK41LdlwffmOfOjbUin6pT8e/LZUwjA==" }, + "svelte-extras": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/svelte-extras/-/svelte-extras-1.6.0.tgz", + "integrity": "sha512-0yzXHJdnaX3+KiLrDu9Hl6V7+idfKrUkYqhpbdnxCEJos2FSxtpos6cjAt+A2vVrdcNjFqtXYs6xS+rFWeg1yA==" + }, "svelte-loader": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/svelte-loader/-/svelte-loader-2.3.3.tgz", @@ -6788,6 +6798,37 @@ "tmp": "0.0.31" } }, + "svelte-transitions": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/svelte-transitions/-/svelte-transitions-1.1.1.tgz", + "integrity": "sha1-AaLpVPOnTXH8dtOn3Sn90VVRCBA=", + "requires": { + "svelte-transitions-fade": "1.0.0", + "svelte-transitions-fly": "1.0.2", + "svelte-transitions-slide": "1.0.0" + } + }, + "svelte-transitions-fade": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-transitions-fade/-/svelte-transitions-fade-1.0.0.tgz", + "integrity": "sha1-2+FSDfH1tTcL1hr+/Gfy0v/2MwM=" + }, + "svelte-transitions-fly": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/svelte-transitions-fly/-/svelte-transitions-fly-1.0.2.tgz", + "integrity": "sha1-CP02aUG0uSmpL5Y1uQJDpYbCuNc=", + "requires": { + "eases-jsnext": "1.0.10" + } + }, + "svelte-transitions-slide": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-transitions-slide/-/svelte-transitions-slide-1.0.0.tgz", + "integrity": "sha1-FQ3Zy455+p4vJQ4ZjH1plgvyGZQ=", + "requires": { + "eases-jsnext": "1.0.10" + } + }, "svgo": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", diff --git a/package.json b/package.json index 9e9307bd..d2d681f8 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,9 @@ "serve-static": "^1.13.1", "style-loader": "^0.19.1", "svelte": "^1.50.0", + "svelte-extras": "^1.6.0", "svelte-loader": "^2.3.3", + "svelte-transitions": "^1.1.1", "uglifyjs-webpack-plugin": "^1.1.5", "url-search-params": "^0.10.0", "webpack": "^3.10.0", diff --git a/routes/_components/LoadingMask.html b/routes/_components/LoadingMask.html new file mode 100644 index 00000000..e6f7e6b0 --- /dev/null +++ b/routes/_components/LoadingMask.html @@ -0,0 +1,61 @@ +
+ {{#if show}} +
+ + + +
+ {{/if}} +
+ + \ No newline at end of file diff --git a/routes/_components/Toast.html b/routes/_components/Toast.html new file mode 100644 index 00000000..ea6fd233 --- /dev/null +++ b/routes/_components/Toast.html @@ -0,0 +1,96 @@ +
+
+ {{text}} +
+
+ + \ No newline at end of file diff --git a/routes/_utils/toast.js b/routes/_utils/toast.js new file mode 100644 index 00000000..f2a945e8 --- /dev/null +++ b/routes/_utils/toast.js @@ -0,0 +1,18 @@ +import Toast from '../_components/Toast.html' + +let toast + +if (process.browser) { + toast = new Toast({ + target: document.querySelector('#toast') + }) + if (process.env.NODE_ENV !== 'production') { + window.toast = toast // for debugging + } +} else { + toast = { + say: () => {} + } +} + +export { toast } \ No newline at end of file diff --git a/routes/settings/_components/SettingsList.html b/routes/settings/_components/SettingsList.html index fd5c8eab..2e5e5060 100644 --- a/routes/settings/_components/SettingsList.html +++ b/routes/settings/_components/SettingsList.html @@ -4,8 +4,15 @@ \ No newline at end of file diff --git a/routes/settings/_components/SettingsNav.html b/routes/settings/_components/SettingsNav.html index cbe6137f..11615365 100644 --- a/routes/settings/_components/SettingsNav.html +++ b/routes/settings/_components/SettingsNav.html @@ -13,16 +13,15 @@ diff --git a/routes/settings/instances/add.html b/routes/settings/instances/add.html index 79bff786..a4333eb8 100644 --- a/routes/settings/instances/add.html +++ b/routes/settings/instances/add.html @@ -6,6 +6,8 @@

Add an Instance

+ + {{#if $isUserLoggedIn}}

Connect to an instance to log in.

{{else}} @@ -15,7 +17,7 @@
- +
{{#if !$isUserLoggedIn}} @@ -53,6 +55,9 @@ import { store } from '../../_utils/store' import { goto } from 'sapper/runtime.js' import { switchToTheme } from '../../_utils/themeEngine' + import { toast } from '../../_utils/toast' + import LoadingMask from '../../_components/LoadingMask' + import { fade } from 'svelte-transitions' const REDIRECT_URI = (typeof location !== 'undefined' ? location.origin : 'https://pinafore.social') + '/settings/instances/add' @@ -70,17 +75,37 @@ }, components: { Layout, - SettingsLayout + SettingsLayout, + LoadingMask }, store: () => store, + transitions: { + fade + }, methods: { onSubmit: async function(event) { event.preventDefault() + this.set({loading: true}) + try { + await this.redirectToOauth() + } catch (err) { + if (process.env.NODE_ENV !== 'production') { + console.error(err) + } + toast.say(`Error: ${err.message || err.name}. Is this a valid Mastodon instance?`) + } finally { + this.set({loading: false}) + } + }, + redirectToOauth: async function() { let instanceName = this.store.get('instanceNameInSearch') + let loggedInInstances = this.store.get('loggedInInstances') instanceName = instanceName.replace(/^https?:\/\//, '').replace('/$', '') - // TODO: show toast error if you're already logged into this instance + if (Object.keys(loggedInInstances).includes(instanceName)) { + toast.say(`You've already logged in to ${instanceName}`) + return + } let instanceData = await registerApplication(instanceName, REDIRECT_URI) - // TODO: handle error this.store.set({ currentRegisteredInstanceName: instanceName, currentRegisteredInstance: instanceData @@ -94,6 +119,16 @@ document.location.href = oauthUrl }, onReceivedOauthCode: async function(code) { + try { + this.set({loading: true}) + await this.registerNewInstance(code) + } catch (err) { + toast.say(`Error: ${err.message || err.name}. Failed to connect to instance.`) + } finally { + this.set({loading: false}) + } + }, + registerNewInstance: async function (code) { let currentRegisteredInstanceName = this.store.get('currentRegisteredInstanceName') let currentRegisteredInstance = this.store.get('currentRegisteredInstance') let instanceData = await getAccessTokenFromAuthCode( @@ -103,7 +138,6 @@ code, REDIRECT_URI ) - // TODO: handle error let loggedInInstances = this.store.get('loggedInInstances') let loggedInInstancesInOrder = this.store.get('loggedInInstancesInOrder') let instanceThemes = this.store.get('instanceThemes') @@ -124,7 +158,7 @@ this.store.save() switchToTheme('default') goto('/') - }, + } } } \ No newline at end of file diff --git a/scss/global.scss b/scss/global.scss index 9b8ecf8c..8317f269 100644 --- a/scss/global.scss +++ b/scss/global.scss @@ -24,7 +24,6 @@ main { background: var(--main-bg); border: 1px solid var(--main-border); border-radius: 1px; - min-height: 50vh; } h1, h2, h3, h4, h5, h6 { diff --git a/scss/themes/_base.scss b/scss/themes/_base.scss index 1b2035dd..007b5755 100644 --- a/scss/themes/_base.scss +++ b/scss/themes/_base.scss @@ -47,4 +47,11 @@ --settings-list-item-border: $border-color; --settings-list-item-bg-active: darken($main-bg-color, 10%); --settings-list-item-bg-hover: darken($main-bg-color, 2%); + + --toast-bg: $toast-bg; + --toast-border: $toast-border; + --toast-text: $secondary-text-color; + + --mask-bg: $toast-bg; + --mask-svg-fill: $secondary-text-color; } diff --git a/scss/themes/_default.scss b/scss/themes/_default.scss index bec4df7e..c3993519 100644 --- a/scss/themes/_default.scss +++ b/scss/themes/_default.scss @@ -5,6 +5,8 @@ $main-text-color: #333; $border-color: #dadada; $main-bg-color: white; $secondary-text-color: white; +$toast-border: #fafafa; +$toast-bg: #333; @import "_base.scss"; diff --git a/scss/themes/hotpants.scss b/scss/themes/hotpants.scss index 23f69f72..c44345a7 100644 --- a/scss/themes/hotpants.scss +++ b/scss/themes/hotpants.scss @@ -5,6 +5,8 @@ $main-text-color: #333; $border-color: #dadada; $main-bg-color: white; $secondary-text-color: white; +$toast-border: #fafafa; +$toast-bg: #333; @import "_base.scss"; diff --git a/scss/themes/majesty.scss b/scss/themes/majesty.scss index 325f96e3..d3fbb2f3 100644 --- a/scss/themes/majesty.scss +++ b/scss/themes/majesty.scss @@ -5,6 +5,8 @@ $main-text-color: #333; $border-color: #dadada; $main-bg-color: white; $secondary-text-color: white; +$toast-border: #fafafa; +$toast-bg: #333; @import "_base.scss"; diff --git a/scss/themes/oaken.scss b/scss/themes/oaken.scss index 8623e53f..3204af40 100644 --- a/scss/themes/oaken.scss +++ b/scss/themes/oaken.scss @@ -5,6 +5,8 @@ $main-text-color: #333; $border-color: #dadada; $main-bg-color: white; $secondary-text-color: white; +$toast-border: #fafafa; +$toast-bg: #333; @import "_base.scss"; diff --git a/scss/themes/scarlet.scss b/scss/themes/scarlet.scss index 2d0cc481..b70e7f57 100644 --- a/scss/themes/scarlet.scss +++ b/scss/themes/scarlet.scss @@ -5,6 +5,8 @@ $main-text-color: #333; $border-color: #dadada; $main-bg-color: white; $secondary-text-color: white; +$toast-border: #fafafa; +$toast-bg: #333; @import "_base.scss"; diff --git a/scss/themes/seafoam.scss b/scss/themes/seafoam.scss index 6fb13899..86b32ce5 100644 --- a/scss/themes/seafoam.scss +++ b/scss/themes/seafoam.scss @@ -5,6 +5,8 @@ $main-text-color: #333; $border-color: #dadada; $main-bg-color: white; $secondary-text-color: white; +$toast-border: #fafafa; +$toast-bg: #333; @import "_base.scss"; diff --git a/templates/2xx.html b/templates/2xx.html index 40d0018d..13233402 100644 --- a/templates/2xx.html +++ b/templates/2xx.html @@ -94,11 +94,20 @@ + + Spinner + + + +
%sapper.html%
+ +
+