diff --git a/bin/build-sass.js b/bin/build-sass.js
index 1d0d357c..a4fcb160 100755
--- a/bin/build-sass.js
+++ b/bin/build-sass.js
@@ -15,6 +15,7 @@ const now = require('performance-now')
const globalScss = path.join(__dirname, '../scss/global.scss')
const defaultThemeScss = path.join(__dirname, '../scss/themes/_default.scss')
+const offlineThemeScss = path.join(__dirname, '../scss/themes/_offline.scss')
const html2xxFile = path.join(__dirname, '../templates/2xx.html')
const scssDir = path.join(__dirname, '../scss')
const themesScssDir = path.join(__dirname, '../scss/themes')
@@ -37,7 +38,8 @@ function doWatch() {
async function compileGlobalSass() {
let results = await Promise.all([
render({file: defaultThemeScss, outputStyle: 'compressed'}),
- render({file: globalScss, outputStyle: 'compressed'})
+ render({file: globalScss, outputStyle: 'compressed'}),
+ render({file: offlineThemeScss, outputStyle: 'compressed'})
])
let css = results.map(_ => _.css).join('')
diff --git a/package-lock.json b/package-lock.json
index f5a85226..c0863a5f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3310,6 +3310,11 @@
"repeating": "2.0.1"
}
},
+ "indexeddb-getall-shim": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/indexeddb-getall-shim/-/indexeddb-getall-shim-1.3.1.tgz",
+ "integrity": "sha1-aOUV06zspHd+/9DP+ZGS248KXoY="
+ },
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
diff --git a/package.json b/package.json
index 3a3d94d8..bab23e21 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"fg-loadcss": "^2.0.1",
"font-awesome-svg-png": "^1.2.2",
"glob": "^7.1.2",
+ "indexeddb-getall-shim": "^1.3.1",
"intersection-observer": "^0.5.0",
"intl-relativeformat": "^2.1.0",
"lodash": "^4.17.4",
diff --git a/routes/_components/Layout.html b/routes/_components/Layout.html
index def3f340..87c2dbd1 100644
--- a/routes/_components/Layout.html
+++ b/routes/_components/Layout.html
@@ -1,4 +1,4 @@
-<:Window bind:innerHeight='innerHeight'/>
+<:Window bind:innerHeight bind:online />
@@ -12,15 +12,27 @@
import debounce from 'lodash/debounce'
import throttle from 'lodash/throttle'
+ import { toast } from '../_utils/toast'
import { mark, stop } from '../_utils/marks'
const SCROLL_EVENT_DELAY = 300
const RESIZE_EVENT_DELAY = 700
+ const OFFLINE_DELAY = 1000
+
+ const notifyOffline = debounce(() => {
+ toast.say('You appear to be offline. You can still read toots while offline.')
+ }, OFFLINE_DELAY)
export default {
oncreate() {
mark('onCreate Layout')
let node = this.refs.node
+ this.observe('online', online => {
+ document.body.classList.toggle('offline', !online)
+ if (!online) {
+ notifyOffline()
+ }
+ })
this.observe('innerHeight', debounce(() => {
// respond to window resize events
this.store.set({
diff --git a/routes/_components/Timeline.html b/routes/_components/Timeline.html
index 6aa756e4..727afe4d 100644
--- a/routes/_components/Timeline.html
+++ b/routes/_components/Timeline.html
@@ -26,14 +26,13 @@
export default {
async oncreate() {
- this.observe('online', e => console.log(e))
let instanceName = this.store.get('currentInstance')
let instanceData = this.store.get('currentInstanceData')
let online = this.get('online')
let statuses = online ?
await getHomeTimeline(instanceName, instanceData.access_token, null, FETCH_LIMIT) :
await getTimelineFromDatabaseAfter(null, FETCH_LIMIT)
- if (!online) {
+ if (online) {
insertStatusesIntoDatabase(statuses)
}
this.addStatuses(statuses)
diff --git a/routes/_components/VirtualList.html b/routes/_components/VirtualList.html
index 5bada12b..44519302 100644
--- a/routes/_components/VirtualList.html
+++ b/routes/_components/VirtualList.html
@@ -19,7 +19,7 @@
import { virtualListStore } from '../_utils/virtualListStore'
import { mark, stop } from '../_utils/marks'
- const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
+ const DISTANCE_FROM_BOTTOM_TO_FIRE = 200
export default {
oncreate () {
diff --git a/routes/_utils/asyncModules.js b/routes/_utils/asyncModules.js
index a665f40a..d1a45722 100644
--- a/routes/_utils/asyncModules.js
+++ b/routes/_utils/asyncModules.js
@@ -21,9 +21,14 @@ const importRequestIdleCallback = () => import(
/* webpackChunkName: 'requestidlecallback' */ 'requestidlecallback'
)
+const importIndexedDBGetAllShim = () => import(
+ /* webpackChunkName: 'indexeddb-getall-shim' */ 'indexeddb-getall-shim'
+ )
+
export {
importURLSearchParams,
importTimeline,
importIntersectionObserver,
- importRequestIdleCallback
+ importRequestIdleCallback,
+ importIndexedDBGetAllShim
}
\ No newline at end of file
diff --git a/routes/_utils/database/statuses.js b/routes/_utils/database/statuses.js
index d88852fa..3ee4b976 100644
--- a/routes/_utils/database/statuses.js
+++ b/routes/_utils/database/statuses.js
@@ -22,8 +22,8 @@ const dbPromise = new Promise((resolve, reject) => {
function transformStatusForStorage(status) {
status = cloneDeep(status)
- status.pinafore_id_as_big_int = parseInt(status, 10)
- status.pinafore_id_as_negative_big_int = -parseInt(status, 10)
+ status.pinafore_id_as_big_int = parseInt(status.id, 10)
+ status.pinafore_id_as_negative_big_int = -parseInt(status.id, 10)
status.pinafore_stale = true
return status
}
@@ -34,19 +34,15 @@ export async function getTimelineAfter(max_id = null, limit = 20) {
const tx = db.transaction(STORE, 'readonly')
const store = tx.objectStore(STORE)
const index = store.index('pinafore_id_as_negative_big_int')
- let res
let sinceAsNegativeBigInt = max_id === null ? null : -parseInt(max_id, 10)
let query = sinceAsNegativeBigInt === null ? null : IDBKeyRange.lowerBound(sinceAsNegativeBigInt, false)
+ let res
index.getAll(query, limit).onsuccess = (e) => {
- console.log('done calling getAll()')
res = e.target.result
}
- tx.oncomplete = () => {
- console.log('complete')
- resolve(res)
- }
+ tx.oncomplete = () => resolve(res)
tx.onerror = reject
})
}
diff --git a/scss/themes/_default.scss b/scss/themes/_default.scss
index eace05cd..fedc1162 100644
--- a/scss/themes/_default.scss
+++ b/scss/themes/_default.scss
@@ -8,10 +8,8 @@ $secondary-text-color: white;
$toast-border: #fafafa;
$toast-bg: #333;
-$whatever: royalblue;
-
@import "_base.scss";
-:root {
+body {
@include baseTheme();
}
diff --git a/scss/themes/_offline.scss b/scss/themes/_offline.scss
new file mode 100644
index 00000000..32878043
--- /dev/null
+++ b/scss/themes/_offline.scss
@@ -0,0 +1,20 @@
+$main-theme-color: #999999;
+$body-bg-color: lighten($main-theme-color, 38%);
+$anchor-color: $main-theme-color;
+$main-text-color: #333;
+$border-color: #dadada;
+$main-bg-color: white;
+$secondary-text-color: white;
+$toast-border: #fafafa;
+$toast-bg: #333;
+
+@import "_base.scss";
+
+body.offline,
+body.theme-hotpants.offline,
+body.theme-majesty.offline,
+body.theme-oaken.offline,
+body.theme-scarlet.offline,
+body.theme-seafoam.offline {
+ @include baseTheme();
+}
diff --git a/templates/2xx.html b/templates/2xx.html
index cc7a0f73..59a29f1a 100644
--- a/templates/2xx.html
+++ b/templates/2xx.html
@@ -16,8 +16,9 @@
diff --git a/templates/main.js b/templates/main.js
index 7c0e6fb8..70bb0640 100644
--- a/templates/main.js
+++ b/templates/main.js
@@ -1,15 +1,18 @@
import { init } from 'sapper/runtime.js'
+import { toast } from '../routes/_utils/toast'
import {
importURLSearchParams,
importIntersectionObserver,
- importRequestIdleCallback
+ importRequestIdleCallback,
+ importIndexedDBGetAllShim,
} from '../routes/_utils/asyncModules'
// polyfills
Promise.all([
typeof URLSearchParams === 'undefined' && importURLSearchParams(),
typeof IntersectionObserver === 'undefined' && importIntersectionObserver(),
- typeof requestIdleCallback === 'undefined' && importRequestIdleCallback()
+ typeof requestIdleCallback === 'undefined' && importRequestIdleCallback(),
+ !IDBObjectStore.prototype.getAll && importIndexedDBGetAllShim()
]).then(() => {
// `routes` is an array of route objects injected by Sapper
init(document.querySelector('#sapper'), __routes__)
@@ -17,7 +20,7 @@ Promise.all([
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.onstatechange = (e) => {
if (e.target.state === 'redundant') {
- importToast().then(toast => toast.say('App update available. Reload to update.'));
+ toast.say('App update available. Reload to update.');
}
}
}
diff --git a/templates/service-worker.js b/templates/service-worker.js
index 27ddf996..4d388f66 100644
--- a/templates/service-worker.js
+++ b/templates/service-worker.js
@@ -37,7 +37,8 @@ self.addEventListener('activate', event => {
})
const NETWORK_ONLY = [
- '/oauth'
+ '/oauth',
+ '/api/v1/timelines'
]
const CACHE_FIRST = [