mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-29 08:21:20 +00:00
Fix more navigation bugs
This commit is contained in:
parent
780f0b3407
commit
5187f3d0e9
@ -6,6 +6,7 @@
|
||||
- [x] Skip notifying admin when the person joining/leaving groups is the admin
|
||||
- [x] Remove group share modal, skip straight to create invite link
|
||||
- [x] Rank groups by WoT
|
||||
- [x] Fix subtle navigation bugs
|
||||
|
||||
# 0.4.4
|
||||
|
||||
|
@ -345,7 +345,7 @@
|
||||
let scrollY
|
||||
|
||||
const unsubHistory = router.history.subscribe($history => {
|
||||
if ($history[0].config.modal) {
|
||||
if ($history[0].modal) {
|
||||
// This is not idempotent, so don't duplicate it
|
||||
if (document.body.style.position !== "fixed") {
|
||||
scrollY = window.scrollY
|
||||
|
@ -73,7 +73,7 @@
|
||||
<i class="fa fa-cog" /> Settings
|
||||
</MenuMobileItem>
|
||||
{#if !$env.FORCE_GROUP && $env.PLATFORM_RELAYS.length === 0}
|
||||
<MenuMobileItem href="/settings/relays">
|
||||
<MenuMobileItem href="/settings/relays" on:click={closeMenu}>
|
||||
<i class="fa fa-server" />
|
||||
<div class="relative inline-block">
|
||||
Relays
|
||||
@ -84,7 +84,7 @@
|
||||
</div>
|
||||
</MenuMobileItem>
|
||||
{/if}
|
||||
<MenuMobileItem disabled={!$pubkey} href="/notifications">
|
||||
<MenuMobileItem disabled={!$pubkey} href="/notifications" on:click={closeMenu}>
|
||||
<i class="fa fa-bell" />
|
||||
<div class="relative inline-block">
|
||||
Notifications
|
||||
@ -95,11 +95,11 @@
|
||||
</div>
|
||||
</MenuMobileItem>
|
||||
{#if $env.FORCE_GROUP}
|
||||
<MenuMobileItem href="/events">
|
||||
<MenuMobileItem href="/events" on:click={closeMenu}>
|
||||
<i class="fa fa-calendar-days" /> Calendar
|
||||
</MenuMobileItem>
|
||||
{#if $env.ENABLE_MARKET}
|
||||
<MenuMobileItem href="/listings">
|
||||
<MenuMobileItem href="/listings" on:click={closeMenu}>
|
||||
<i class="fa fa-store" /> Market
|
||||
</MenuMobileItem>
|
||||
{/if}
|
||||
@ -108,7 +108,7 @@
|
||||
<i class="fa fa-people-pulling" /> Community
|
||||
</MenuMobileItem>
|
||||
{/if}
|
||||
<MenuMobileItem disabled={!$canSign} href="/channels">
|
||||
<MenuMobileItem disabled={!$canSign} href="/channels" on:click={closeMenu}>
|
||||
<i class="fa fa-message" />
|
||||
<div class="relative inline-block">
|
||||
Messages
|
||||
@ -118,7 +118,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
</MenuMobileItem>
|
||||
<MenuMobileItem href="/notes">
|
||||
<MenuMobileItem href="/notes" on:click={closeMenu}>
|
||||
<i class="fa fa-rss" /> Feed
|
||||
</MenuMobileItem>
|
||||
</div>
|
||||
@ -134,16 +134,16 @@
|
||||
<SliderMenu onEscape={closeSubMenu}>
|
||||
<p class="staatliches mb-8 text-center text-3xl">Community</p>
|
||||
<div class="staatliches m-auto grid grid-cols-2 gap-3">
|
||||
<MenuMobileItem href="/events">
|
||||
<MenuMobileItem href="/events" on:click={closeMenu}>
|
||||
<i class="fa fa-calendar-days" /> Calendar
|
||||
</MenuMobileItem>
|
||||
{#if $env.ENABLE_MARKET}
|
||||
<MenuMobileItem href="/listings">
|
||||
<MenuMobileItem href="/listings" on:click={closeMenu}>
|
||||
<i class="fa fa-store" /> Market
|
||||
</MenuMobileItem>
|
||||
{/if}
|
||||
{#if !$env.FORCE_GROUP}
|
||||
<MenuMobileItem href="/groups">
|
||||
<MenuMobileItem href="/groups" on:click={closeMenu}>
|
||||
<i class="fa fa-circle-nodes" /> Groups
|
||||
</MenuMobileItem>
|
||||
{/if}
|
||||
@ -156,20 +156,20 @@
|
||||
<p class="staatliches mb-8 text-center text-3xl">Settings</p>
|
||||
<div class="staatliches m-auto grid grid-cols-2 gap-3">
|
||||
{#if $installPrompt}
|
||||
<MenuMobileItem on:click={installAsPWA}>
|
||||
<MenuMobileItem on:click={installAsPWA} on:click={closeMenu}>
|
||||
<i class="fa fa-rocket" /> Install
|
||||
</MenuMobileItem>
|
||||
{/if}
|
||||
<MenuMobileItem on:click={toggleTheme}>
|
||||
<MenuMobileItem on:click={toggleTheme} on:click={closeMenu}>
|
||||
<i class="fa fa-palette" /> Theme
|
||||
</MenuMobileItem>
|
||||
<MenuMobileItem disabled={!$pubkey} href="/settings/data">
|
||||
<MenuMobileItem disabled={!$pubkey} href="/settings/data" on:click={closeMenu}>
|
||||
<i class="fa fa-database" /> Database
|
||||
</MenuMobileItem>
|
||||
<MenuMobileItem disabled={!$canSign} href="/settings/content">
|
||||
<MenuMobileItem disabled={!$canSign} href="/settings/content" on:click={closeMenu}>
|
||||
<i class="fa fa-volume-xmark" /> Content
|
||||
</MenuMobileItem>
|
||||
<MenuMobileItem disabled={!$canSign} href="/settings">
|
||||
<MenuMobileItem disabled={!$canSign} href="/settings" on:click={closeMenu}>
|
||||
<i class="fa fa-sliders" /> App Settings
|
||||
</MenuMobileItem>
|
||||
</div>
|
||||
@ -180,13 +180,13 @@
|
||||
<SliderMenu onEscape={closeSubMenu}>
|
||||
<p class="staatliches mb-8 text-center text-3xl">Account</p>
|
||||
<div class="staatliches m-auto mb-8 grid grid-cols-2 gap-3">
|
||||
<MenuMobileItem href="/settings/keys">
|
||||
<MenuMobileItem href="/settings/keys" on:click={closeMenu}>
|
||||
<i class="fa fa-key" /> Keys
|
||||
</MenuMobileItem>
|
||||
<MenuMobileItem href={router.at("people").of($pubkey).toString()}>
|
||||
<MenuMobileItem href={router.at("people").of($pubkey).toString()} on:click={closeMenu}>
|
||||
<i class="fa fa-user-circle" /> Profile
|
||||
</MenuMobileItem>
|
||||
<MenuMobileItem href={router.at("invite/create").qp({initialPubkey: $pubkey}).toString()}>
|
||||
<MenuMobileItem href={router.at("invite/create").qp({initialPubkey: $pubkey}).toString()} on:click={closeMenu}>
|
||||
<i class="fa fa-paper-plane" /> Create Invite
|
||||
</MenuMobileItem>
|
||||
</div>
|
||||
|
@ -30,12 +30,12 @@
|
||||
$: {
|
||||
// Redirect if we have no user
|
||||
if (!$session && $page && router.getMatch($page.path).route.requireUser) {
|
||||
router.go("/", {replace: true})
|
||||
router.go({path: "/", replace: true})
|
||||
}
|
||||
|
||||
// Redirect if we need a signer
|
||||
if (!$signer.isEnabled() && $page && router.getMatch($page.path).route.requireSigner) {
|
||||
router.go("/", {replace: true})
|
||||
router.go({path: "/", replace: true})
|
||||
}
|
||||
|
||||
const props = router.getProps($current)
|
||||
@ -44,7 +44,7 @@
|
||||
// This is usually due to a malformed url.
|
||||
for (const k of router.getMatch($current.path).route.required || []) {
|
||||
if (!props[k]) {
|
||||
router.go("/", {replace: true})
|
||||
router.go({path: "/", replace: true})
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -71,9 +71,9 @@
|
||||
</div>
|
||||
{/key}
|
||||
|
||||
{#each reverse($modals).filter(m => !m.config.virtual) as m, i (router.getKey(m) + i)}
|
||||
{#each reverse($modals).filter(m => !m.virtual) as m, i (router.getKey(m) + i)}
|
||||
{@const promise = router.getMatch(m.path).route.component}
|
||||
<Modal virtual={false} canClose={!m.config.noEscape}>
|
||||
<Modal virtual={false} canClose={!m.noEscape}>
|
||||
{#key $stateKey}
|
||||
{#await promise}
|
||||
<!-- pass -->
|
||||
|
@ -12,15 +12,17 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const getClick = e => {
|
||||
if (!e.touches) {
|
||||
return null
|
||||
const t = Date.now()
|
||||
|
||||
if (e.touches?.[0]) {
|
||||
return {x: e.touches[0].clientX, y: e.touches[0].clientY, t}
|
||||
}
|
||||
|
||||
return {
|
||||
x: e.x || e.touches[0].clientX,
|
||||
y: e.y || e.touches[0].clientY,
|
||||
t: Date.now(),
|
||||
if (e.x || e.y) {
|
||||
return {x: e.x, y: e.y, t}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const startClick = e => {
|
||||
|
@ -53,7 +53,7 @@
|
||||
}
|
||||
|
||||
historyItem = $history[0]
|
||||
isNested = Boolean($history[1]?.config.modal)
|
||||
isNested = Boolean($history[1]?.modal)
|
||||
|
||||
// If history changes and removes this modal, notify the caller if virtual
|
||||
const unsub = history.subscribe($history => {
|
||||
|
@ -38,7 +38,6 @@ const createHistory = source => {
|
||||
to,
|
||||
{state = {}, replace = false, preserveScroll = false, blurActiveElement = true} = {},
|
||||
) {
|
||||
state = {...state, key: Date.now() + ""}
|
||||
// try...catch iOS Safari limits to 100 pushState calls
|
||||
try {
|
||||
if (replace) source.history.replaceState(state, "", to)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {takeWhile, find, filter, identity, mergeLeft, reject, path as getPath} from "ramda"
|
||||
import {first, filterVals} from "hurdak"
|
||||
import {takeWhile, pick, find, filter, identity, mergeLeft, reject, prop} from "ramda"
|
||||
import {first, randomId, filterVals} from "hurdak"
|
||||
import logger from "src/util/logger"
|
||||
import {buildQueryString, parseQueryString, updateIn} from "src/util/misc"
|
||||
import {globalHistory} from "src/util/history"
|
||||
@ -135,7 +135,8 @@ export type Route = RegisterOpts & {
|
||||
component: any
|
||||
}
|
||||
|
||||
export type RouteConfig = {
|
||||
export type HistoryItem = {
|
||||
path: string
|
||||
key?: string
|
||||
mini?: boolean
|
||||
modal?: boolean
|
||||
@ -145,11 +146,6 @@ export type RouteConfig = {
|
||||
context?: Record<string, any>
|
||||
}
|
||||
|
||||
export type HistoryItem = {
|
||||
path: string
|
||||
config: RouteConfig
|
||||
}
|
||||
|
||||
export const asPath = (...parts: string[]) => {
|
||||
let path = parts.filter(identity).join("/")
|
||||
|
||||
@ -230,15 +226,15 @@ class RouterExtension {
|
||||
return path
|
||||
}
|
||||
|
||||
go = (newConfig = {}) => {
|
||||
const config = filterVals(identity, {
|
||||
...this.config,
|
||||
...newConfig,
|
||||
context: this.context,
|
||||
})
|
||||
|
||||
this.router.go(this.toString(), config)
|
||||
}
|
||||
go = (newConfig = {}) =>
|
||||
this.router.go(
|
||||
filterVals(identity, {
|
||||
...this.config,
|
||||
...newConfig,
|
||||
context: this.context,
|
||||
path: this.toString(),
|
||||
})
|
||||
)
|
||||
|
||||
push = (config = {}) => this.go(config)
|
||||
|
||||
@ -253,11 +249,11 @@ export class Router {
|
||||
routes: Route[] = []
|
||||
extensions: Record<string, RouterExtension> = {}
|
||||
history = writable<HistoryItem[]>([])
|
||||
nonVirtual = this.history.derived(reject(getPath(["config", "virtual"])))
|
||||
pages = this.nonVirtual.derived(filter((h: HistoryItem) => !h.config.modal))
|
||||
page = this.nonVirtual.derived(find((h: HistoryItem) => !h.config.modal))
|
||||
modals = this.nonVirtual.derived(takeWhile((h: HistoryItem) => h.config.modal))
|
||||
modal = this.nonVirtual.derived(find((h: HistoryItem) => h.config.modal))
|
||||
nonVirtual = this.history.derived(reject(prop('virtual')))
|
||||
pages = this.nonVirtual.derived(filter((h: HistoryItem) => !h.modal))
|
||||
page = this.nonVirtual.derived(find((h: HistoryItem) => !h.modal))
|
||||
modals = this.nonVirtual.derived(takeWhile((h: HistoryItem) => h.modal))
|
||||
modal = this.nonVirtual.derived(find((h: HistoryItem) => h.modal))
|
||||
current = this.nonVirtual.derived(history => history[0])
|
||||
|
||||
init() {
|
||||
@ -271,14 +267,17 @@ export class Router {
|
||||
|
||||
listen() {
|
||||
return globalHistory.listen(({location, action}) => {
|
||||
const {state, pathname, search} = location
|
||||
const path = pathname + search
|
||||
const [cur, prev] = this.history.get()
|
||||
const key = this.getKey(location.state)
|
||||
const key = this.getKey({path: pathname, ...state})
|
||||
|
||||
// If we're going back, splice instead of push
|
||||
if (action === "POP" && prev && key === this.getKey(prev)) {
|
||||
this.history.update($history => $history.slice(1))
|
||||
} else if (key !== this.getKey(cur)) {
|
||||
this.go(location.pathname + location.search)
|
||||
if (action === "POP") {
|
||||
if (prev && path === prev.path && key !== this.getKey(cur)) {
|
||||
this.history.update($history => $history.slice(1))
|
||||
} else if (path !== cur.path) {
|
||||
this.go({path})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -301,20 +300,26 @@ export class Router {
|
||||
return match
|
||||
}
|
||||
|
||||
go(path, {replace, ...config}: RouteConfig = {}) {
|
||||
const state = {path, config}
|
||||
go({replace, ...state}: HistoryItem = {}) {
|
||||
if (!state.path) {
|
||||
throw new Error("router.go called without a path")
|
||||
}
|
||||
|
||||
if (!state.key) {
|
||||
state.key = randomId()
|
||||
}
|
||||
|
||||
this.history.update($history => {
|
||||
// Drop one if we're replacing
|
||||
if (replace) {
|
||||
$history.splice(0, 1)
|
||||
$history = $history.slice(1)
|
||||
}
|
||||
|
||||
// Keep our history at 100 entries
|
||||
return [state, ...$history.slice(0, 100)]
|
||||
})
|
||||
|
||||
globalHistory.navigate(path, {replace, state})
|
||||
globalHistory.navigate(state.path, {replace, state: {key: state.key}})
|
||||
}
|
||||
|
||||
pop() {
|
||||
@ -328,18 +333,18 @@ export class Router {
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
this.history.update(reject(($item: HistoryItem) => $item.config.key === key))
|
||||
this.history.update(reject(($item: HistoryItem) => $item.key === key))
|
||||
}
|
||||
|
||||
clearModals() {
|
||||
this.history.update($history => {
|
||||
while ($history[0]?.config?.modal) {
|
||||
while ($history[0]?.modal) {
|
||||
$history.splice(0, 1)
|
||||
}
|
||||
|
||||
// Make sure we don't completely clear history out
|
||||
if ($history.length === 0) {
|
||||
$history.push({path: "/", config: {}, ...this.getMatch("/")})
|
||||
$history.push({path: "/"})
|
||||
}
|
||||
|
||||
globalHistory.navigate($history[0].path || "/")
|
||||
@ -362,7 +367,7 @@ export class Router {
|
||||
const path = first(historyItem.path.split("?"))
|
||||
const params = this.decodeQueryString(historyItem.path)
|
||||
|
||||
return this.at(path).qp(params).cg(historyItem.config)
|
||||
return this.at(path).qp(params).cg(historyItem)
|
||||
}
|
||||
|
||||
fromCurrent() {
|
||||
@ -415,11 +420,11 @@ export class Router {
|
||||
return data
|
||||
}
|
||||
|
||||
getKey = (item: HistoryItem) => item.config.key || item.path
|
||||
getKey = (item: HistoryItem) => item.key || item.path
|
||||
|
||||
getProps = (item: HistoryItem) => ({
|
||||
...this.decodeQueryString(item.path),
|
||||
...this.decodeRouteParams(item.path),
|
||||
...item.config.context,
|
||||
...item.context,
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user