mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-07 08:21:08 +00:00
255 lines
7.6 KiB
Svelte
255 lines
7.6 KiB
Svelte
<script lang="ts">
|
|
import platform, { addEventListener, getMetadata, OK, PlatformEvent, Status } from '@hcengineering/platform'
|
|
import { onDestroy } from 'svelte'
|
|
import type { AnyComponent } from '../../types'
|
|
// import { applicationShortcutKey } from '../../utils'
|
|
import { getCurrentLocation, location, navigate } from '../../location'
|
|
|
|
import { Theme, themeStore } from '@hcengineering/theme'
|
|
import Component from '../Component.svelte'
|
|
|
|
import StatusComponent from '../Status.svelte'
|
|
import Clock from './Clock.svelte'
|
|
// import Mute from './icons/Mute.svelte'
|
|
import { checkMobile, deviceOptionsStore as deviceInfo, networkStatus } from '../../'
|
|
import uiPlugin from '../../plugin'
|
|
import Label from '../Label.svelte'
|
|
import FontSizeSelector from './FontSizeSelector.svelte'
|
|
import Computer from './icons/Computer.svelte'
|
|
import Phone from './icons/Phone.svelte'
|
|
import WiFi from './icons/WiFi.svelte'
|
|
import LangSelector from './LangSelector.svelte'
|
|
import ThemeSelector from './ThemeSelector.svelte'
|
|
|
|
let application: AnyComponent | undefined
|
|
|
|
onDestroy(
|
|
location.subscribe((loc) => {
|
|
const routes = getMetadata(uiPlugin.metadata.Routes) ?? new Map()
|
|
const component = loc.path[0]
|
|
|
|
application = routes.get(component)
|
|
if (application === undefined && Array.from(routes.values()).includes(component as AnyComponent)) {
|
|
// if component id is used
|
|
application = component as AnyComponent
|
|
}
|
|
|
|
if (application === undefined) {
|
|
let last = loc.path[1] !== undefined ? localStorage.getItem(`platform_last_loc_${loc.path[1]}`) : null
|
|
if (last === null) {
|
|
last = localStorage.getItem('platform_last_loc')
|
|
}
|
|
let useDefault = true
|
|
if (last !== null) {
|
|
const storedLoc = JSON.parse(last)
|
|
const key = storedLoc.path?.[0]
|
|
if (Array.from(routes.values()).includes(key) || Array.from(routes.keys()).includes(key)) {
|
|
useDefault = false
|
|
navigate(storedLoc)
|
|
}
|
|
}
|
|
if (useDefault) {
|
|
application = getMetadata(uiPlugin.metadata.DefaultApplication)
|
|
if (application !== undefined) {
|
|
const loc = getCurrentLocation()
|
|
loc.path = [application]
|
|
navigate(loc)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
)
|
|
|
|
let status = OK
|
|
let maintenanceTime = -1
|
|
|
|
addEventListener(PlatformEvent, async (_event, _status: Status) => {
|
|
if (_status.code === platform.status.MaintenanceWarning) {
|
|
maintenanceTime = (_status.params as any).time
|
|
} else {
|
|
status = _status
|
|
}
|
|
})
|
|
|
|
let docWidth: number = window.innerWidth
|
|
let docHeight: number = window.innerHeight
|
|
|
|
let isMobile: boolean
|
|
let alwaysMobile: boolean = false
|
|
$: isMobile = alwaysMobile || checkMobile()
|
|
let isPortrait: boolean
|
|
$: isPortrait = docWidth <= docHeight
|
|
|
|
$: $deviceInfo.docWidth = docWidth
|
|
$: $deviceInfo.docHeight = docHeight
|
|
$: $deviceInfo.isPortrait = isPortrait
|
|
$: $deviceInfo.isMobile = isMobile
|
|
$: $deviceInfo.minWidth = docWidth <= 480
|
|
$: $deviceInfo.twoRows = docWidth <= 680
|
|
|
|
$: document.documentElement.style.setProperty('--app-height', `${docHeight}px`)
|
|
|
|
let doubleTouchStartTimestamp = 0
|
|
document.addEventListener('touchstart', (event) => {
|
|
const now = +new Date()
|
|
if (doubleTouchStartTimestamp + 500 > now) {
|
|
event.preventDefault()
|
|
}
|
|
doubleTouchStartTimestamp = now
|
|
})
|
|
document.addEventListener('dblclick', (event) => {
|
|
event.preventDefault()
|
|
})
|
|
</script>
|
|
|
|
<svelte:window bind:innerWidth={docWidth} bind:innerHeight={docHeight} />
|
|
|
|
<Theme>
|
|
<div id="ui-root">
|
|
<div class="antiStatusBar">
|
|
<div class="flex-row-center h-full content-color">
|
|
{$themeStore.language}
|
|
<div
|
|
class="status-info"
|
|
style:margin-left={(isPortrait && docWidth <= 480) || (!isPortrait && docHeight <= 480) ? '1.5rem' : '0'}
|
|
>
|
|
<div class="flex flex-row-center flex-center">
|
|
{#if maintenanceTime > 0}
|
|
<div class="flex-grow flex-center flex-row-center" class:maintenanceScheduled={maintenanceTime > 0}>
|
|
<Label label={platform.status.MaintenanceWarning} params={{ time: maintenanceTime }} />
|
|
</div>
|
|
{/if}
|
|
<StatusComponent {status} />
|
|
</div>
|
|
</div>
|
|
<div class="flex-row-reverse">
|
|
<div class="clock">
|
|
<Clock />
|
|
</div>
|
|
<div class="flex-center widget cursor-pointer">
|
|
<LangSelector />
|
|
</div>
|
|
<div class="flex-center widget cursor-pointer">
|
|
<ThemeSelector />
|
|
</div>
|
|
<div class="flex-center widget cursor-pointer">
|
|
<FontSizeSelector />
|
|
</div>
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
<div
|
|
class="flex-center widget"
|
|
class:rotated={!isPortrait && isMobile}
|
|
on:click={() => {
|
|
alwaysMobile = !alwaysMobile
|
|
document.documentElement.style.setProperty('--app-height', `${window.innerHeight}px`)
|
|
}}
|
|
>
|
|
<svelte:component
|
|
this={isMobile ? Phone : Computer}
|
|
fill={alwaysMobile ? 'var(--theme-won-color)' : 'var(--content-color)'}
|
|
size={'small'}
|
|
/>
|
|
</div>
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
<div
|
|
class="flex-center widget cursor-pointer"
|
|
on:click={(evt) => {
|
|
getMetadata(uiPlugin.metadata.ShowNetwork)?.(evt)
|
|
}}
|
|
>
|
|
<WiFi
|
|
size={'small'}
|
|
fill={$networkStatus === -1
|
|
? 'var(--theme-error-color)'
|
|
: $networkStatus % 2 === 1
|
|
? 'var(--theme-warning-color)'
|
|
: 'currentColor'}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="app">
|
|
{#if application}
|
|
<Component is={application} props={{}} />
|
|
{:else}
|
|
<div class="error">
|
|
Application not found: {application}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</Theme>
|
|
|
|
<style lang="scss">
|
|
* {
|
|
--status-bar-height: 32px;
|
|
}
|
|
|
|
#ui-root {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
// height: 100vh;
|
|
height: 100%;
|
|
// height: var(--app-height);
|
|
|
|
.antiStatusBar {
|
|
-webkit-app-region: drag;
|
|
min-height: var(--status-bar-height);
|
|
height: var(--status-bar-height);
|
|
// min-width: 600px;
|
|
font-size: 12px;
|
|
line-height: 150%;
|
|
background-color: var(--theme-statusbar-color);
|
|
|
|
.maintenanceScheduled {
|
|
padding: 0 0.5rem;
|
|
width: fit-content;
|
|
height: 1.25rem;
|
|
max-width: 22rem;
|
|
color: var(--tooltip-bg-color);
|
|
background-color: var(--highlight-red);
|
|
border-radius: 0.625rem;
|
|
}
|
|
|
|
.status-info {
|
|
flex-grow: 1;
|
|
text-align: center;
|
|
}
|
|
.clock {
|
|
margin: 0 16px 0 24px;
|
|
font-weight: 500;
|
|
user-select: none;
|
|
}
|
|
.widget {
|
|
-webkit-app-region: no-drag;
|
|
width: 16px;
|
|
height: 16px;
|
|
font-size: 14px;
|
|
color: var(--content-color);
|
|
transition: transform 0.15s ease-in-out;
|
|
|
|
&.rotated {
|
|
transform-origin: center center;
|
|
transform: rotate(90deg);
|
|
}
|
|
}
|
|
.widget + .widget {
|
|
margin-right: 12px;
|
|
}
|
|
}
|
|
|
|
.app {
|
|
height: calc(100% - var(--status-bar-height));
|
|
// min-width: 600px;
|
|
// min-height: 480px;
|
|
|
|
.error {
|
|
margin-top: 45vh;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
</style>
|