mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-12 04:37:44 +02:00
UBERF-9699 Refactor settings UI (#8370)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
@@ -110,6 +110,7 @@
|
||||
"FullSize": "Plná velikost",
|
||||
"UseMaxWidth": "Maximální šířka",
|
||||
"Sidebar": "Postranní panel",
|
||||
"FontSize": "Velikost písma",
|
||||
"Language": "Jazyk"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
"FullSize": "Volle Größe",
|
||||
"UseMaxWidth": "Maximale Breite",
|
||||
"Sidebar": "Seitenleiste",
|
||||
"FontSize": "Schriftgröße",
|
||||
"Language": "Sprache"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "Full size",
|
||||
"UseMaxWidth": "Max width",
|
||||
"Sidebar": "Sidebar",
|
||||
"FontSize": "Font size",
|
||||
"Language": "Language"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "Tamaño completo",
|
||||
"UseMaxWidth": "Ancho máximo",
|
||||
"Sidebar": "Barra lateral",
|
||||
"FontSize": "Tamaño de fuente",
|
||||
"Language": "Idioma"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "Taille réelle",
|
||||
"UseMaxWidth": "Largeur maximale",
|
||||
"Sidebar": "Barre latérale",
|
||||
"FontSize": "Taille de police",
|
||||
"Language": "Langue"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "Dimensione intera",
|
||||
"UseMaxWidth": "Larghezza massima",
|
||||
"Sidebar": "Barra laterale",
|
||||
"FontSize ": "Dimensione del carattere",
|
||||
"Language": "Lingua"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "Tamanho completo",
|
||||
"UseMaxWidth": "Largura máxima",
|
||||
"Sidebar": "Barra lateral",
|
||||
"FontSize": "Tamanho da fonte",
|
||||
"Language": "Idioma"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "Полный размер",
|
||||
"UseMaxWidth": "Максимальная ширина",
|
||||
"Sidebar": "Боковая панель",
|
||||
"FontSize": "Размер шрифта",
|
||||
"Language": "Язык"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"FullSize": "全尺寸",
|
||||
"UseMaxWidth": "使用最大宽度",
|
||||
"Sidebar": "侧边栏",
|
||||
"FontSize": "字体大小",
|
||||
"Language": "语言"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
>
|
||||
{#if withIcons}
|
||||
<div class="hulyPopup-row__icon">
|
||||
{#if item.icon}<Icon icon={item.icon} size={'small'} />{/if}
|
||||
{#if item.icon}<Icon icon={item.icon} iconProps={item.iconProps} size={'small'} />{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if item.description}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<!--
|
||||
// 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>
|
||||
@@ -1,50 +0,0 @@
|
||||
<!--
|
||||
// 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 -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<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>
|
||||
@@ -1,58 +0,0 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { IntlString } from '@hcengineering/platform'
|
||||
import { getContext } from 'svelte'
|
||||
import ui, { deviceOptionsStore as deviceInfo, modalStore, showPopup } from '../..'
|
||||
import FontSizePopup from './FontSizePopup.svelte'
|
||||
import FontSize from './icons/FontSize.svelte'
|
||||
|
||||
const { currentFontSize, setFontSize } = getContext<{
|
||||
currentFontSize: string
|
||||
setFontSize: (value: number) => void
|
||||
}>('fontsize')
|
||||
|
||||
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.findIndex((fs) => fs.id === currentFontSize)
|
||||
|
||||
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)
|
||||
$modalStore = $modalStore
|
||||
}
|
||||
pressed = false
|
||||
})
|
||||
}
|
||||
$: $deviceInfo.fontSize = fontsizes[current].size
|
||||
</script>
|
||||
|
||||
<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 />
|
||||
</button>
|
||||
@@ -1,48 +0,0 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 Label from '../Label.svelte'
|
||||
import IconCheck from '../icons/Check.svelte'
|
||||
import Html from '../Html.svelte'
|
||||
|
||||
export let langs: any
|
||||
export let selected: string
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="antiPopup" style:min-width={'200px'}>
|
||||
<div class="ap-space x2" />
|
||||
{#each langs as lang}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="ap-menuItem hoverable flex-row-center leading-16px"
|
||||
on:click={() => {
|
||||
dispatch('close', lang.id)
|
||||
}}
|
||||
>
|
||||
<div class="svg-16px flex-no-shrink text-16px mr-2"><Html value={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" />
|
||||
</div>
|
||||
@@ -1,85 +0,0 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// 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 { getContext, onMount } from 'svelte'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import ui, { showPopup, deviceOptionsStore as deviceInfo } from '../..'
|
||||
import LangPopup from './LangPopup.svelte'
|
||||
import Html from '../Html.svelte'
|
||||
import { updateEmojis } from '../emoji'
|
||||
|
||||
let pressed: boolean = false
|
||||
|
||||
const { currentLanguage, setLanguage } = getContext<{ currentLanguage: string, setLanguage: (lang: string) => void }>(
|
||||
'lang'
|
||||
)
|
||||
const uiLangs = new Set(getMetadata(ui.metadata.Languages))
|
||||
const langs = [
|
||||
{ id: 'en', label: ui.string.English, logo: '🇺🇸' },
|
||||
{ id: 'pt', label: ui.string.Portuguese, logo: '🇵🇹' },
|
||||
{ id: 'es', label: ui.string.Spanish, logo: '🇪🇸' },
|
||||
{ id: 'ru', label: ui.string.Russian, logo: '🇷🇺' },
|
||||
{ id: 'zh', label: ui.string.Chinese, logo: '🇨🇳' },
|
||||
{ id: 'fr', label: ui.string.French, logo: '🇫🇷' },
|
||||
{ id: 'it', label: ui.string.Italian, logo: '🇮🇹' },
|
||||
{ id: 'cs', label: ui.string.Czech, logo: '🇨🇿' },
|
||||
{ id: 'de', label: ui.string.German, logo: '🇩🇪' }
|
||||
].filter((lang) => uiLangs.has(lang.id))
|
||||
if (langs.findIndex((l) => l.id === currentLanguage) < 0 && langs.length !== 0) {
|
||||
setLanguage(langs[0].id)
|
||||
}
|
||||
|
||||
if (langs.length === 0) {
|
||||
console.error(
|
||||
`List of configured UI languages: [${getMetadata(ui.metadata.Languages)?.join(
|
||||
', '
|
||||
)}] doesn't contain any languages available in the app. Please check you configuration.`
|
||||
)
|
||||
}
|
||||
|
||||
const isSelectable = langs.length > 1
|
||||
|
||||
$: selected = langs.find((item) => item.id === currentLanguage)
|
||||
|
||||
const selectLanguage = (): void => {
|
||||
if (!isSelectable) {
|
||||
return
|
||||
}
|
||||
pressed = true
|
||||
|
||||
showPopup(LangPopup, { langs, selected: selected?.id }, 'status', (result) => {
|
||||
if (result) {
|
||||
selected = langs.find((item) => item.id === result)
|
||||
setLanguage(result)
|
||||
void updateEmojis(result)
|
||||
}
|
||||
pressed = false
|
||||
})
|
||||
}
|
||||
$: $deviceInfo.language = selected?.id
|
||||
onMount(() => {
|
||||
void updateEmojis()
|
||||
})
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="antiButton ghost jf-center bs-none no-focus resetIconSize statusButton square"
|
||||
class:pressed
|
||||
on:click={selectLanguage}
|
||||
>
|
||||
{#if selected}
|
||||
<Html value={selected.logo} />
|
||||
{/if}
|
||||
</button>
|
||||
@@ -4,14 +4,15 @@
|
||||
import type { AnyComponent, WidthType } from '../../types'
|
||||
import { deviceSizes, deviceWidths } from '../../types'
|
||||
// import { applicationShortcutKey } from '../../utils'
|
||||
import { Theme } from '@hcengineering/theme'
|
||||
import { Theme, themeStore } from '@hcengineering/theme'
|
||||
import {
|
||||
IconArrowLeft,
|
||||
IconArrowRight,
|
||||
checkMobile,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
checkAdaptiveMatching,
|
||||
getLocalWeekStart
|
||||
getLocalWeekStart,
|
||||
updateEmojis
|
||||
} from '../../'
|
||||
import { desktopPlatform, getCurrentLocation, location, locationStorageKeyId, navigate } from '../../location'
|
||||
import uiPlugin from '../../plugin'
|
||||
@@ -19,10 +20,8 @@
|
||||
import Label from '../Label.svelte'
|
||||
import StatusComponent from '../Status.svelte'
|
||||
import Clock from './Clock.svelte'
|
||||
import FontSizeSelector from './FontSizeSelector.svelte'
|
||||
import LangSelector from './LangSelector.svelte'
|
||||
import RootBarExtension from './RootBarExtension.svelte'
|
||||
import ThemeSelector from './ThemeSelector.svelte'
|
||||
import Settings from './Settings.svelte'
|
||||
|
||||
let application: AnyComponent | undefined
|
||||
|
||||
@@ -89,9 +88,13 @@
|
||||
$: $deviceInfo.isMobile = isMobile
|
||||
$: $deviceInfo.minWidth = docWidth <= 480
|
||||
$: $deviceInfo.twoRows = docWidth <= 680
|
||||
$: $deviceInfo.language = $themeStore.language
|
||||
$: $deviceInfo.fontSize = $themeStore.fontSize
|
||||
|
||||
$: document.documentElement.style.setProperty('--app-height', `${docHeight}px`)
|
||||
|
||||
$: void updateEmojis($themeStore.language)
|
||||
|
||||
let doubleTouchStartTimestamp = 0
|
||||
document.addEventListener('touchstart', (event) => {
|
||||
const now = +new Date()
|
||||
@@ -155,7 +158,7 @@
|
||||
<Theme>
|
||||
<div id="ui-root" class:mobile-theme={isMobile}>
|
||||
<div class="antiStatusBar">
|
||||
<div class="flex-row-center h-full content-color gap-3 pl-4">
|
||||
<div class="flex-row-center h-full content-color gap-3 px-4">
|
||||
{#if desktopPlatform}
|
||||
<div class="history-box flex-row-center gap-3">
|
||||
<button
|
||||
@@ -201,17 +204,13 @@
|
||||
<StatusComponent {status} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex-row-reverse" style:-webkit-app-region={'no-drag'}>
|
||||
<div class="clock">
|
||||
<Clock />
|
||||
</div>
|
||||
<div class="flex-row-reverse flex-gap-2" style:-webkit-app-region={'no-drag'}>
|
||||
<Settings />
|
||||
<Clock />
|
||||
<div class="flex-row-center gap-statusbar">
|
||||
{#if !secondRow}
|
||||
<RootBarExtension position="right" />
|
||||
{/if}
|
||||
<FontSizeSelector />
|
||||
<ThemeSelector />
|
||||
<LangSelector />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -282,9 +281,6 @@
|
||||
font-size: 14px;
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
.clock {
|
||||
margin: 0 12px 0 8px;
|
||||
}
|
||||
|
||||
.second-row {
|
||||
display: none;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 { showPopup } from '../..'
|
||||
import SettingsPopup from './SettingsPopup.svelte'
|
||||
import Settings from './icons/Settings.svelte'
|
||||
|
||||
let pressed: boolean = false
|
||||
let btn: HTMLButtonElement
|
||||
|
||||
function showSettings (): void {
|
||||
pressed = true
|
||||
showPopup(SettingsPopup, {}, btn, () => {
|
||||
pressed = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<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={showSettings}
|
||||
>
|
||||
<Settings />
|
||||
</button>
|
||||
@@ -0,0 +1,196 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 { type IntlString, getMetadata } from '@hcengineering/platform'
|
||||
import { getContext } from 'svelte'
|
||||
|
||||
import FontSize from './icons/FontSize.svelte'
|
||||
import Language from './icons/Language.svelte'
|
||||
|
||||
import ThemeButton from './ThemeButton.svelte'
|
||||
import ui, {
|
||||
Html,
|
||||
Icon,
|
||||
Label,
|
||||
ModernPopup,
|
||||
showPopup,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
modalStore,
|
||||
eventToHTMLElement
|
||||
} from '../..'
|
||||
|
||||
const fontSizeContext = getContext<{ currentFontSize: string, setFontSize: (value: string) => void }>('fontsize')
|
||||
const setFontSize = fontSizeContext.setFontSize
|
||||
let currentFontSize = fontSizeContext.currentFontSize
|
||||
|
||||
const themeContext = getContext<{ currentTheme: string, setTheme: (theme: string) => void }>('theme')
|
||||
const setTheme = themeContext.setTheme
|
||||
let currentTheme = themeContext.currentTheme
|
||||
|
||||
const languageContext = getContext<{ currentLanguage: string, setLanguage: (language: string) => void }>('lang')
|
||||
const setLanguage = languageContext.setLanguage
|
||||
let currentLanguage = languageContext.currentLanguage
|
||||
|
||||
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 }
|
||||
]
|
||||
|
||||
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 }
|
||||
]
|
||||
|
||||
const uiLangs = new Set(getMetadata(ui.metadata.Languages))
|
||||
const langs = [
|
||||
{ id: 'en', label: ui.string.English, logo: '🇺🇸' },
|
||||
{ id: 'pt', label: ui.string.Portuguese, logo: '🇵🇹' },
|
||||
{ id: 'es', label: ui.string.Spanish, logo: '🇪🇸' },
|
||||
{ id: 'ru', label: ui.string.Russian, logo: '🇷🇺' },
|
||||
{ id: 'zh', label: ui.string.Chinese, logo: '🇨🇳' },
|
||||
{ id: 'fr', label: ui.string.French, logo: '🇫🇷' },
|
||||
{ id: 'it', label: ui.string.Italian, logo: '🇮🇹' },
|
||||
{ id: 'cs', label: ui.string.Czech, logo: '🇨🇿' },
|
||||
{ id: 'de', label: ui.string.German, logo: '🇩🇪' }
|
||||
].filter((lang) => uiLangs.has(lang.id))
|
||||
|
||||
if (langs.findIndex((l) => l.id === currentLanguage) < 0 && langs.length !== 0) {
|
||||
setLanguage(langs[0].id)
|
||||
}
|
||||
|
||||
if (langs.length === 0) {
|
||||
console.error(
|
||||
`List of configured UI languages: [${getMetadata(ui.metadata.Languages)?.join(
|
||||
', '
|
||||
)}] doesn't contain any languages available in the app. Please check you configuration.`
|
||||
)
|
||||
}
|
||||
|
||||
function selectFontSize (size: string): void {
|
||||
if (currentFontSize === size) return
|
||||
currentFontSize = size
|
||||
setFontSize(size)
|
||||
$modalStore = $modalStore
|
||||
}
|
||||
|
||||
function selectTheme (theme: string): void {
|
||||
if (currentTheme === theme) return
|
||||
currentTheme = theme
|
||||
setTheme(theme)
|
||||
}
|
||||
|
||||
function selectLanguage (language: string): void {
|
||||
if (currentLanguage === language) return
|
||||
currentLanguage = language
|
||||
setLanguage(language)
|
||||
}
|
||||
|
||||
$: $deviceInfo.theme = currentTheme
|
||||
$: fontsize = fontsizes.find((fs) => fs.id === currentFontSize) ?? fontsizes[0]
|
||||
$: language = langs.find((lang) => lang.id === currentLanguage) ?? langs[0]
|
||||
</script>
|
||||
|
||||
<div class="antiPopup">
|
||||
<div class="ap-scroll">
|
||||
<div class="ap-box">
|
||||
<div class="flex-row-center m-4">
|
||||
{#each themes as theme}
|
||||
{@const selected = currentTheme === theme.id}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="statusPopup-option"
|
||||
class:selected
|
||||
on:click={() => {
|
||||
selectTheme(theme.id)
|
||||
}}
|
||||
>
|
||||
<ThemeButton theme={theme.id} focused={currentTheme} />
|
||||
<span class="label overflow-label">
|
||||
<Label label={theme.label} />
|
||||
</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="ap-menuItem separator halfMargin" />
|
||||
|
||||
<button
|
||||
class="ap-menuItem antiPopup-submenu withIcon flex-row-center flex-grow"
|
||||
on:click={(ev) => {
|
||||
const items = fontsizes.map((p) => {
|
||||
return {
|
||||
...p,
|
||||
icon: FontSize,
|
||||
iconProps: {
|
||||
size: p.size
|
||||
}
|
||||
}
|
||||
})
|
||||
showPopup(ModernPopup, { items, selected: fontsize.id }, eventToHTMLElement(ev), (id) => {
|
||||
if (id !== undefined) {
|
||||
selectFontSize(id)
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div class="flex-between flex-grow">
|
||||
<div class="flex-row-center">
|
||||
<div class="icon mr-2"><FontSize size={'16px'} /></div>
|
||||
<span class="label font-medium"><Label label={ui.string.FontSize} /></span>
|
||||
</div>
|
||||
<div class="flex-row-center pr-4">
|
||||
<Label label={fontsize.label} />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="ap-menuItem separator halfMargin" />
|
||||
|
||||
<button
|
||||
class="ap-menuItem antiPopup-submenu withIcon flex-row-center flex-grow"
|
||||
on:click={(ev) => {
|
||||
const items = langs.map((p) => {
|
||||
return {
|
||||
...p,
|
||||
icon: Html,
|
||||
iconProps: {
|
||||
value: p.logo
|
||||
}
|
||||
}
|
||||
})
|
||||
showPopup(ModernPopup, { items, selected: language.id }, eventToHTMLElement(ev), (id) => {
|
||||
if (id !== undefined) {
|
||||
selectLanguage(id)
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div class="flex-between flex-grow">
|
||||
<div class="flex-row-center">
|
||||
<div class="icon mr-2"><Icon icon={Language} size={'small'} /></div>
|
||||
<span class="label font-medium"><Label label={ui.string.Language} /></span>
|
||||
</div>
|
||||
<div class="flex-row-center pr-4">
|
||||
<div class="label text-lgd">
|
||||
<Html value={language.logo} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -17,33 +17,33 @@
|
||||
import FontSize from './icons/FontSize.svelte'
|
||||
import CheckCircled from './icons/CheckCircled.svelte'
|
||||
|
||||
export let size: string
|
||||
export let theme: string
|
||||
export let focused: string
|
||||
|
||||
let btn: HTMLButtonElement
|
||||
|
||||
onMount(() => {
|
||||
if (focused === size) btn.focus()
|
||||
if (focused === theme) 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'}
|
||||
class:focused={theme === focused}
|
||||
class:both={theme === 'theme-system'}
|
||||
>
|
||||
{#if size === 'theme-light' || size === 'theme-system'}
|
||||
{#if theme === 'theme-light' || theme === 'theme-system'}
|
||||
<div class="light-container">
|
||||
<div class="paper"><FontSize /></div>
|
||||
<div class="paper"><FontSize size={'small'} /></div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if size === 'theme-dark' || size === 'theme-system'}
|
||||
{#if theme === 'theme-dark' || theme === 'theme-system'}
|
||||
<div class="dark-container">
|
||||
<div class="paper"><FontSize /></div>
|
||||
<div class="paper"><FontSize size={'small'} /></div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if focused === size}
|
||||
{#if focused === theme}
|
||||
<CheckCircled />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<!--
|
||||
// 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 -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<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>
|
||||
@@ -1,53 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
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<{ currentTheme: string, setTheme: (theme: string) => void }>('theme')
|
||||
|
||||
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.findIndex((th) => th.id === currentTheme)
|
||||
|
||||
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>
|
||||
|
||||
<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>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M4.68191 1.69187C4.87991 1.49938 4.88436 1.18283 4.69187 0.984833C4.49938 0.786842 4.18283 0.782385 3.98483 0.974878C2.65823 2.26464 1.83337 4.06435 1.83337 6.05505C1.83337 9.59167 4.43291 12.5202 7.83337 13.0729V14.1667H7.00004C6.7239 14.1667 6.50004 14.3906 6.50004 14.6667C6.50004 14.9429 6.7239 15.1667 7.00004 15.1667H9.66671C9.94285 15.1667 10.1667 14.9429 10.1667 14.6667C10.1667 14.3906 9.94285 14.1667 9.66671 14.1667H8.83337V13.1648C8.88878 13.1661 8.94434 13.1667 9.00004 13.1667C10.9518 13.1667 12.7227 12.3918 14.0152 11.1352C14.2132 10.9427 14.2177 10.6262 14.0252 10.4282C13.8327 10.2302 13.5162 10.2257 13.3182 10.4182C12.2056 11.4999 10.6823 12.1667 9.00004 12.1667C5.59037 12.1667 2.83337 9.42653 2.83337 6.05505C2.83337 4.34666 3.54004 2.80204 4.68191 1.69187Z"
|
||||
fill="#84868B"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M14.1667 6.00004C14.1667 3.14657 11.8535 0.833374 9.00004 0.833374C6.14657 0.833374 3.83337 3.14657 3.83337 6.00004C3.83337 8.85351 6.14657 11.1667 9.00004 11.1667C11.8535 11.1667 14.1667 8.85351 14.1667 6.00004ZM10.4809 2.1042C12.051 2.70134 13.1667 4.2204 13.1667 6.00004C13.1667 6.05806 13.1655 6.11581 13.1632 6.17325C12.6127 6.21617 12.2572 6.46117 12.0059 6.6343L11.9834 6.6498C11.7159 6.83381 11.622 6.88121 11.4314 6.84309C10.588 6.67441 9.91228 6.65022 9.42916 6.87348C9.16608 6.99505 8.96919 7.18556 8.84651 7.43242C8.7297 7.66746 8.69443 7.92441 8.69443 8.16744C8.69443 8.59239 8.69082 8.71663 8.66595 8.81643C8.6436 8.90609 8.60163 8.98698 8.4156 9.3069C8.29623 9.51219 8.17257 9.78133 8.16691 10.0834C6.26494 9.69742 4.83337 8.01591 4.83337 6.00004C4.83337 4.93814 5.23061 3.96903 5.8846 3.23318C5.99594 3.29692 6.12615 3.41985 6.35256 3.65906C7.16302 4.51543 8.09936 4.69029 8.81521 4.31208C9.07412 4.17529 9.24817 3.99547 9.35513 3.77965C9.44011 3.60819 9.4714 3.42827 9.48901 3.32701L9.49446 3.29611C9.51553 3.18052 9.52807 3.15412 9.53787 3.13932C9.54107 3.13436 9.56782 3.09285 9.69883 3.04094C10.1188 2.87452 10.3883 2.54386 10.4722 2.14918C10.4754 2.13421 10.4783 2.11921 10.4809 2.1042ZM12.5502 7.47369C12.7083 7.36492 12.8367 7.27751 12.984 7.22419C12.4784 8.87157 10.9791 10.0842 9.18534 10.1627C9.18342 10.1598 9.18179 10.1571 9.1804 10.1548C9.17035 10.1376 9.16748 10.1253 9.16683 10.1108C9.16493 10.0679 9.18335 9.97592 9.28007 9.80958L9.30549 9.76591C9.45445 9.51018 9.57539 9.30254 9.63627 9.05825C9.68712 8.8542 9.69367 8.63306 9.69439 8.35499C9.6945 8.31317 9.69448 8.27006 9.69445 8.22552L9.69443 8.16744C9.69443 8.01307 9.7182 7.92539 9.74202 7.87746C9.75998 7.84133 9.78532 7.8105 9.84864 7.78124C9.9615 7.72909 10.1734 7.69224 10.5449 7.72185C10.732 7.73676 10.9596 7.76852 11.2353 7.82366C11.86 7.94863 12.264 7.67061 12.5407 7.48024L12.5502 7.47369ZM9.4995 1.863C9.33574 1.84344 9.16907 1.83337 9.00004 1.83337C8.12977 1.83337 7.32181 2.10018 6.6535 2.55646C6.80213 2.67993 6.93823 2.82311 7.07885 2.97168C7.66786 3.59405 8.13098 3.54259 8.34807 3.4279C8.43679 3.38102 8.45311 3.34785 8.45873 3.33641L8.45914 3.33558C8.47687 3.29981 8.48428 3.26156 8.51067 3.11678C8.53273 2.99578 8.5711 2.78807 8.7039 2.58751C8.84434 2.37543 9.05399 2.22081 9.33046 2.11126C9.44573 2.06559 9.4812 2.00164 9.49401 1.94135C9.49878 1.9189 9.50098 1.89249 9.4995 1.863Z"
|
||||
fill="#84868B"
|
||||
/>
|
||||
</svg>
|
||||
File diff suppressed because one or more lines are too long
@@ -138,6 +138,7 @@ export const uis = plugin(uiId, {
|
||||
FullSize: '' as IntlString,
|
||||
UseMaxWidth: '' as IntlString,
|
||||
Sidebar: '' as IntlString,
|
||||
FontSize: '' as IntlString,
|
||||
Language: '' as IntlString
|
||||
},
|
||||
metadata: {
|
||||
|
||||
Reference in New Issue
Block a user