UBER-1127: updated status bar layout (#3940)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-11-06 13:11:30 +03:00 committed by GitHub
parent 429574ce1d
commit cbd7e82e8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 785 additions and 216 deletions

View File

@ -15,28 +15,36 @@
<script lang="ts">
import platform, { loadPluginStrings, setMetadata } from '@hcengineering/platform'
import { onMount, setContext } from 'svelte'
import { ThemeOptions, getCurrentFontSize, getCurrentLanguage, getCurrentTheme, themeStore as themeOptions } from './'
import {
ThemeOptions,
getCurrentFontSize,
getCurrentLanguage,
getCurrentTheme,
isThemeDark,
themeStore as themeOptions
} from './'
const currentTheme = getCurrentTheme()
const currentFontSize = getCurrentFontSize()
let currentLanguage = getCurrentLanguage()
const setOptions = (currentFont: string, theme: string, language: string) => {
themeOptions.set(new ThemeOptions(currentFont === 'normal-font' ? 16 : 14, theme === 'theme-dark', language))
themeOptions.set(new ThemeOptions(currentFont === 'normal-font' ? 16 : 14, isThemeDark(theme), language))
}
const getRealTheme = (theme: string): string => (isThemeDark(theme) ? 'theme-dark' : 'theme-light')
const setRootColors = (theme: string, set = true) => {
if (set) {
localStorage.setItem('theme', theme)
}
document.documentElement.setAttribute('class', `${theme} ${getCurrentFontSize()}`)
document.documentElement.setAttribute('class', `${getRealTheme(theme)} ${getCurrentFontSize()}`)
setOptions(getCurrentFontSize(), theme, getCurrentLanguage())
}
const setRootFontSize = (fontsize: string, set = true) => {
if (set) {
localStorage.setItem('fontsize', fontsize)
}
document.documentElement.setAttribute('class', `${getCurrentTheme()} ${fontsize}`)
document.documentElement.setAttribute('class', `${getRealTheme(getCurrentTheme())} ${fontsize}`)
setOptions(fontsize, getCurrentTheme(), getCurrentLanguage())
}
const setLanguage = async (language: string, set: boolean = true) => {

View File

@ -27,26 +27,33 @@ export const setDefaultLanguage = (language: string): void => {
}
}
function isSystemThemeDark (): boolean {
return window.matchMedia('(prefers-color-scheme: dark)').matches
}
function getDefaultTheme (): string {
return isSystemThemeDark() ? 'theme-dark' : 'theme-light'
function getDefaultProps (prop: string, value: string): string {
localStorage.setItem(prop, value)
return value
}
/**
* @public
*/
export const getCurrentTheme = (): string => localStorage.getItem('theme') ?? getDefaultTheme()
export const isSystemThemeDark = (): boolean => window.matchMedia('(prefers-color-scheme: dark)').matches
/**
* @public
*/
export const getCurrentFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
export const isThemeDark = (theme: string): boolean =>
theme === 'theme-dark' || (theme === 'theme-system' && isSystemThemeDark())
/**
* @public
*/
export const getCurrentLanguage = (): string => localStorage.getItem('lang') ?? 'en'
export const getCurrentTheme = (): string => localStorage.getItem('theme') ?? getDefaultProps('theme', 'theme-system')
/**
* @public
*/
export const getCurrentFontSize = (): string =>
localStorage.getItem('fontsize') ?? getDefaultProps('fontsize', 'normal-font')
/**
* @public
*/
export const getCurrentLanguage = (): string => localStorage.getItem('lang') ?? getDefaultProps('lang', 'en')
export class ThemeOptions {
constructor (readonly fontSize: number, readonly dark: boolean, readonly language: string) {}
@ -54,7 +61,7 @@ export class ThemeOptions {
export const themeStore = writable<ThemeOptions>(
new ThemeOptions(
getCurrentFontSize() === 'normal-font' ? 16 : 14,
getCurrentTheme() === 'theme-dark',
isThemeDark(getCurrentTheme()),
getCurrentLanguage()
)
)

View File

@ -76,6 +76,8 @@
--text-editor-highlighted-node-delete-background-color: #F6DCDA;
--text-editor-highlighted-node-delete-font-color: #54201C;
--theme-clockface-sec-arrow: conic-gradient(at 50% -10px, rgba(255, 0, 0, 0), rgba(255, 0, 0, 0) 49%, #F47758 50%, rgba(255, 0, 0, 0) 51%, rgba(255, 0, 0, 0) 100%);
--theme-clockface-sec-holder: #F47758;
}
/* Dark Theme */
@ -117,7 +119,7 @@
--theme-bg-dark-color: rgba(0, 0, 0, .2);
--theme-back-color: #0f0f18;
--theme-overlay-color: rgba(0, 0, 0, .3);
--theme-statusbar-color: #2C2C35;
--theme-statusbar-color: #1A1928;
--theme-navpanel-color: #14141F;
--theme-navpanel-hovered: rgba(255, 255, 255, .04);
--theme-navpanel-selected: rgba(255, 255, 255, .08);
@ -173,6 +175,7 @@
--theme-popup-divider: rgba(255, 255, 255, .09);
--theme-popup-header: #3A3A47;
--theme-popup-shadow: 0 0 .5rem rgba(0, 0, 0, .2);
--theme-popup-checkicon: #FFFFFF99;
--theme-panel-color: #1A1A28;
--theme-calendar-today-color: #fff;
--theme-calendar-holiday-color: #eb5757;
@ -285,6 +288,14 @@
--text-editor-toc-default-color: rgba(255, 255, 255, 0.1);
--text-editor-toc-hovered-color: rgba(255, 255, 255, 0.4);
--theme-clockface-back: radial-gradient(farthest-corner at 50% 0%, #bbb, #fff 100%);
--theme-clockface-shadow: inset 0 -3px 10px #aaa;
--theme-clockface-hours: #666;
--theme-clockface-quarter: #31302e;
--theme-clockface-min-arrow: conic-gradient(at 50% -10px, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 49%, #2F2F3A 50%, rgba(0, 0, 0, 0) 51%, rgba(0, 0, 0, 0) 100%);
--theme-clockface-arrows-holder: radial-gradient(at top center, #2F2F3A, #555555);
--theme-clockface-arrows-shadow: 0 0 1px white;
}
/* Light Theme */
@ -326,7 +337,7 @@
--theme-bg-dark-color: rgba(255, 255, 255, .8);
--theme-back-color: #D9D9DD;
--theme-overlay-color: rgba(0, 0, 0, .2);
--theme-statusbar-color: #bfbfc6;
--theme-statusbar-color: #FFF;
--theme-navpanel-color: #FBFBFC;
--theme-navpanel-hovered: rgba(0, 0, 0, .04);
--theme-navpanel-selected: rgba(0, 0, 0, .08);
@ -382,6 +393,7 @@
--theme-popup-divider: rgba(0, 0, 0, .09);
--theme-popup-header: #EBEBEB;
--theme-popup-shadow: 0 0 .5rem rgba(0, 0, 0, .2);
--theme-popup-checkicon: #205DC2;
--theme-panel-color: #FFFFFF;
--theme-calendar-today-color: #000;
--theme-calendar-holiday-color: #eb5757;
@ -494,4 +506,12 @@
--text-editor-toc-default-color: rgba(0, 0, 0, 0.1);
--text-editor-toc-hovered-color: rgba(0, 0, 0, 0.4);
--theme-clockface-back: radial-gradient(farthest-corner at 50% 0%, #606060, #000 100%);
--theme-clockface-shadow: inset 0 -3px 10px #000;
--theme-clockface-hours: #999;
--theme-clockface-quarter: #CECFD1;
--theme-clockface-min-arrow: conic-gradient(at 50% -10px, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 49%, white 50%, rgba(255, 255, 255, 0) 51%, rgba(255, 255, 255, 0) 100%);
--theme-clockface-arrows-holder: radial-gradient(at top center, #eee, #aaa);
--theme-clockface-arrows-shadow: 0 0 1px black;
}

View File

@ -444,6 +444,7 @@ input.search {
.gapV-12 > *:not(:last-child) { margin-bottom: 3rem; }
.gap-around-2 > * { margin: .25rem; }
.gap-around-4 > * { margin: .5rem; }
.gap-statusbar > *:not(:last-child) { margin-right: 12px; }
/* --------- */
.sm-tool-icon {
@ -686,6 +687,7 @@ input.search {
.min-w-8 { min-width: 2rem; }
.min-w-9 { min-width: 2.25rem; }
.min-w-12 { min-width: 3rem; }
.min-w-50 { min-width: 12.5rem; }
.min-w-60 { min-width: 15rem; }
.min-w-80 { min-width: 20rem; }
.min-w-100 { min-width: 25rem; }
@ -818,6 +820,7 @@ a.no-line {
color: var(--theme-dark-color);
user-select: none;
}
.text-16px { font-size: 16px; }
.text-xs { font-size: .625rem; }
.text-11px { font-size: .6875rem; }
.text-sm { font-size: .75rem; }
@ -837,7 +840,9 @@ a.no-line {
.lower { text-transform: lowercase; }
.text-left { text-align: left; }
.text-center { text-align: center; }
.leading-16px { line-height: 16px; }
.leading-3 { line-height: .75rem; }
.tracking--05px { letter-spacing: -.5px; }
.tracking-1px { letter-spacing: 1px; }
.over-underline {

View File

@ -60,6 +60,7 @@
&.short { max-width: 8.5rem; }
&.accent { font-weight: 500; }
&.sh-no-shape { border-radius: .375rem; }
&.sh-round-small { border-radius: .25rem; }
&.sh-round { border-radius: .5rem; }
&.sh-round2 { border-radius: .75rem; }
&.sh-circle { border-radius: 1rem; }
@ -86,6 +87,7 @@
&.bs-solid { border-style: solid; }
&.bs-dashed { border-style: dashed; }
&.bs-none { border: none; }
&.jf-left { justify-content: flex-start; }
&.jf-center { justify-content: center; }
&.only-icon {
@ -99,7 +101,9 @@
border-color: var(--theme-button-border);
&:hover { background-color: var(--theme-button-hovered); }
&:active { background-color: var(--theme-button-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--theme-button-pressed); }
&:focus {
background-color: var(--theme-button-focused);
border-color: var(--theme-button-focused-border);
@ -137,7 +141,9 @@
}
&.ghost, &.stepper {
&:hover { background-color: var(--theme-button-hovered); }
&:active { background-color: var(--theme-button-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--theme-button-pressed); }
&.selected { background-color: var(--highlight-select); }
&.selected:hover { background-color: var(--highlight-select-hover); }
}
@ -200,7 +206,7 @@
}
}
&.regular, &.ghost {
&:hover, &:active, &:focus { color: var(--theme-caption-color); }
&:hover, &:active, &.pressed, &.pressed:hover, &:focus { color: var(--theme-caption-color); }
}
&.primary,
&.secondary,
@ -218,7 +224,9 @@
background-color: var(--primary-button-default);
&:hover { background-color: var(--primary-button-hovered); }
&:active { background-color: var(--primary-button-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--primary-button-pressed); }
&:focus { background-color: var(--primary-button-focused); }
&:disabled {
color: var(--primary-button-disabled-color);
@ -231,7 +239,9 @@
&.secondary {
background-color: var(--secondary-button-default);
&:hover { background-color: var(--secondary-button-hovered); }
&:active { background-color: var(--secondary-button-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--secondary-button-pressed); }
&:focus { background-color: var(--secondary-button-focused); }
&:disabled {
color: var(--secondary-button-disabled-color);
@ -241,7 +251,9 @@
&.positive {
background-color: var(--positive-button-default);
&:hover { background-color: var(--positive-button-hovered); }
&:active { background-color: var(--positive-button-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--positive-button-pressed); }
&:focus { background-color: var(--positive-button-focused); }
&:disabled {
color: var(--positive-button-disabled-color);
@ -251,7 +263,9 @@
&.negative {
background-color: var(--negative-button-default);
&:hover { background-color: var(--negative-button-hovered); }
&:active { background-color: var(--negative-button-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--negative-button-pressed); }
&:focus { background-color: var(--negative-button-focused); }
&:disabled {
color: var(--negative-button-disabled-color);
@ -269,7 +283,9 @@
.btn-right-icon { color: var(--theme-button-contrast-color); }
&:hover { background-color: var(--theme-button-contrast-hovered); }
&:active { background-color: var(--theme-button-contrast-pressed); }
&:active,
&.pressed,
&.pressed:hover { background-color: var(--theme-button-contrast-pressed); }
&:focus { background-color: var(--theme-button-contrast-hovered); }
&:disabled {
color: var(--theme-button-contrast-disabled-color);
@ -311,5 +327,20 @@
.btn-right-icon { opacity: .5; }
}
.resetIconSize { font-size: 16px; }
}
.resetIconSize,
&.resetIconSize { font-size: 16px !important; }
&.statusButton {
padding: 0 8px;
height: 20px;
min-width: 20px;
font-size: 13px;
border-radius: 4px;
&.square {
flex-shrink: 0;
padding: 2px;
width: 20px;
}
}
}

View File

@ -271,6 +271,31 @@
padding: .5rem 0 1.25rem;
}
/* Statusbar - Popup */
.statusPopup-option {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
min-height: 0;
&:not(:last-child) { margin-right: 12px; }
.label {
margin-top: .5rem;
font-weight: 500;
font-size: 12px;
color: var(--theme-darker-color);
}
&:hover .label { color: var(--theme-dark-color); }
&.selected .label {
font-weight: 600;
color: var(--theme-content-color);
}
&:not(.selected) { cursor: pointer; }
}
/* Basic */
.antiGrid {
display: flex;

View File

@ -71,12 +71,14 @@
scrollbar-color: var(--theme-comp-header-color) var(--theme-back-color);
scrollbar-width: none;
--body-font-size: .875rem;
--status-bar-height: 36px;
--panel-aside-width: 25rem; // 20rem;
--font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
--mono-font: 'IBM Plex Mono', monospace;
--timing-shadow: cubic-bezier(0,.65,.35,1);
--timing-main: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--timing-rotate: cubic-bezier(.28,1.92,.39,.56);
--timing-clock: cubic-bezier(.35,2.1,.79,.71);
// transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
&::after,

View File

@ -358,7 +358,7 @@
&.halfMargin { margin: .25rem 0; }
}
}
&:not(.thinStyle) .ap-menuItem:not(.separator, .withComp) { padding: .25rem .5rem; }
&:not(.thinStyle) .ap-menuItem:not(.separator, .withComp) { padding: .625rem .5rem; }
&.thinStyle {
border-radius: .75rem;
@ -378,7 +378,7 @@
margin-left: 1rem;
width: 1rem;
height: 1rem;
color: var(--theme-dark-color);
color: var(--theme-popup-checkicon);
}
.ap-subheader {
flex-shrink: 0;

View File

@ -61,6 +61,11 @@
"TravelAndPlaces": "Travel & Places",
"Objects": "Objects",
"Food": "Food",
"MoreCount": "{count} more"
"MoreCount": "{count} more",
"Spacious": "Spacious",
"Compact": "Compact",
"ThemeLight": "Light",
"ThemeDark": "Dark",
"ThemeSystem": "System"
}
}

View File

@ -61,6 +61,11 @@
"TravelAndPlaces": "Путешествия & Места",
"Objects": "Объекты",
"Food": "Еда",
"MoreCount": "Ещё {count}"
"MoreCount": "Ещё {count}",
"Spacious": "Просторный",
"Compact": "Компактный",
"ThemeLight": "Светлая",
"ThemeDark": "Тёмная",
"ThemeSystem": "Системная"
}
}

View File

@ -46,14 +46,15 @@
export let loading: boolean = false
export let width: string | undefined = undefined
export let height: string | undefined = undefined
export let resetIconSize: boolean = false
export let resetIconSize: 'none' | 'icon' | 'full' = 'none'
export let highlight: boolean = false
export let pressed: boolean = false
export let selected: boolean = false
export let notSelected: boolean = false
export let focus: boolean = false
export let click: boolean = false
export let title: string | undefined = undefined
export let borderStyle: 'solid' | 'dashed' = 'solid'
export let borderStyle: 'solid' | 'dashed' | 'none' = 'solid'
export let id: string | undefined = undefined
export let input: HTMLButtonElement | undefined = undefined
export let showTooltip: LabelAndProps | undefined = undefined
@ -121,12 +122,14 @@
class:no-focus={noFocus}
class:accent
class:highlight
class:pressed
class:selected
class:notSelected
class:iconL={(icon || $$slots.icon) && (label || $$slots.content)}
class:iconR={(iconRight || $$slots.iconRight) && (label || $$slots.content)}
disabled={disabled || loading}
class:short
class:resetIconSize={resetIconSize === 'full'}
style:width
style:height
style:flex-shrink={shrink}
@ -141,14 +144,14 @@
{id}
>
{#if icon && !loading}
<div class="btn-icon pointer-events-none" class:resetIconSize>
<div class="btn-icon pointer-events-none" class:resetIconSize={resetIconSize === 'icon'}>
<Icon bind:icon size={iconSize} {iconProps} />
</div>
{/if}
{#if loading}
<div
class="btn-icon pointer-events-none spinner"
class:resetIconSize
class:resetIconSize={resetIconSize === 'icon'}
style:color={primary ? 'var(--primary-button-color)' : 'var(--theme-caption-color)'}
>
<Spinner size={iconSize === 'inline' ? 'inline' : 'small'} />
@ -160,7 +163,7 @@
</span>
{/if}
{#if iconRight}
<div class="btn-right-icon pointer-events-none" class:resetIconSize>
<div class="btn-right-icon pointer-events-none" class:resetIconSize={resetIconSize === 'icon'}>
<Icon bind:icon={iconRight} size={iconRightSize} iconProps={iconRightProps} />
</div>
{/if}

View File

@ -126,3 +126,7 @@ export const getDueDateIconModifier = (
export function getFormattedDate (value: number | null): string {
return value === null ? '' : new Date(value).toLocaleString('default', { month: 'short', day: 'numeric' })
}
export const getTimeZoneName = (): string => {
return Intl.DateTimeFormat().resolvedOptions().timeZone.split('/')[1]
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
export let fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 16 16" {fill} xmlns="http://www.w3.org/2000/svg">

View File

@ -1,9 +1,12 @@
<script lang="ts">
import { onDestroy } from 'svelte'
import { showPopup, getTimeZoneName } from '../..'
import ClockPopup from './ClockPopup.svelte'
let hours = ''
let minutes = ''
let delimiter = false
let delimiter: boolean = false
let pressed: boolean = false
function updateTime () {
const date = new Date()
@ -20,8 +23,18 @@
onDestroy(() => clearInterval(interval))
</script>
<div style="min-width: 40px">
<button
class="antiButton ghost jf-center bs-none no-focus statusButton"
class:pressed
on:click={(ev) => {
pressed = true
showPopup(ClockPopup, {}, 'status', () => {
pressed = false
})
}}
>
<span>{getTimeZoneName()}</span>&nbsp;&nbsp;
<span>{hours}</span>
<span style="visibility: {delimiter ? 'visible' : 'hidden'}">:</span>
<span style:visibility={delimiter ? 'visible' : 'hidden'}>:</span>
<span>{minutes}</span>
</div>
</button>

View File

@ -0,0 +1,140 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { onDestroy } from 'svelte'
const clock: Array<{ value: number; class: string }> = [
{ value: 0, class: 'hour-arrow' },
{ value: 0, class: 'minute-arrow' },
{ value: 0, class: 'second-arrow' }
]
let reqId: any
const updateTime = (): void => {
const now = new Date()
const startDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0).getTime()
const diff = now.getTime() - startDay
let h = diff / 3600000
if (h > 12) h -= 12
const m = (diff / 1000 / 60) % 60
const s = (diff / 1000) % 60
clock[0].value = h * 30
clock[1].value = m * 6
clock[2].value = s * 6
setTimeout(() => (reqId = requestAnimationFrame(updateTime)), 1000 / 25)
}
reqId = requestAnimationFrame(updateTime)
onDestroy(() => clearInterval(reqId))
</script>
<div class="clockFace-container">
{#each [...Array(12).keys()] as hour}
<div class="hour" data-hour={hour === 0 ? '12' : `${hour}`} />
{/each}
{#each clock as arrow}
<div class={arrow.class} style:transform={`rotate(${arrow.value}deg)`} />
{/each}
</div>
<style lang="scss">
.hour {
position: absolute;
top: 1px;
left: 50%;
width: 1px;
height: 2px;
background: var(--theme-clockface-hours);
transform-origin: 50% 29px;
transform: rotate(0deg);
@for $i from 2 through 12 {
&:nth-child(#{$i}) {
transform: rotate(#{$i * 30 - 30}deg);
}
}
&:nth-child(3n + 1) {
height: 5px;
background: var(--theme-clockface-quarter);
}
}
.clockFace-container {
position: relative;
flex-shrink: 0;
width: 60px;
height: 60px;
background: var(--theme-clockface-back);
border-radius: 50%;
box-shadow: var(--theme-clockface-shadow);
.second-arrow,
.minute-arrow,
.hour-arrow {
position: absolute;
left: calc(50% - 0.5px);
box-shadow: va(--theme-clockface-arrows-shadow);
transform: rotate(0deg);
}
.anim {
transition-property: transform;
transition-timing-function: var(--timing-clock);
transition-duration: 0.25s;
}
.second-arrow {
top: 2px;
width: 2px;
height: 34px;
background: var(--theme-clockface-sec-arrow);
transform-origin: 50% 28px;
&::before,
&::after {
content: '';
position: absolute;
left: 50%;
border-radius: 50%;
transform: translateX(-50%);
}
&::before {
top: 25px;
width: 6px;
height: 6px;
background-color: var(--theme-clockface-sec-holder);
}
&::after {
top: 26px;
width: 4px;
height: 4px;
background: var(--theme-clockface-arrows-holder);
}
}
.minute-arrow {
top: 4px;
width: 2px;
height: 32px;
background: var(--theme-clockface-min-arrow);
transform-origin: 50% 26px;
}
.hour-arrow {
top: 12px;
left: calc(50% - 1px);
width: 3px;
height: 24px;
background: var(--theme-clockface-min-arrow);
transform-origin: 50% 18px;
}
}
</style>

View File

@ -0,0 +1,27 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { getTimeZoneName } from '../..'
import ClockFace from './ClockFace.svelte'
</script>
<div class="antiPopup" style:flex-direction={'row'} style:padding={'12px'}>
<div class="statusPopup-option">
<ClockFace />
<span class="label overflow-label">
{getTimeZoneName()}
</span>
</div>
</div>

View File

@ -0,0 +1,55 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { onMount } from 'svelte'
import FontSize from './icons/FontSize.svelte'
export let size: string
export let focused: string
let btn: HTMLButtonElement
onMount(() => {
if (focused === size) btn.focus()
})
</script>
<button
bind:this={btn}
class="antiButton regular sh-no-shape jf-center bs-solid no-focus statusPopupButton"
class:focused={focused === size}
>
<FontSize size={size === 'small-font' ? '20px' : '28px'} />
</button>
<style lang="scss">
.statusPopupButton {
position: relative;
flex-shrink: 0;
width: 52px;
height: 52px;
border-radius: 6px;
&.focused::before,
&:focus::before {
position: absolute;
content: '';
inset: -3px;
border: 1px solid var(--primary-button-default);
border-radius: 8.5px;
cursor: default;
}
}
</style>

View File

@ -0,0 +1,43 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import type { IntlString } from '@hcengineering/platform'
import FontSizeButton from './FontSizeButton.svelte'
import { Label, deviceOptionsStore as deviceInfo } from '../..'
export let fontsizes: Array<{ id: string; label: IntlString; size: number }>
export let selected: string = ''
const dispatch = createEventDispatcher()
const select = (size: string): void => {
if (selected === size) return
selected = size
dispatch('close', size)
}
</script>
<div class="antiPopup" style:flex-direction={'row'} style:padding={'12px'}>
{#each fontsizes as font}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="statusPopup-option" class:selected={selected === font.id} on:click={() => select(font.id)}>
<FontSizeButton size={font.id} focused={selected} />
<span class="label overflow-label" class:tracking--05px={$deviceInfo.language === 'ru'}>
<Label label={font.label} />
</span>
</div>
{/each}
</div>

View File

@ -14,28 +14,45 @@
-->
<script lang="ts">
import { getContext } from 'svelte'
import { IntlString } from '@hcengineering/platform'
import ui, { popupstore, showPopup, deviceOptionsStore as deviceInfo } from '../..'
import FontSize from './icons/FontSize.svelte'
import { popupstore } from '../../popups'
import { deviceOptionsStore as deviceInfo } from '../..'
import FontSizePopup from './FontSizePopup.svelte'
const { currentFontSize, setFontSize } = getContext('fontsize') as {
currentFontSize: string
setFontSize: (size: string) => void
}
const fontsizes = ['small-font', 'normal-font']
const fontsizes: Array<{ id: string; label: IntlString; size: number }> = [
{ id: 'normal-font', label: ui.string.Spacious, size: 16 },
{ id: 'small-font', label: ui.string.Compact, size: 14 }
]
let pressed: boolean = false
let btn: HTMLButtonElement
let current = fontsizes.indexOf(currentFontSize)
let current = fontsizes.findIndex((fs) => fs.id === currentFontSize)
function changeFontSize () {
current++
setFontSize(fontsizes[current % fontsizes.length])
$popupstore = $popupstore
function changeFontSize (ev: MouseEvent) {
pressed = true
showPopup(FontSizePopup, { fontsizes, selected: fontsizes[current].id }, btn, (result) => {
if (result) {
setFontSize(result)
current = fontsizes.findIndex((fs) => fs.id === result)
$popupstore = $popupstore
}
pressed = false
})
}
$: $deviceInfo.fontSize = fontsizes[current % fontsizes.length] === 'normal-font' ? 16 : 14
$: $deviceInfo.fontSize = fontsizes[current].size
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-center" on:click={changeFontSize}>
<button
bind:this={btn}
class="antiButton ghost jf-center bs-none no-focus resetIconSize statusButton square"
class:pressed
style:color={'var(--theme-dark-color)'}
on:click={changeFontSize}
>
<FontSize />
</div>
</button>

View File

@ -15,26 +15,31 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import Label from '../Label.svelte'
import IconCheck from '../icons/Check.svelte'
export let langs: any
export let selected: string
const dispatch = createEventDispatcher()
</script>
<div class="antiPopup">
<div class="antiPopup" style:min-width={'200px'}>
<div class="ap-space x2" />
{#each langs as lang}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="ap-menuItem hoverable flex-row-center"
class="ap-menuItem hoverable flex-row-center leading-16px"
on:click={() => {
dispatch('close', lang.id)
}}
>
<svg class="svg-small">
<use href="#{lang.id}-flag" />
</svg>
<div class="ml-2"><Label label={lang.label} /></div>
<div class="svg-16px flex-no-shrink text-16px mr-2">{@html lang.logo}</div>
<span class="overflow-label flex-grow"><Label label={lang.label} /></span>
<div class="ap-check">
{#if lang.id === selected}
<IconCheck size={'small'} fill={'var(--primary-button-default)'} />
{/if}
</div>
</div>
{/each}
<div class="ap-space x2" />

View File

@ -17,9 +17,9 @@
import { getMetadata } from '@hcengineering/platform'
import { showPopup } from '../..'
import LangPopup from './LangPopup.svelte'
import ui from '../../plugin'
import ui, { deviceOptionsStore as deviceInfo } from '../..'
import Flags from './icons/Flags.svelte'
let pressed: boolean = false
const { currentLanguage, setLanguage } = getContext('lang') as {
currentLanguage: string
@ -27,8 +27,8 @@
}
const uiLangs = new Set(getMetadata(ui.metadata.Languages))
const langs = [
{ id: 'en', label: ui.string.English },
{ id: 'ru', label: ui.string.Russian }
{ id: 'en', label: ui.string.English, logo: '&#x1F1FA;&#x1F1F8;' },
{ id: 'ru', label: ui.string.Russian, logo: '&#x1F1F7;&#x1F1FA;' }
].filter((lang) => uiLangs.has(lang.id))
if (langs.findIndex((l) => l.id === currentLanguage) < 0 && langs.length !== 0) {
@ -46,28 +46,28 @@
const isSelectable = langs.length > 1
$: selected = langs.find((item) => item.id === currentLanguage)
let trigger: HTMLElement
const selectLanguage = (): void => {
if (!isSelectable) {
return
}
pressed = true
showPopup(LangPopup, { langs }, trigger, (result) => {
showPopup(LangPopup, { langs, selected: selected?.id }, 'status', (result) => {
if (result) {
selected = langs.find((item) => item.id === result)
setLanguage(result)
}
pressed = false
})
}
$: $deviceInfo.language = selected?.id
</script>
<Flags />
{#if selected}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div bind:this={trigger} class="flex-center {isSelectable ? 'cursor-pointer' : ''}" on:click={selectLanguage}>
<svg class="svg-16px">
<use href="#{selected.id}-flag" />
</svg>
</div>
{/if}
<button
class="antiButton ghost jf-center bs-none no-focus resetIconSize statusButton square"
class:pressed
on:click={selectLanguage}
>
{@html selected?.logo}
</button>

View File

@ -12,13 +12,17 @@
import StatusComponent from '../Status.svelte'
import Clock from './Clock.svelte'
// import Mute from './icons/Mute.svelte'
import { checkMobile, deviceOptionsStore as deviceInfo, networkStatus } from '../../'
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 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'
@ -76,7 +80,7 @@
let docHeight: number = window.innerHeight
let isMobile: boolean
let alwaysMobile: boolean = false
const alwaysMobile: boolean = false
$: isMobile = alwaysMobile || checkMobile()
let isPortrait: boolean
$: isPortrait = docWidth <= docHeight
@ -159,17 +163,12 @@
<div class="clock">
<Clock />
</div>
<div class="flex-center widget">
<div class="flex-row-center gap-statusbar">
<FontSizeSelector />
<ThemeSelector />
<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
<!-- <div
class="flex-center widget"
class:rotated={!isPortrait && isMobile}
on:click={() => {
@ -183,7 +182,6 @@
size={'small'}
/>
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="flex-center widget cursor-pointer"
on:click={(evt) => {
@ -198,7 +196,7 @@
? 'var(--theme-warning-color)'
: 'currentColor'}
/>
</div>
</div> -->
</div>
</div>
</div>
@ -215,10 +213,6 @@
</Theme>
<style lang="scss">
* {
--status-bar-height: 32px;
}
#ui-root {
position: relative;
display: flex;
@ -235,6 +229,7 @@
font-size: 12px;
line-height: 150%;
background-color: var(--theme-statusbar-color);
border-bottom: 1px solid var(--theme-navpanel-divider);
.maintenanceScheduled {
padding: 0 0.5rem;
@ -251,16 +246,12 @@
text-align: center;
}
.clock {
margin: 0 16px 0 24px;
font-weight: 500;
user-select: none;
margin: 0 12px 0 8px;
}
.widget {
-webkit-app-region: no-drag;
width: 16px;
height: 16px;
font-size: 14px;
color: var(--content-color);
font-size: 13px;
color: var(--theme-content-color);
transition: transform 0.15s ease-in-out;
&.rotated {

View File

@ -0,0 +1,151 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { onMount } from 'svelte'
import FontSize from './icons/FontSize.svelte'
import CheckCircled from './icons/CheckCircled.svelte'
export let size: string
export let focused: string
let btn: HTMLButtonElement
onMount(() => {
if (focused === size) btn.focus()
})
</script>
<button
bind:this={btn}
class="antiButton regular sh-no-shape jf-center bs-none no-focus statusPopupThemeButton"
class:focused={focused === size}
class:both={size === 'theme-system'}
>
{#if size === 'theme-light' || size === 'theme-system'}
<div class="light-container">
<div class="paper"><FontSize /></div>
</div>
{/if}
{#if size === 'theme-dark' || size === 'theme-system'}
<div class="dark-container">
<div class="paper"><FontSize /></div>
</div>
{/if}
{#if focused === size}
<CheckCircled />
{/if}
</button>
<style lang="scss">
:global(.statusPopupThemeButton svg.check) {
position: absolute;
bottom: 3px;
right: 3px;
width: 16px;
height: 16px;
}
.statusPopupThemeButton {
position: relative;
flex-shrink: 0;
width: 76px;
height: 56px;
border-radius: 6px;
.light-container {
background-color: #f5f5f5;
border: 1px solid rgba(0, 0, 0, 0.1);
.paper {
color: #000000cc;
background-color: #fff;
border-top: 1px solid rgba(0, 0, 0, 0.2);
border-left: 1px solid rgba(0, 0, 0, 0.2);
}
}
.dark-container {
background-color: #3f3f3f;
.paper {
color: #ffffffcc;
background-color: #161516;
border-top: 1px solid rgba(255, 255, 255, 0.2);
border-left: 1px solid rgba(255, 255, 255, 0.2);
}
}
.light-container,
.dark-container {
overflow: hidden;
height: 100%;
.paper {
padding: 6px 0 0 6px;
width: 100%;
height: 100%;
border-radius: 4px 0px 5.5px 0px;
}
}
&.both {
.light-container {
border-right: none;
border-radius: 5.75px 0 0 5.75px;
}
.dark-container {
border-radius: 0 5.75px 5.75px 0;
}
.light-container,
.dark-container {
width: 50%;
.paper {
margin: 16px 0 0 8px;
}
}
}
&:not(.both) {
.dark-container {
border: 1px solid rgba(255, 255, 255, 0.1);
}
.light-container,
.dark-container {
width: 100%;
border-radius: 5.75px;
.paper {
margin: 16px 0 0 16px;
}
}
}
&:hover:not(:focus) {
.light-container .paper {
color: #000;
background-color: #f2f2f2;
}
.dark-container .paper {
color: #fff;
background-color: #222222;
}
}
&.focused::before,
&:focus::before {
position: absolute;
content: '';
inset: -3px;
border: 1px solid var(--primary-button-default);
border-radius: 8.5px;
cursor: default;
}
}
</style>

View File

@ -0,0 +1,43 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import type { IntlString } from '@hcengineering/platform'
import ThemeButton from './ThemeButton.svelte'
import { Label } from '../..'
export let themes: Array<{ id: string; label: IntlString; size: number }>
export let selected: string = ''
const dispatch = createEventDispatcher()
const select = (size: string): void => {
if (selected === size) return
selected = size
dispatch('close', size)
}
</script>
<div class="antiPopup" style:flex-direction={'row'} style:padding={'12px'}>
{#each themes as theme}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="statusPopup-option" class:selected={selected === theme.id} on:click={() => select(theme.id)}>
<ThemeButton size={theme.id} focused={selected} />
<span class="label overflow-label">
<Label label={theme.label} />
</span>
</div>
{/each}
</div>

View File

@ -1,23 +1,53 @@
<script lang="ts">
import { getContext } from 'svelte'
import Mute from './icons/Mute.svelte'
import { deviceOptionsStore as deviceInfo } from '../../'
import { IntlString } from '@hcengineering/platform'
import ui, { showPopup, deviceOptionsStore as deviceInfo } from '../..'
import Theme from './icons/Theme.svelte'
import ThemePopup from './ThemePopup.svelte'
import { isSystemThemeDark } from '@hcengineering/theme'
const { currentTheme, setTheme } = getContext('theme') as { currentTheme: string; setTheme: (theme: string) => void }
const themes = ['theme-light', 'theme-dark']
const themes: Array<{ id: string; label: IntlString }> = [
{ id: 'theme-light', label: ui.string.ThemeLight },
{ id: 'theme-dark', label: ui.string.ThemeDark },
{ id: 'theme-system', label: ui.string.ThemeSystem }
]
let pressed: boolean = false
let remove: any = null
let current = themes.indexOf(currentTheme)
$deviceInfo.theme = currentTheme
let current = themes.findIndex((th) => th.id === currentTheme)
function changeTheme () {
current++
setTheme(themes[current % themes.length])
$deviceInfo.theme = themes[current % themes.length]
function changeTheme (ev: MouseEvent) {
pressed = true
showPopup(ThemePopup, { themes, selected: themes[current].id }, 'status', (result) => {
if (result) {
setTheme(result)
current = themes.findIndex((th) => th.id === result)
}
pressed = false
})
}
$: $deviceInfo.theme = themes[current].id
$: if (themes[current].id === 'theme-system') checkSystemTheme()
const checkSystemTheme = () => {
if (remove !== null || themes[current].id !== 'theme-system') remove()
const isDark = isSystemThemeDark()
const media = matchMedia(`(prefers-color-scheme: ${isDark ? 'light' : 'dark'})`)
setTheme(themes[current].id)
media.addEventListener('change', checkSystemTheme)
remove = () => {
media.removeEventListener('change', checkSystemTheme)
}
}
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-center" on:click={changeTheme}>
<Mute />
</div>
<button
class="antiButton ghost jf-center bs-none no-focus resetIconSize statusButton square"
class:pressed
style:color={'var(--theme-dark-color)'}
on:click={changeTheme}
>
<Theme />
</button>

View File

@ -0,0 +1,11 @@
<script lang="ts">
export let fill: string = 'var(--primary-button-default)'
</script>
<svg class="svg-16px check" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M4.11101 2.17959C5.26216 1.41042 6.61553 0.999878 8 0.999878C9.85652 0.999878 11.637 1.73738 12.9497 3.05013C14.2625 4.36288 15 6.14336 15 7.99988C15 9.38435 14.5895 10.7377 13.8203 11.8889C13.0511 13.04 11.9579 13.9372 10.6788 14.467C9.3997 14.9968 7.99224 15.1355 6.63437 14.8654C5.2765 14.5953 4.02922 13.9286 3.05026 12.9496C2.07129 11.9707 1.4046 10.7234 1.13451 9.36551C0.86441 8.00764 1.00303 6.60018 1.53285 5.32109C2.06266 4.04201 2.95987 2.94876 4.11101 2.17959ZM11.3536 6.35355C11.5488 6.15829 11.5488 5.84171 11.3536 5.64645C11.1583 5.45118 10.8417 5.45118 10.6464 5.64645L7 9.29289L5.35355 7.64645C5.15829 7.45118 4.84171 7.45118 4.64645 7.64645C4.45118 7.84171 4.45118 8.15829 4.64645 8.35355L6.64645 10.3536C6.84171 10.5488 7.15829 10.5488 7.35355 10.3536L11.3536 6.35355Z"
/>
</svg>

View File

@ -1,84 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="usa-star" viewBox="0 -0.5 0.5 0.5">
<polygon
points="0.3,-0.3 0.4,-0.5 0.2,-0.4 0.2,-0.4 0.2,-0.4 0.1,-0.5 0.2,-0.3 0.2,-0.3 0.2,-0.3 0,-0.2 0.2,-0.2 0.2,0 0.3,-0.2 0.3,-0.2 0.3,-0.2 0.5,-0.2 0.3,-0.3 0.3,-0.3 "
/>
</symbol>
<symbol id="en-flag" viewBox="0 0 16 16">
<g fill={'#DB2E2E'}>
<rect y="6.1" width="16" height="0.8" />
<rect y="4.5" width="16" height="0.8" />
<rect y="3" width="16" height="0.8" />
<rect y="7.6" width="16" height="0.8" />
<rect y="9.2" width="16" height="0.8" />
<rect y="10.7" width="16" height="0.8" />
<rect y="12.2" width="16" height="0.8" />
</g>
<g fill={'#FFFFFF'}>
<rect y="5.3" width="16" height="0.8" />
<rect y="3.8" width="16" height="0.8" />
<rect y="6.8" width="16" height="0.8" />
<rect y="8.4" width="16" height="0.8" />
<rect y="9.9" width="16" height="0.8" />
<rect y="11.5" width="16" height="0.8" />
</g>
<rect fill={'#2E4593'} y="3" width="6" height="4.6" />
<g fill={'#FFFFFF'}>
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.2971 3.1931)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.2774 3.1931)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.2414 3.1931)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.2254 3.1931)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.2313 3.1931)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 5.1989 3.1931)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.7922 3.6606)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.7726 3.6606)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.7366 3.6606)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.7206 3.6606)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.7265 3.6606)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.7922 4.601)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.7726 4.601)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.7366 4.601)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.7206 4.601)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.7265 4.601)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.7922 5.5424)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.7726 5.5424)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.7366 5.5424)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.7206 5.5424)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.7265 5.5424)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.7922 6.4829)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.7726 6.4829)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.7366 6.4829)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.7206 6.4829)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.7265 6.4829)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.2971 4.1299)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.2774 4.1299)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.2414 4.1299)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.2254 4.1299)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.2313 4.1299)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 5.1989 4.1299)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.2971 5.0712)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.2774 5.0712)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.2414 5.0712)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.2254 5.0712)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.2313 5.0712)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 5.1989 5.0712)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.2971 6.0135)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.2774 6.0135)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.2414 6.0135)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.2254 6.0135)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.2313 6.0135)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 5.1989 6.0135)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 0.2971 6.9558)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 1.2774 6.9558)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 2.2414 6.9558)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 3.2254 6.9558)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 4.2313 6.9558)" />
<use xlink:href="#usa-star" width="0.5" height="0.5" y="-0.5" transform="matrix(1 0 0 -1 5.1989 6.9558)" />
</g>
</symbol>
<symbol id="ru-flag" viewBox="0 0 16 16">
<rect fill={'#FDFFFF'} y="3" width="16" height="3.3" />
<rect fill={'#DB2E2E'} y="9.7" width="16" height="3.3" />
<rect fill={'#3C5EBF'} y="6.3" width="16" height="3.3" />
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -1,12 +1,13 @@
<script lang="ts">
const fill: string = 'currentColor'
export let size: string = '16px'
export let fill: string = 'currentColor'
</script>
<svg class="svg-16px" {fill} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M5.1,4.6L0,19.4h2.1l1.5-4.2h5.7l1.5,4.2h2.1L7.7,4.6H5.1z M3.9,13.4l2.3-6.9h0.2l2.4,6.9H3.9z" />
<path
d="M23,17.6v-5.7c0-1.1-0.3-2.1-1.1-2.8c-0.8-0.7-1.8-1-3.3-1c-1,0-1.8,0.2-2.4,0.7c-0.7,0.5-1.1,1-1.5,1.5l1.1,1.1 c0.3-0.5,0.7-1,1.1-1.3c0.5-0.3,1-0.5,1.6-0.5c0.8,0,1.5,0.2,1.8,0.7c0.3,0.3,0.7,1,0.7,1.6v1h-2.1c-1.6,0-2.8,0.3-3.6,0.8 c-0.8,0.5-1.1,1.3-1.1,2.4c0,1,0.3,1.8,1,2.4c0.7,0.7,1.5,0.8,2.6,0.8c0.8,0,1.5-0.2,2-0.5c0.5-0.3,1-0.8,1.1-1.5h0.2 c0,0.5,0.3,1,0.5,1.3c0.3,0.3,0.8,0.5,1.3,0.5H24v-1.6C24,17.6,23,17.6,23,17.6z M20.9,16.2c0,0.5-0.3,1-0.8,1.3s-1.1,0.5-2,0.5 c-0.7,0-1.1-0.2-1.5-0.5s-0.5-0.7-0.5-1.1v-0.5c0-0.5,0.2-1,0.7-1.1c0.5-0.3,1.1-0.3,2-0.3h2.1V16.2z"
/>
</g>
<svg style:width={size} style:height={size} {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M23.8382 23.1294C26.1022 23.1294 27.7617 21.7172 27.7617 19.797V18.7192L24.134 18.9422C22.0501 19.0661 20.9695 19.797 20.9695 21.0854C20.9695 22.3242 22.0886 23.1294 23.8382 23.1294ZM23.3622 25C20.545 25 18.6797 23.4391 18.6797 21.073C18.6797 18.7812 20.5064 17.4309 23.8767 17.2327L27.7617 17.0097V15.8947C27.7617 14.2347 26.6296 13.318 24.5843 13.318C22.9763 13.318 21.7799 14.1108 21.5098 15.3744H19.3615C19.4258 13.1198 21.7027 11.3978 24.61 11.3978C27.8903 11.3978 30 13.0826 30 15.7089V24.8761H27.8775V22.5596H27.826C27.0413 24.0461 25.3047 25 23.3622 25Z"
/>
<path
d="M15.5458 24.8761L13.6805 19.7598H6.29658L4.4313 24.8761H2L8.84365 7H11.1334L17.9771 24.8761H15.5458ZM9.94996 9.71301L6.97837 17.8644H12.9987L10.0271 9.71301H9.94996Z"
/>
</svg>

View File

@ -1,9 +0,0 @@
<script lang="ts">
const fill: string = 'currentColor'
</script>
<svg class="svg-16px" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M14.3,8c-0.2-0.1-0.5-0.1-0.7,0c-1.6,1.2-3.9,1-5.3-0.4C6.9,6.2,6.7,4,7.9,2.4c0.1-0.2,0.2-0.4,0-0.7 C7.9,1.5,7.6,1.4,7.4,1.4c-3.5,0.3-6.1,3.3-6,6.8c0.1,3.5,2.9,6.3,6.4,6.4c0.1,0,0.1,0,0.2,0c3.4,0,6.3-2.6,6.6-6 C14.6,8.4,14.5,8.1,14.3,8z M7.8,13.4C5,13.3,2.7,11,2.6,8.2C2.5,5.7,4.1,3.6,6.3,2.9C5.5,4.8,6,7,7.5,8.5c1.5,1.5,3.8,1.9,5.7,1.2 C12.4,11.9,10.3,13.5,7.8,13.4z"
/>
</svg>

View File

@ -0,0 +1,9 @@
<script lang="ts">
export let fill: string = 'currentColor'
</script>
<svg class="svg-16px" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path
d="M16,2C8.3,2,2,8.3,2,16s6.3,14,14,14s14-6.3,14-14S23.7,2,16,2z M12.4,27.5c-1.5-0.5-2.9-1.2-4.1-2.2c-0.6-0.5-1.1-1-1.6-1.6c-1-1.2-1.7-2.6-2.2-4.1C4.2,18.4,4,17.2,4,16C4,9.4,9.4,4,16,4v24C14.8,28,13.6,27.8,12.4,27.5z"
/>
</svg>

View File

@ -87,7 +87,12 @@ export const uis = plugin(uiId, {
TravelAndPlaces: '' as IntlString,
Food: '' as IntlString,
MoreCount: '' as IntlString,
Objects: '' as IntlString
Objects: '' as IntlString,
Spacious: '' as IntlString,
Compact: '' as IntlString,
ThemeLight: '' as IntlString,
ThemeDark: '' as IntlString,
ThemeSystem: '' as IntlString
},
metadata: {
DefaultApplication: '' as Metadata<AnyComponent>,

View File

@ -329,6 +329,9 @@ export function fitPopupElement (
newProps.bottom = '12px'
newProps.right = '12px'
show = true
} else if (element === 'status') {
newProps.top = 'calc(var(--status-bar-height) + 7.5px)'
newProps.right = '12px'
}
} else {
if (clientWidth !== undefined && clientHeight !== undefined) {

View File

@ -157,6 +157,7 @@ export type ButtonShape =
| 'circle'
| 'round'
| 'round2'
| 'round-small'
| 'filter'
| undefined
export type EditStyle =
@ -196,6 +197,7 @@ export type PopupPosAlignment =
| 'help-center'
| 'centered'
| 'center'
| 'status'
export function isPopupPosAlignment (x: any): x is PopupPosAlignment {
return (
@ -349,7 +351,8 @@ export interface DeviceOptions {
sizes: Record<WidthType, boolean>
minWidth: boolean
twoRows: boolean
theme?: any
theme?: string
language?: string
}
export interface TimelineItem {