contact messages: centered panel on paskia's shared blur backdrop
The panel was a right-docked sidebar with its own translucent backdrop. It is main content: now centered at the paskia dialog's dimensions (min(36rem,100%) x min(42rem,92vh)), full-screen below 36rem, holding the refcounted global blur backdrop (z 1099) while open with the panel's click-catch overlay at 1100 (below the auth iframe at 9999). Escape closes too.
This commit is contained in:
1 parent
f3c288c76c
commit
9a2435f03a
2 files changed
+45
-13
No files matched your search
@@ -3,7 +3,7 @@
|
||||
// socket (via the bridge pagerite.js hands to contact-main), with the
|
||||
// composer shared with the admin inbox. state is contact-main's reactive
|
||||
// store ({open, thread, unread}).
|
||||
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
||||
import { formatWhen } from './analytics/format.js'
|
||||
import Composer from './Composer.vue'
|
||||
|
||||
@@ -26,6 +26,13 @@ watch(() => props.state.open, (open) => { if (open) scrollDown() })
|
||||
// Relative timestamps like in analytics.
|
||||
const fmtTime = (t) => formatWhen(t)
|
||||
|
||||
// Escape closes, like the paskia dialogs whose backdrop we share.
|
||||
function onKey(ev) {
|
||||
if (ev.key === 'Escape' && props.state.open) emit('close')
|
||||
}
|
||||
onMounted(() => addEventListener('keydown', onKey))
|
||||
onUnmounted(() => removeEventListener('keydown', onKey))
|
||||
|
||||
const NAME_KEY = 'pagerite-contact-name'
|
||||
const EMAIL_KEY = 'pagerite-contact-email'
|
||||
|
||||
@@ -53,7 +60,7 @@ function onSend(md) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="state.open" class="contact-backdrop" @click.self="emit('close')">
|
||||
<div v-if="state.open" class="contact-overlay" @click.self="emit('close')">
|
||||
<section class="contact-panel" role="dialog" aria-label="Contact us">
|
||||
<header>
|
||||
<h2>Contact us</h2>
|
||||
@@ -89,27 +96,43 @@ function onSend(md) {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.contact-backdrop {
|
||||
.contact-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 30;
|
||||
background: rgb(0 0 0 / 0.25);
|
||||
/* Above paskia's shared blur backdrop (1099, held by contact-main while
|
||||
open), below the authentication iframe (9999). Transparent: the blur
|
||||
is the backdrop's job, this layer only centers the panel and catches
|
||||
outside clicks (the backdrop itself is pointer-events: none). */
|
||||
z-index: 1100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.contact-panel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(26rem, 94vw);
|
||||
/* Same dimensions as paskia's own dialog. */
|
||||
width: min(36rem, 100%);
|
||||
height: min(42rem, 92vh);
|
||||
padding: 0.8rem;
|
||||
gap: 0.6rem;
|
||||
background: var(--bg, Canvas);
|
||||
color: var(--text, CanvasText);
|
||||
border-left: 1px solid var(--line);
|
||||
box-shadow: -0.5rem 0 2rem rgb(0 0 0 / 0.2);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0.5rem 2rem rgb(0 0 0 / 0.3);
|
||||
}
|
||||
|
||||
/* Mobile: full screen. */
|
||||
@media (max-width: 36rem) {
|
||||
.contact-panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-panel header {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
// socket through the bridge pagerite.js hands over ({send, register}) —
|
||||
// no extra connection is opened. The session token is a localStorage
|
||||
// random; the server stores only its hash.
|
||||
import { createApp, reactive } from 'vue'
|
||||
import { createApp, reactive, watch } from 'vue'
|
||||
import { holdGlobalBackdrop, releaseGlobalBackdrop } from 'paskia'
|
||||
import ContactPanel from './ContactPanel.vue'
|
||||
|
||||
const TOKEN_KEY = 'pagerite-contact-token'
|
||||
@@ -12,6 +13,14 @@ const SEEN_KEY = 'pagerite-contact-seen'
|
||||
let app = null
|
||||
const state = reactive({ open: false, thread: null, unread: false })
|
||||
|
||||
// The panel is main content, not a sidebar: while open it holds paskia's
|
||||
// shared blur backdrop (refcounted, z-index 1099; the panel itself sits at
|
||||
// 1100, below the auth iframe's 9999).
|
||||
watch(() => state.open, (open) => {
|
||||
if (open) holdGlobalBackdrop()
|
||||
else releaseGlobalBackdrop()
|
||||
})
|
||||
|
||||
function ensureToken() {
|
||||
let token = localStorage.getItem(TOKEN_KEY)
|
||||
if (!token) {
|
||||
|
||||
Reference in new issue
Block a user