mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-20 07:10:02 +00:00
Add wizard (#2571)
Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@xored.com>
This commit is contained in:
parent
6e0b1d1036
commit
67e86538bb
59
packages/ui/src/components/wizard/Wizard.svelte
Normal file
59
packages/ui/src/components/wizard/Wizard.svelte
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||||
|
// Copyright © 2021 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 { getPlatformColor } from '../../colors'
|
||||||
|
import { Component, WizardModel, WizardItemPosition } from '../..'
|
||||||
|
import ScrollerBar from '../ScrollerBar.svelte'
|
||||||
|
import WizardStep from './WizardStep.svelte'
|
||||||
|
|
||||||
|
export let items: readonly WizardModel[]
|
||||||
|
export let selected = 0
|
||||||
|
export let gap: 'none' | 'small' | 'big' = 'none'
|
||||||
|
|
||||||
|
const COLOR = 9
|
||||||
|
|
||||||
|
let divScroll: HTMLElement
|
||||||
|
let selectedItem: WizardModel | undefined
|
||||||
|
|
||||||
|
function getPosition (n: number): WizardItemPosition {
|
||||||
|
if (n === 0) return 'start'
|
||||||
|
else if (n === items.length - 1) return 'end'
|
||||||
|
else return 'middle'
|
||||||
|
}
|
||||||
|
|
||||||
|
$: selectedItem = items[selected]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ScrollerBar {gap} bind:scroller={divScroll}>
|
||||||
|
{#each items as item, i}
|
||||||
|
<WizardStep
|
||||||
|
label={item.label}
|
||||||
|
position={getPosition(i)}
|
||||||
|
positionState={selected === i ? 'current' : i < selected ? 'prev' : 'next'}
|
||||||
|
prevColor={getPlatformColor(COLOR)}
|
||||||
|
currentColor={getPlatformColor(COLOR)}
|
||||||
|
nextColor="var(--theme-bg-focused-color)"
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</ScrollerBar>
|
||||||
|
|
||||||
|
{#if selectedItem}
|
||||||
|
{#if typeof selectedItem.component === 'string'}
|
||||||
|
<Component is={selectedItem.component} props={selectedItem.props} on:change />
|
||||||
|
{:else}
|
||||||
|
<svelte:component this={selectedItem.component} {...selectedItem.props} on:change />
|
||||||
|
{/if}
|
||||||
|
{/if}
|
142
packages/ui/src/components/wizard/WizardStep.svelte
Normal file
142
packages/ui/src/components/wizard/WizardStep.svelte
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||||
|
// Copyright © 2021 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 { IntlString, translate } from '@hcengineering/platform'
|
||||||
|
import { afterUpdate } from 'svelte'
|
||||||
|
import { WizardItemPosition, WizardItemPositionState } from '../..'
|
||||||
|
|
||||||
|
export let label: IntlString
|
||||||
|
export let position: WizardItemPosition
|
||||||
|
export let positionState: WizardItemPositionState
|
||||||
|
export let currentColor = 'var(--theme-bg-focused-color)'
|
||||||
|
export let prevColor = 'var(--theme-bg-focused-color)'
|
||||||
|
export let nextColor = 'var(--theme-bg-accent-color)'
|
||||||
|
|
||||||
|
let lenght: number = 0
|
||||||
|
let text: HTMLElement
|
||||||
|
let divBar: HTMLElement
|
||||||
|
let svgBack: SVGElement
|
||||||
|
let style: string
|
||||||
|
let translation: string | undefined
|
||||||
|
|
||||||
|
function getStyle (state: typeof positionState) {
|
||||||
|
switch (state) {
|
||||||
|
case 'current':
|
||||||
|
return `fill: ${currentColor};`
|
||||||
|
case 'prev':
|
||||||
|
return `fill: ${prevColor};`
|
||||||
|
case 'next':
|
||||||
|
return `fill: ${nextColor};`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: style = getStyle(positionState)
|
||||||
|
$: label && translate(label, {}).then((t) => (translation = t))
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
if (text) lenght = text.clientWidth + 32 > 300 ? 300 : text.clientWidth + 32
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if translation}
|
||||||
|
<div class="hidden-text text-md font-medium" bind:this={text}>{translation}</div>
|
||||||
|
{#if lenght > 0}
|
||||||
|
<div class="flex-row">
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<div bind:this={divBar} class="bar" on:click|stopPropagation>
|
||||||
|
<svg
|
||||||
|
bind:this={svgBack}
|
||||||
|
class="bar__back"
|
||||||
|
viewBox="0 0 {lenght} 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
>
|
||||||
|
{#if position === 'start'}
|
||||||
|
<path
|
||||||
|
class="bar__element"
|
||||||
|
{style}
|
||||||
|
d="M0,5.3C0,2.4,2.3,0,5.2,0h1.3h{lenght -
|
||||||
|
13}h1.2c0.5,0,1,0.3,1.2,0.9l4,10.7c0.1,0.3,0.1,0.7,0,0.9l-4,10.7c-0.2,0.5-0.7,0.9-1.2,0.9 l-1.2,0h-{lenght -
|
||||||
|
13}H5.2C2.3,24,0,21.6,0,18.7V5.3z"
|
||||||
|
/>
|
||||||
|
{:else if position === 'middle'}
|
||||||
|
<path
|
||||||
|
class="bar__element"
|
||||||
|
{style}
|
||||||
|
d="M4,11.5L0.1,0.9C-0.1,0.5,0.2,0,0.6,0h5.8h{lenght -
|
||||||
|
13}h1.2c0.5,0,1,0.3,1.2,0.9l4,10.7c0.1,0.3,0.1,0.7,0,0.9l-4,10.7 c-0.2,0.5-0.7,0.9-1.2,0.9h-1.2h-{lenght -
|
||||||
|
13}H0.6c-0.5,0-0.8-0.5-0.6-0.9L4,12.5C4.1,12.2,4.1,11.8,4,11.5z"
|
||||||
|
/>
|
||||||
|
{:else if position === 'end'}
|
||||||
|
<path
|
||||||
|
class="bar__element"
|
||||||
|
{style}
|
||||||
|
d="M4.1,11.5l-4-10.6C-0.1,0.5,0.2,0,0.7,0h{lenght - 7}C{lenght -
|
||||||
|
3},0,{lenght},2.4,{lenght},5.3v13.3c0,2.9-2.4,5.3-5.3,5.3h-{lenght}H0.6c-0.5,0-0.8-0.5-0.6-0.9L4,12.5C4.1,12.2,4.1,11.8,4,11.5z"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<path
|
||||||
|
class="bar__element"
|
||||||
|
{style}
|
||||||
|
d="M0,5.3C0,2.4,2.3,0,5.2,0h1.3h{lenght}h1.3C49.7,0,52,2.4,52,5.3v13.3c0,2.9-2.3,5.3-5.2,5.3h-1.3h-{lenght}H5.2 C2.3,24,0,21.6,0,18.7V5.3z"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</svg>
|
||||||
|
<div class="container"><div class="overflow-label">{translation}</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.bar {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
min-width: 0;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
&__back {
|
||||||
|
width: auto;
|
||||||
|
padding: 1px 0.5px;
|
||||||
|
height: calc(1.5rem + 2px);
|
||||||
|
}
|
||||||
|
&__element {
|
||||||
|
fill: var(--accent-bg-color);
|
||||||
|
stroke: var(--divider-color);
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
top: 0;
|
||||||
|
left: 0.5rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
min-width: 0;
|
||||||
|
width: calc(100% - 1rem);
|
||||||
|
height: 100%;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: var(--dark-color);
|
||||||
|
pointer-events: none;
|
||||||
|
color: var(--caption-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -163,6 +163,7 @@ export { default as notificationsStore } from './components/notifications/store'
|
|||||||
export { NotificationPosition } from './components/notifications/NotificationPosition'
|
export { NotificationPosition } from './components/notifications/NotificationPosition'
|
||||||
export { NotificationSeverity } from './components/notifications/NotificationSeverity'
|
export { NotificationSeverity } from './components/notifications/NotificationSeverity'
|
||||||
export { Notification } from './components/notifications/Notification'
|
export { Notification } from './components/notifications/Notification'
|
||||||
|
export { default as Wizard } from './components/wizard/Wizard.svelte'
|
||||||
|
|
||||||
export * from './types'
|
export * from './types'
|
||||||
export * from './location'
|
export * from './location'
|
||||||
|
@ -281,3 +281,11 @@ export interface TimelineState {
|
|||||||
timelineBox: DOMRect
|
timelineBox: DOMRect
|
||||||
viewBox: DOMRect
|
viewBox: DOMRect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WizardModel {
|
||||||
|
label: IntlString
|
||||||
|
component: AnyComponent | AnySvelteComponent
|
||||||
|
props?: any
|
||||||
|
}
|
||||||
|
export type WizardItemPosition = 'start' | 'middle' | 'end'
|
||||||
|
export type WizardItemPositionState = 'current' | 'prev' | 'next'
|
||||||
|
Loading…
Reference in New Issue
Block a user