mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-21 16:09:12 +03:00
UI and icons fixes (#7177)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
This commit is contained in:
parent
bcdfed6871
commit
dd8ba84a9b
@ -93,6 +93,11 @@
|
||||
user-select: none;
|
||||
box-shadow: var(--theme-popup-shadow);
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 1.75rem;
|
||||
color: var(--theme-content-color);
|
||||
|
@ -900,6 +900,7 @@ a.no-line {
|
||||
.leading-3 { line-height: .75rem; }
|
||||
.tracking--05px { letter-spacing: -.5px; }
|
||||
.tracking-1px { letter-spacing: 1px; }
|
||||
.text-balance { text-wrap: balance; }
|
||||
|
||||
.over-underline {
|
||||
cursor: pointer;
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
--tag-on-accent-PorpoiseText: #FFFFFF;
|
||||
--tag-accent-SunshineBackground: #FFBD2E;
|
||||
|
||||
--border-color-global-error-border-color: #fb6863;
|
||||
}
|
||||
|
||||
/* Dark Theme */
|
||||
|
@ -444,4 +444,9 @@
|
||||
&.delete {
|
||||
background: var(--text-editor-highlighted-node-delete-background-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hiding the selection of an empty line
|
||||
.select-text p > br.ProseMirror-trailingBreak::selection {
|
||||
background: transparent;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
--spacing-4: 2rem;
|
||||
--spacing-4_5: 2.25rem;
|
||||
--spacing-5: 2.5rem;
|
||||
--spacing-5_5: 2.75rem;
|
||||
--spacing-6: 3rem;
|
||||
--spacing-6_5: 3.5rem;
|
||||
--spacing-7: 4rem;
|
||||
|
@ -543,6 +543,11 @@
|
||||
.hulyModal-footer {
|
||||
padding: var(--spacing-1_5);
|
||||
}
|
||||
@media screen and (max-width: 480px) {
|
||||
width: 100vw;
|
||||
height: var(--app-height);
|
||||
min-width: 20rem;
|
||||
}
|
||||
}
|
||||
&.type-aside,
|
||||
&.type-popup {
|
||||
|
@ -50,6 +50,7 @@
|
||||
}
|
||||
|
||||
&__title-wrap {
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
@ -277,6 +278,12 @@
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.antiCard-header {
|
||||
padding: .75rem .75rem .375rem;
|
||||
|
||||
|
123
packages/ui/src/components/ModernCheckbox.svelte
Normal file
123
packages/ui/src/components/ModernCheckbox.svelte
Normal file
@ -0,0 +1,123 @@
|
||||
<script lang="ts">
|
||||
//
|
||||
// © 2023 Hardcore Engineering, Inc. All Rights Reserved.
|
||||
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
|
||||
//
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { generateId } from '@hcengineering/core'
|
||||
import { Label } from '../..'
|
||||
|
||||
export let id: string = generateId()
|
||||
export let label: string | undefined = undefined
|
||||
export let labelIntl: IntlString | undefined = undefined
|
||||
export let labelParams: Record<string, any> | undefined = undefined
|
||||
export let checked: boolean = false
|
||||
export let indeterminate: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let error: boolean = false
|
||||
export let required: boolean = false
|
||||
</script>
|
||||
|
||||
<label class="checkbox-container" class:disabled>
|
||||
<input type="checkbox" class="checkbox" {id} bind:checked {disabled} {indeterminate} {required} on:change />
|
||||
<div class="checkbox-element" class:disabled class:error />
|
||||
{#if label !== undefined || labelIntl !== undefined || $$slots.default !== undefined}
|
||||
<div class="checkbox-label">
|
||||
{#if labelIntl}<Label label={labelIntl} params={labelParams} />{:else}{label}{/if}
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
<slot name="after" />
|
||||
</label>
|
||||
|
||||
<style lang="scss">
|
||||
.checkbox-element {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
width: var(--spacing-2);
|
||||
height: var(--spacing-2);
|
||||
background-color: var(--selector-BackgroundColor);
|
||||
border: 1px solid var(--selector-BorderColor);
|
||||
border-radius: var(--extra-small-BorderRadius);
|
||||
}
|
||||
.checkbox-label {
|
||||
color: var(--global-primary-TextColor);
|
||||
user-select: none;
|
||||
}
|
||||
.checkbox {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
|
||||
&:checked + .checkbox-element,
|
||||
&:indeterminate + .checkbox-element {
|
||||
background-color: var(--selector-active-BackgroundColor);
|
||||
border-color: var(--selector-active-BackgroundColor);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0.625rem;
|
||||
height: 0.5rem;
|
||||
background-color: var(--selector-IconColor);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
&:checked + .checkbox-element::after {
|
||||
clip-path: path(
|
||||
'M9.7,0.5c0.4,0.4,0.4,1,0,1.4L4.1,7.8L0.3,4.2c-0.4-0.4-0.4-1,0-1.4c0.4-0.4,1-0.4,1.4,0L4,5l4.3-4.5C8.6,0.1,9.3,0.1,9.7,0.5z'
|
||||
);
|
||||
}
|
||||
&:indeterminate + .checkbox-element::after {
|
||||
clip-path: path('M0,4c0-0.6,0.4-1,1-1h8c0.6,0,1,0.4,1,1c0,0.6-0.4,1-1,1H1C0.4,5,0,4.6,0,4z');
|
||||
}
|
||||
&:disabled + .checkbox-element {
|
||||
box-shadow: none;
|
||||
background-color: var(--selector-disabled-BackgroundColor);
|
||||
border-color: var(--selector-disabled-BorderColor);
|
||||
|
||||
& + .checkbox-label {
|
||||
color: var(--global-disabled-TextColor);
|
||||
}
|
||||
}
|
||||
& + .checkbox-element.error {
|
||||
border-color: var(--border-color-global-error-border-color);
|
||||
}
|
||||
&:focus + .checkbox-element {
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
&:required + .checkbox-element + .checkbox-label::after {
|
||||
content: '*';
|
||||
position: relative;
|
||||
top: -0.125rem;
|
||||
left: 0.125rem;
|
||||
color: var(--global-error-TextColor);
|
||||
}
|
||||
}
|
||||
.checkbox-container {
|
||||
display: inline-flex;
|
||||
gap: var(--spacing-1_5);
|
||||
min-width: var(--spacing-2);
|
||||
min-height: var(--spacing-2);
|
||||
|
||||
&:not(.disabled) {
|
||||
cursor: pointer;
|
||||
|
||||
&:active .checkbox-element {
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
&:hover .checkbox-element {
|
||||
box-shadow: 0 0 0 4px var(--selector-hover-overlay-BackgroundColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
111
packages/ui/src/components/ModernRadioButton.svelte
Normal file
111
packages/ui/src/components/ModernRadioButton.svelte
Normal file
@ -0,0 +1,111 @@
|
||||
<script lang="ts">
|
||||
//
|
||||
// © 2023 Hardcore Engineering, Inc. All Rights Reserved.
|
||||
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
|
||||
//
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { generateId } from '@hcengineering/core'
|
||||
import { Label } from '../..'
|
||||
|
||||
export let id: string = generateId()
|
||||
export let group: any
|
||||
export let value: any
|
||||
export let label: string | undefined = undefined
|
||||
export let labelIntl: IntlString | undefined = undefined
|
||||
export let labelParams: Record<string, any> | undefined = undefined
|
||||
export let checked: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let error: boolean = false
|
||||
</script>
|
||||
|
||||
<label class="radioButton-container" class:disabled>
|
||||
<input type="radio" class="radioButton" {id} bind:group {value} {checked} {disabled} on:change />
|
||||
<div class="radioButton-element" class:disabled class:error />
|
||||
{#if label !== undefined || labelIntl !== undefined || $$slots.default !== undefined}
|
||||
<div class="radioButton-label">
|
||||
{#if labelIntl}<Label label={labelIntl} params={labelParams} />{:else}{label}{/if}
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
<slot name="after" />
|
||||
</label>
|
||||
|
||||
<style lang="scss">
|
||||
.radioButton-element {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
width: var(--spacing-2);
|
||||
height: var(--spacing-2);
|
||||
background-color: var(--selector-BackgroundColor);
|
||||
border: 1px solid var(--selector-BorderColor);
|
||||
border-radius: var(--large-BorderRadius);
|
||||
}
|
||||
.radioButton-label {
|
||||
color: var(--global-primary-TextColor);
|
||||
user-select: none;
|
||||
}
|
||||
.radioButton {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
|
||||
&:checked + .radioButton-element {
|
||||
background-color: var(--selector-active-BackgroundColor);
|
||||
border-color: var(--selector-active-BackgroundColor);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: var(--spacing-0_75);
|
||||
height: var(--spacing-0_75);
|
||||
background-color: var(--selector-IconColor);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
&:disabled + .radioButton-element {
|
||||
box-shadow: none;
|
||||
background-color: var(--selector-disabled-BackgroundColor);
|
||||
border-color: var(--selector-disabled-BorderColor);
|
||||
|
||||
&::after {
|
||||
background-color: var(--selector-disabled-IconColor);
|
||||
}
|
||||
& + .radioButton-label {
|
||||
color: var(--global-disabled-TextColor);
|
||||
}
|
||||
}
|
||||
& + .radioButton-element.error {
|
||||
border-color: var(--border-color-global-error-border-color);
|
||||
}
|
||||
&:focus + .radioButton-element {
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
.radioButton-container {
|
||||
display: inline-flex;
|
||||
gap: var(--spacing-2);
|
||||
min-width: var(--spacing-2);
|
||||
min-height: var(--spacing-2);
|
||||
|
||||
&:not(.disabled) {
|
||||
cursor: pointer;
|
||||
|
||||
&:active .radioButton-element {
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
&:hover .radioButton-element {
|
||||
box-shadow: 0 0 0 4px var(--selector-hover-overlay-BackgroundColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -76,6 +76,12 @@
|
||||
|
||||
$: document.body.style.cursor = drag ? 'all-scroll' : 'default'
|
||||
$: docSize = checkAdaptiveMatching($deviceInfo.size, 'md')
|
||||
$: isFullMobile =
|
||||
$deviceInfo.isMobile &&
|
||||
$deviceInfo.isPortrait &&
|
||||
['right', 'top', 'float', 'full', 'content', 'middle', 'centered', 'center', 'full-centered'].some(
|
||||
(el) => element === el
|
||||
)
|
||||
|
||||
function _update (result: any): void {
|
||||
if (onUpdate !== undefined) onUpdate(result)
|
||||
@ -100,7 +106,7 @@
|
||||
contentPanel: HTMLElement | undefined
|
||||
): void => {
|
||||
const device: DeviceOptions = $deviceInfo
|
||||
if ((fullSize || docSize) && (element === 'float' || element === 'centered')) {
|
||||
if (((fullSize || docSize) && (element === 'float' || element === 'centered')) || isFullMobile) {
|
||||
options = fitPopupElement(modalHTML, device, 'full', contentPanel, clientWidth, clientHeight)
|
||||
options.props.maxHeight = '100vh'
|
||||
if (!modalHTML.classList.contains('fullsize')) modalHTML.classList.add('fullsize')
|
||||
|
@ -158,6 +158,8 @@ export { default as HotkeyGroup } from './components/HotkeyGroup.svelte'
|
||||
export { default as ModernWizardDialog } from './components/wizard/ModernWizardDialog.svelte'
|
||||
export { default as ModernWizardBar } from './components/wizard/ModernWizardBar.svelte'
|
||||
export { default as ModernTab } from './components/ModernTab.svelte'
|
||||
export { default as ModernCheckbox } from './components/ModernCheckbox.svelte'
|
||||
export { default as ModernRadioButton } from './components/ModernRadioButton.svelte'
|
||||
|
||||
export { default as IconAdd } from './components/icons/Add.svelte'
|
||||
export { default as IconCircleAdd } from './components/icons/CircleAdd.svelte'
|
||||
|
@ -1,7 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||
<symbol id="application" viewBox="0 0 1024 1024">
|
||||
<path d="M904 512h-56c-4.4 0-8 3.6-8 8v320H184V184h320c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V520c0-4.4-3.6-8-8-8z" />
|
||||
<path d="M355.9 534.9L354 653.8c-.1 8.9 7.1 16.2 16 16.2h.4l118-2.9c2-.1 4-.9 5.4-2.3l415.9-415c3.1-3.1 3.1-8.2 0-11.3L785.4 114.3c-1.6-1.6-3.6-2.3-5.7-2.3s-4.1.8-5.7 2.3l-415.8 415a8.3 8.3 0 00-2.3 5.6zm63.5 23.6L779.7 199l45.2 45.1-360.5 359.7-45.7 1.1.7-46.4z" />
|
||||
<symbol id="application" viewBox="0 0 32 32">
|
||||
<path d="M22.9,23.4c-0.6,0-1,0.4-1,1v1.5c0,0.5-0.2,1.1-0.6,1.5c-0.4,0.4-0.9,0.6-1.5,0.6H6.1c-0.5,0-1.1-0.2-1.5-0.6C4.2,27,4,26.5,4,25.9V12.2c0-0.5,0.2-1.1,0.6-1.5c0.4-0.4,0.9-0.6,1.5-0.6h1.5c0.6,0,1-0.4,1-1s-0.4-1-1-1H6.1C5,8.1,4,8.5,3.2,9.3C2.4,10.1,2,11.1,2,12.2v13.8C2,27,2.4,28,3.2,28.8C4,29.6,5,30,6.1,30h13.8c1.1,0,2.1-0.4,2.9-1.2c0.8-0.8,1.2-1.8,1.2-2.9v-1.5C23.9,23.9,23.4,23.4,22.9,23.4z" />
|
||||
<path d="M30,6.2c0-1.1-0.4-2.2-1.2-3C28,2.4,26.9,2,25.8,2s-2.2,0.4-3,1.2l-2,2c0,0-0.1,0-0.1,0.1c0,0,0,0.1-0.1,0.1L9.9,16.1c-0.2,0.2-0.3,0.4-0.3,0.7v4.6c0,0.6,0.4,1,1,1h4.6c0.3,0,0.5-0.1,0.7-0.3l10.6-10.6c0,0,0.1,0,0.1-0.1c0,0,0-0.1,0.1-0.1l2-2C29.6,8.4,30,7.3,30,6.2z M14.8,20.4h-3.2v-3.2l9.7-9.7l3.1,3.1L14.8,20.4z M27.4,7.8l-1.4,1.4l-3.1-3.1l1.4-1.4c0.8-0.8,2.3-0.8,3.1,0c0.4,0.4,0.6,1,0.6,1.6S27.8,7.4,27.4,7.8z" />
|
||||
</symbol>
|
||||
<symbol id="survey" viewBox="0 0 24 24">
|
||||
<path d="M13,6h8c0.6,0,1-0.4,1-1s-0.4-1-1-1h-8c-0.6,0-1,0.4-1,1S12.4,6,13,6z" />
|
||||
<path d="M13,10h5c0.6,0,1-0.4,1-1s-0.4-1-1-1h-5c-0.6,0-1,0.4-1,1S12.4,10,13,10z" />
|
||||
<path d="M21,14h-8c-0.6,0-1,0.4-1,1s0.4,1,1,1h8c0.6,0,1-0.4,1-1S21.6,14,21,14z" />
|
||||
<path d="M18,18h-5c-0.6,0-1,0.4-1,1s0.4,1,1,1h5c0.6,0,1-0.4,1-1S18.6,18,18,18z" />
|
||||
<path d="M8,3H4C2.9,3,2,3.9,2,5v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2V5C10,3.9,9.1,3,8,3z M8,9H4V5h4V9z" />
|
||||
<path d="M8,13H4c-1.1,0-2,0.9-2,2v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4C10,13.9,9.1,13,8,13z M8,19H4v-4h4V19z" />
|
||||
</symbol>
|
||||
<symbol id="radio" viewBox="0 0 15 15">
|
||||
<path d="M7.5.877a6.623 6.623 0 100 13.246A6.623 6.623 0 007.5.877zM1.827 7.5a5.673 5.673 0 1111.346 0 5.673 5.673 0 01-11.346 0zm5.673 2a2 2 0 100-4 2 2 0 000 4z"/>
|
||||
@ -12,8 +20,11 @@
|
||||
<symbol id="textline" viewBox="0 0 24 24">
|
||||
<path d="M17 7h5v10h-5v2a1 1 0 001 1h2v2h-2.5c-.55 0-1.5-.45-1.5-1 0 .55-.95 1-1.5 1H12v-2h2a1 1 0 001-1V5a1 1 0 00-1-1h-2V2h2.5c.55 0 1.5.45 1.5 1 0-.55.95-1 1.5-1H20v2h-2a1 1 0 00-1 1v2M2 7h11v2H4v6h9v2H2V7m18 8V9h-3v6h3z" />
|
||||
</symbol>
|
||||
<symbol id="page" viewBox="0 0 24 24">
|
||||
<path d="M5 8v12h14V8H5zm0-2h14V4H5v2zm15 16H4a1 1 0 01-1-1V3a1 1 0 011-1h16a1 1 0 011 1v18a1 1 0 01-1 1zM7 10h4v4H7v-4zm0 6h10v2H7v-2zm6-5h4v2h-4v-2z" />
|
||||
<symbol id="poll" viewBox="0 0 24 24">
|
||||
<path d="M20.3,1.5H3.7c-1.2,0-2.2,1-2.2,2.2v16.7c0,1.2,0.9,2.2,2.2,2.2h16.7c1.3,0,2.2-0.9,2.2-2.2V3.7C22.5,2.4,21.6,1.5,20.3,1.5z M20.5,3.7v2.6H8.2V3.5h12.1C20.4,3.5,20.5,3.5,20.5,3.7z M3.7,3.5h2.6v2.8H3.5V3.7C3.5,3.6,3.6,3.5,3.7,3.5z M20.5,20.5c0,0-0.1,0-0.2,0H3.7c-0.2,0-0.2-0.1-0.2-0.2V8.2h17v12.1C20.5,20.4,20.5,20.5,20.5,20.5z" />
|
||||
<path d="M17.3,16.4H6.7c-0.6,0-1,0.4-1,1s0.4,1,1,1h10.6c0.6,0,1-0.4,1-1S17.8,16.4,17.3,16.4z" />
|
||||
<path d="M17.3,11.1h-4c-0.6,0-1,0.4-1,1s0.4,1,1,1h4c0.6,0,1-0.4,1-1S17.8,11.1,17.3,11.1z" />
|
||||
<path d="M6.7,14.5h2.6c0.6,0,1-0.4,1-1v-2.6c0-0.6-0.4-1-1-1H6.7c-0.6,0-1,0.4-1,1v2.6C5.7,14,6.2,14.5,6.7,14.5z M7.7,11.8h0.6v0.6H7.7V11.8z" />
|
||||
</symbol>
|
||||
<symbol id="asterisk" viewBox="0 0 24 24">
|
||||
<path d="M13 3v7.267l6.294-3.633 1 1.732-6.293 3.633 6.293 3.635-1 1.732L13 13.732V21h-2v-7.268l-6.294 3.634-1-1.732L9.999 12 3.706 8.366l1-1.732L11 10.267V3z" />
|
||||
@ -27,14 +38,18 @@
|
||||
<symbol id="submit" viewBox="0 0 32 32">
|
||||
<path d="M4 8C4 5.79086 5.79086 4 8 4H21C21.5523 4 22 4.44772 22 5C22 5.55228 21.5523 6 21 6H8C6.89543 6 6 6.89543 6 8V24C6 25.1046 6.89543 26 8 26H24C25.1046 26 26 25.1046 26 24V17C26 16.4477 26.4477 16 27 16C27.5523 16 28 16.4477 28 17V24C28 26.2091 26.2091 28 24 28H8C5.79086 28 4 26.2091 4 24V8ZM29.7071 6.29289C30.0976 6.68342 30.0976 7.31658 29.7071 7.70711L17.7071 19.7071C17.3166 20.0976 16.6834 20.0976 16.2929 19.7071L10.2929 13.7071C9.90237 13.3166 9.90237 12.6834 10.2929 12.2929C10.6834 11.9024 11.3166 11.9024 11.7071 12.2929L17 17.5858L28.2929 6.29289C28.6834 5.90237 29.3166 5.90237 29.7071 6.29289Z" />
|
||||
</symbol>
|
||||
<symbol id="validate-ok" viewBox="0 0 1024 1024">
|
||||
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z" />
|
||||
<symbol id="validate-ok" viewBox="0 0 24 24">
|
||||
<path d="M12,1.5C6.2,1.5,1.5,6.2,1.5,12c0,5.8,4.7,10.5,10.5,10.5c5.8,0,10.5-4.7,10.5-10.5C22.5,6.2,17.8,1.5,12,1.5z M12,20.5c-4.7,0-8.5-3.8-8.5-8.5c0-4.7,3.8-8.5,8.5-8.5c4.7,0,8.5,3.8,8.5,8.5C20.5,16.7,16.7,20.5,12,20.5z" />
|
||||
<path d="M14.5,9.2l-3.5,3.5l-1.4-1.4c-0.4-0.4-1-0.4-1.4,0c-0.4,0.4-0.4,1,0,1.4l2.1,2.1c0.2,0.2,0.4,0.3,0.7,0.3s0.5-0.1,0.7-0.3l4.2-4.2c0.4-0.4,0.4-1,0-1.4S14.9,8.8,14.5,9.2z" />
|
||||
</symbol>
|
||||
<symbol id="validate-fail" viewBox="0 0 24 24">
|
||||
<path d="M16.707 2.293A.996.996 0 0016 2H8a.996.996 0 00-.707.293l-5 5A.996.996 0 002 8v8c0 .266.105.52.293.707l5 5A.996.996 0 008 22h8c.266 0 .52-.105.707-.293l5-5A.996.996 0 0022 16V8a.996.996 0 00-.293-.707l-5-5zM13 17h-2v-2h2v2zm0-4h-2V7h2v6z" />
|
||||
<path d="M21.9,7.1l-5-5c-0.4-0.4-0.9-0.6-1.4-0.6h-7c-0.6,0-1,0.2-1.4,0.6l-5,5C1.7,7.5,1.5,8,1.5,8.5v7c0,0.6,0.2,1,0.6,1.4l5,5c0.4,0.4,0.9,0.6,1.4,0.6h7c0.6,0,1-0.2,1.4-0.6l5-5c0.4-0.4,0.6-0.9,0.6-1.4v-7C22.5,8,22.3,7.5,21.9,7.1z M20.5,15.5l-5,5l-7,0l-5-5l0-7l5-5l0,0l7,0l5,5L20.5,15.5z" />
|
||||
<path d="M12,13c0.6,0,1-0.4,1-1V7.8c0-0.6-0.4-1-1-1s-1,0.4-1,1V12C11,12.6,11.4,13,12,13z" />
|
||||
<path d="M12,15.2L12,15.2c-0.6,0-1,0.4-1,1s0.5,1,1,1s1-0.4,1-1S12.6,15.2,12,15.2z" />
|
||||
</symbol>
|
||||
<symbol id="info" viewBox="0 0 16 16">
|
||||
<path d="M7 4.75c0-.412.338-.75.75-.75h.5c.412 0 .75.338.75.75v.5c0 .412-.338.75-.75.75h-.5A.753.753 0 017 5.25v-.5zM10 12H6v-1h1V8H6V7h3v4h1z" />
|
||||
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm0 14.5a6.5 6.5 0 110-13 6.5 6.5 0 010 13z" />
|
||||
<symbol id="info" viewBox="0 0 24 24">
|
||||
<path d="M12,1.5C6.2,1.5,1.5,6.2,1.5,12c0,5.8,4.7,10.5,10.5,10.5c5.8,0,10.5-4.7,10.5-10.5C22.5,6.2,17.8,1.5,12,1.5z M12,20.5c-4.7,0-8.5-3.8-8.5-8.5c0-4.7,3.8-8.5,8.5-8.5c4.7,0,8.5,3.8,8.5,8.5C20.5,16.7,16.7,20.5,12,20.5z" />
|
||||
<path d="M12,8.8c0.6,0,1-0.4,1-1s-0.4-1-1-1h0c-0.6,0-1,0.4-1,1S11.5,8.8,12,8.8z" />
|
||||
<path d="M13.1,15.2L13.1,15.2L13,12c0-0.6-0.4-1-1-1h-1.1c-0.6,0-1,0.4-1,1s0.4,1,1,1H11v3.2c0,0.6,0.4,1,1,1h1.1c0.6,0,1-0.4,1-1S13.6,15.2,13.1,15.2z" />
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 6.3 KiB |
@ -20,12 +20,12 @@ const icons = require('../assets/icons.svg') as string // eslint-disable-line
|
||||
loadMetadata(survey.icon, {
|
||||
Application: `${icons}#application`,
|
||||
Info: `${icons}#info`,
|
||||
Poll: `${icons}#page`,
|
||||
Poll: `${icons}#poll`,
|
||||
Question: `${icons}#question`,
|
||||
QuestionKindString: `${icons}#textline`,
|
||||
QuestionKindOption: `${icons}#radio`,
|
||||
QuestionKindOptions: `${icons}#checkbox`,
|
||||
Survey: `${icons}#application`,
|
||||
Survey: `${icons}#survey`,
|
||||
Submit: `${icons}#submit`,
|
||||
QuestionIsMandatory: `${icons}#asterisk`,
|
||||
QuestionHasCustomOption: `${icons}#star`,
|
||||
|
@ -60,7 +60,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="antiSection">
|
||||
<div class="antiSection flex-gap-4">
|
||||
{#if hasText(object.prompt)}
|
||||
<div class="antiSection-header">
|
||||
<span class="antiSection-header__title">
|
||||
@ -70,21 +70,13 @@
|
||||
{/if}
|
||||
{#each object.questions ?? [] as question, index}
|
||||
{#if isQuestionValid(question)}
|
||||
<div class="question">
|
||||
<PollQuestion
|
||||
bind:this={questionNodes[index]}
|
||||
bind:isAnswered={isAnswered[index]}
|
||||
readonly={readonly || object.isCompleted}
|
||||
on:answered={saveAnswers}
|
||||
{question}
|
||||
/>
|
||||
</div>
|
||||
<PollQuestion
|
||||
bind:this={questionNodes[index]}
|
||||
bind:isAnswered={isAnswered[index]}
|
||||
readonly={readonly || object.isCompleted}
|
||||
on:answered={saveAnswers}
|
||||
{question}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.question {
|
||||
margin-top: 1.25em;
|
||||
}
|
||||
</style>
|
||||
|
@ -18,14 +18,14 @@
|
||||
import { MessageBox, getClient } from '@hcengineering/presentation'
|
||||
import { Question, QuestionKind, Survey } from '@hcengineering/survey'
|
||||
import {
|
||||
Button,
|
||||
EditBox,
|
||||
Icon,
|
||||
IconDelete,
|
||||
SelectPopup,
|
||||
eventToHTMLElement,
|
||||
showPopup,
|
||||
tooltip
|
||||
tooltip,
|
||||
ButtonIcon
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import survey from '../plugin'
|
||||
@ -37,11 +37,14 @@
|
||||
export let index: number
|
||||
export let readonly: boolean = false
|
||||
|
||||
let editQuestion: EditBox
|
||||
let hovered: boolean = false
|
||||
|
||||
$: question = parent?.questions?.[index] as Question
|
||||
$: options = question?.options ?? []
|
||||
$: questionIcon =
|
||||
question === undefined
|
||||
? undefined
|
||||
? survey.icon.Question
|
||||
: question.kind === QuestionKind.OPTIONS
|
||||
? survey.icon.QuestionKindOptions
|
||||
: question.kind === QuestionKind.OPTION
|
||||
@ -134,6 +137,7 @@
|
||||
}
|
||||
|
||||
function showQuestionParams (ev: MouseEvent): void {
|
||||
hovered = true
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
@ -215,11 +219,13 @@
|
||||
console.error('Unknown command id', id)
|
||||
}
|
||||
}
|
||||
hovered = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function showOptionParams (ev: MouseEvent, index: number): void {
|
||||
hovered = true
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
@ -245,6 +251,7 @@
|
||||
console.error('Unknown command id', id)
|
||||
}
|
||||
}
|
||||
hovered = false
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -335,93 +342,105 @@
|
||||
isRootDragging = false
|
||||
dispatch('dragEnd')
|
||||
}
|
||||
|
||||
const focusQuestion = (): void => {
|
||||
editQuestion.focusInput()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="root" bind:this={rootElement} class:is-dragged={isRootDragging}>
|
||||
<div class="header">
|
||||
<div
|
||||
bind:this={rootElement}
|
||||
class="question-container flex-col flex-gap-2"
|
||||
class:is-dragged={isRootDragging}
|
||||
class:hovered
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="flex-row-center flex-gap-3 text-base pr-2" on:click={focusQuestion}>
|
||||
{#if question === undefined}
|
||||
<Button noFocus={true} icon={survey.icon.Question} />
|
||||
<div class="text">
|
||||
<EditBox placeholder={survey.string.QuestionPlaceholder} bind:value={newQuestion} on:change={createQuestion} />
|
||||
</div>
|
||||
<ButtonIcon size={'small'} disabled icon={survey.icon.Question} />
|
||||
<EditBox
|
||||
bind:this={editQuestion}
|
||||
kind={'editbox'}
|
||||
placeholder={survey.string.QuestionPlaceholder}
|
||||
bind:value={newQuestion}
|
||||
on:change={createQuestion}
|
||||
/>
|
||||
{:else}
|
||||
<div role="presentation" draggable={!readonly} on:dragstart={rootDragStart} on:dragend={rootDragEnd}>
|
||||
<Button disabled={readonly} icon={questionIcon} on:click={showQuestionParams} />
|
||||
</div>
|
||||
<div class="text">
|
||||
<EditBox
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.QuestionPlaceholderEmpty}
|
||||
bind:value={question.name}
|
||||
on:change={changeName}
|
||||
/>
|
||||
{#if question.hasCustomOption && question.kind !== QuestionKind.STRING}
|
||||
<span class="question-param-icon" use:tooltip={{ label: survey.string.QuestionTooltipCustomOption }}>
|
||||
<Icon icon={survey.icon.QuestionHasCustomOption} size="medium" fill="var(--theme-won-color)" />
|
||||
</span>
|
||||
{/if}
|
||||
{#if question.isMandatory}
|
||||
<span class="question-param-icon" use:tooltip={{ label: survey.string.QuestionTooltipMandatory }}>
|
||||
<Icon icon={survey.icon.QuestionIsMandatory} size="medium" fill="var(--theme-urgent-color)" />
|
||||
</span>
|
||||
{/if}
|
||||
<ButtonIcon size={'small'} disabled={readonly} icon={questionIcon} on:click={showQuestionParams} />
|
||||
</div>
|
||||
<EditBox
|
||||
bind:this={editQuestion}
|
||||
kind={'editbox'}
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.QuestionPlaceholderEmpty}
|
||||
bind:value={question.name}
|
||||
on:change={changeName}
|
||||
/>
|
||||
{#if question.hasCustomOption && question.kind !== QuestionKind.STRING}
|
||||
<div class="flex-no-shrink" use:tooltip={{ label: survey.string.QuestionTooltipCustomOption }}>
|
||||
<Icon icon={survey.icon.QuestionHasCustomOption} size={'small'} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if question.isMandatory}
|
||||
<div class="flex-no-shrink" use:tooltip={{ label: survey.string.QuestionTooltipMandatory }}>
|
||||
<Icon icon={survey.icon.QuestionIsMandatory} size={'small'} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if question !== undefined && question.kind !== QuestionKind.STRING}
|
||||
<div>
|
||||
{#each options as option, index (index)}
|
||||
{#each options as option, index (index)}
|
||||
<div
|
||||
class="flex-row-center flex-gap-3 option"
|
||||
role="listitem"
|
||||
bind:this={draggableElements[index]}
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, index)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, index)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:is-dragged={index === draggedIndex}
|
||||
class:dragged-over={draggedIndex !== undefined &&
|
||||
draggedOverIndex === index &&
|
||||
draggedOverIndex !== draggedIndex &&
|
||||
draggedOverIndex !== draggedIndex + 1}
|
||||
>
|
||||
<div
|
||||
class="option"
|
||||
role="listitem"
|
||||
bind:this={draggableElements[index]}
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, index)
|
||||
role="presentation"
|
||||
draggable={!readonly}
|
||||
on:dragstart={(ev) => {
|
||||
dragStart(ev, index)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, index)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:is-dragged={index === draggedIndex}
|
||||
class:dragged-over={draggedIndex !== undefined &&
|
||||
draggedOverIndex === index &&
|
||||
draggedOverIndex !== draggedIndex &&
|
||||
draggedOverIndex !== draggedIndex + 1}
|
||||
on:dragend={dragEnd}
|
||||
>
|
||||
<div
|
||||
role="presentation"
|
||||
draggable={!readonly}
|
||||
on:dragstart={(ev) => {
|
||||
dragStart(ev, index)
|
||||
<ButtonIcon
|
||||
disabled={readonly}
|
||||
icon={questionIcon}
|
||||
iconSize={'x-small'}
|
||||
kind={'tertiary'}
|
||||
size={'extra-small'}
|
||||
on:click={(ev) => {
|
||||
showOptionParams(ev, index)
|
||||
}}
|
||||
on:dragend={dragEnd}
|
||||
>
|
||||
<Button
|
||||
disabled={readonly}
|
||||
icon={questionIcon}
|
||||
kind="list"
|
||||
size="small"
|
||||
on:click={(ev) => {
|
||||
showOptionParams(ev, index)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="text">
|
||||
<EditBox
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.QuestionPlaceholderOption}
|
||||
bind:value={options[index]}
|
||||
on:change={async () => {
|
||||
await changeOption(index)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<EditBox
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.QuestionPlaceholderOption}
|
||||
bind:value={options[index]}
|
||||
on:change={async () => {
|
||||
await changeOption(index)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{#if !readonly}
|
||||
<div
|
||||
class="option"
|
||||
class="flex-row-center flex-gap-3 option"
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, options.length)
|
||||
@ -432,54 +451,35 @@
|
||||
on:drop={dragDrop}
|
||||
class:dragged-over={draggedOverIndex === options.length && draggedIndex !== options.length - 1}
|
||||
>
|
||||
<Button noFocus={true} icon={survey.icon.Question} kind="list" size="small" />
|
||||
<div class="text">
|
||||
<EditBox placeholder={survey.string.QuestionPlaceholderOption} bind:value={newOption} on:change={addOption} />
|
||||
</div>
|
||||
<ButtonIcon disabled icon={survey.icon.Question} iconSize={'x-small'} kind={'tertiary'} size={'extra-small'} />
|
||||
<EditBox placeholder={survey.string.QuestionPlaceholderOption} bind:value={newOption} on:change={addOption} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
font-size: 1.05rem;
|
||||
margin-top: 0.5em;
|
||||
border-radius: var(--medium-BorderRadius);
|
||||
padding: 0.5em;
|
||||
.question-container {
|
||||
padding: var(--spacing-1);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
transition: opacity 0.1s ease-in;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--global-ui-hover-highlight-BackgroundColor);
|
||||
background-color: var(--theme-popup-color); // var(--global-ui-hover-highlight-BackgroundColor);
|
||||
}
|
||||
&.hovered,
|
||||
&:focus-within {
|
||||
background-color: var(--theme-list-row-color);
|
||||
}
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
.text {
|
||||
font-size: 0.95em;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
}
|
||||
.option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 2em;
|
||||
padding-top: 0.25em;
|
||||
padding-bottom: 0.25em;
|
||||
padding: var(--spacing-0_5) var(--spacing-0_5) var(--spacing-0_5) var(--spacing-5_5);
|
||||
}
|
||||
.is-dragged {
|
||||
opacity: 0.2;
|
||||
transition: opacity 0.1s ease-in;
|
||||
}
|
||||
.dragged-over {
|
||||
transition: box-shadow 0.1s ease-in;
|
||||
box-shadow: 0 -3px 0 0 var(--primary-button-outline);
|
||||
}
|
||||
.question-param-icon {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
</style>
|
||||
|
@ -17,9 +17,10 @@
|
||||
<script lang="ts">
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Survey } from '@hcengineering/survey'
|
||||
import { EditBox, FocusHandler, Label, createFocusManager } from '@hcengineering/ui'
|
||||
import { EditBox, FocusHandler, Label, createFocusManager, Icon } from '@hcengineering/ui'
|
||||
import EditQuestion from './EditQuestion.svelte'
|
||||
import survey from '../plugin'
|
||||
import IconQuestion from './icons/Question.svelte'
|
||||
|
||||
const manager = createFocusManager()
|
||||
const client = getClient()
|
||||
@ -87,85 +88,82 @@
|
||||
<FocusHandler {manager} />
|
||||
|
||||
{#if object !== undefined}
|
||||
<div class="flex-grow flex-col">
|
||||
<div class="name">
|
||||
<EditBox disabled={readonly} placeholder={survey.string.Name} bind:value={object.name} on:change={nameChange} />
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<EditBox
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.PromptPlaceholder}
|
||||
bind:value={object.prompt}
|
||||
on:change={promptChange}
|
||||
/>
|
||||
</div>
|
||||
<div class="antiSection">
|
||||
<div class="antiSection-header">
|
||||
<span class="antiSection-header__title">
|
||||
<Label label={survey.string.Questions} />
|
||||
</span>
|
||||
<div class="flex-row-center flex-no-shrink step-tb-6">
|
||||
<EditBox
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.Name}
|
||||
bind:value={object.name}
|
||||
kind={'large-style'}
|
||||
on:change={nameChange}
|
||||
/>
|
||||
</div>
|
||||
<div class="step-tb-6">
|
||||
<EditBox
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.PromptPlaceholder}
|
||||
bind:value={object.prompt}
|
||||
on:change={promptChange}
|
||||
/>
|
||||
</div>
|
||||
<div class="antiSection step-tb-6">
|
||||
<div class="antiSection-header mb-3">
|
||||
<div class="antiSection-header__icon">
|
||||
<Icon icon={IconQuestion} size={'small'} />
|
||||
</div>
|
||||
{#each questions as question, index}
|
||||
<div
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, index)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, index)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:dragged-over={draggedIndex !== undefined &&
|
||||
draggedOverIndex === index &&
|
||||
draggedOverIndex !== draggedIndex &&
|
||||
draggedOverIndex !== draggedIndex + 1}
|
||||
>
|
||||
<EditQuestion
|
||||
{index}
|
||||
{readonly}
|
||||
parent={object}
|
||||
on:dragStart={() => {
|
||||
draggedIndex = index
|
||||
}}
|
||||
on:dragEnd={() => {
|
||||
draggedIndex = undefined
|
||||
draggedOverIndex = undefined
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{#if !readonly}
|
||||
<div
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, questions.length)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, questions.length)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:dragged-over={draggedOverIndex === questions.length && draggedIndex !== questions.length - 1}
|
||||
>
|
||||
<EditQuestion parent={object} index={-1} />
|
||||
</div>
|
||||
{/if}
|
||||
<span class="antiSection-header__title">
|
||||
<Label label={survey.string.Questions} />
|
||||
</span>
|
||||
</div>
|
||||
{#each questions as question, index}
|
||||
<div
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, index)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, index)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:dragged-over={draggedIndex !== undefined &&
|
||||
draggedOverIndex === index &&
|
||||
draggedOverIndex !== draggedIndex &&
|
||||
draggedOverIndex !== draggedIndex + 1}
|
||||
>
|
||||
<EditQuestion
|
||||
{index}
|
||||
{readonly}
|
||||
parent={object}
|
||||
on:dragStart={() => {
|
||||
draggedIndex = index
|
||||
}}
|
||||
on:dragEnd={() => {
|
||||
draggedIndex = undefined
|
||||
draggedOverIndex = undefined
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
{#if !readonly}
|
||||
<div
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, questions.length)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, questions.length)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:dragged-over={draggedOverIndex === questions.length && draggedIndex !== questions.length - 1}
|
||||
>
|
||||
<EditQuestion parent={object} index={-1} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.name {
|
||||
font-weight: 500;
|
||||
font-size: 1.25rem;
|
||||
color: var(--caption-color);
|
||||
display: flex;
|
||||
}
|
||||
.prompt {
|
||||
font-weight: 400;
|
||||
font-size: 1.05rem;
|
||||
color: var(--caption-color);
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
div[role='listitem'] + div[role='listitem'] {
|
||||
margin-top: var(--spacing-1);
|
||||
}
|
||||
.dragged-over {
|
||||
transition: box-shadow 0.1s ease-in;
|
||||
|
@ -19,9 +19,9 @@
|
||||
import { Panel } from '@hcengineering/panel'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Survey } from '@hcengineering/survey'
|
||||
import { Button, Icon, IconMoreH, Label, tooltip } from '@hcengineering/ui'
|
||||
import { Button, Icon, IconMoreH, Label, tooltip, Breadcrumb } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { DocNavLink, showMenu } from '@hcengineering/view-resources'
|
||||
import { showMenu } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import EditSurvey from './EditSurvey.svelte'
|
||||
import EditPoll from './EditPoll.svelte'
|
||||
@ -53,7 +53,7 @@
|
||||
<Panel
|
||||
isHeader={false}
|
||||
isSub={false}
|
||||
isAside={true}
|
||||
isAside={false}
|
||||
{embedded}
|
||||
{object}
|
||||
on:open
|
||||
@ -63,22 +63,20 @@
|
||||
withoutInput={readonly}
|
||||
>
|
||||
<svelte:fragment slot="title">
|
||||
<DocNavLink noUnderline {object}>
|
||||
<div class="title">{object.name}</div>
|
||||
</DocNavLink>
|
||||
<Breadcrumb icon={survey.icon.Survey} title={object.name} size={'large'} isCurrent />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
{#if !readonly}
|
||||
{#if preview}
|
||||
{#if canSubmit}
|
||||
<span use:tooltip={{ label: survey.string.ValidateOk }}>
|
||||
<Icon size="x-large" icon={survey.icon.ValidateOk} fill="var(--theme-won-color)" />
|
||||
</span>
|
||||
<div use:tooltip={{ label: survey.string.ValidateOk }}>
|
||||
<Icon size="x-large" icon={survey.icon.ValidateOk} fill="var(--positive-button-default)" />
|
||||
</div>
|
||||
{:else}
|
||||
<span use:tooltip={{ label: survey.string.ValidateFail }}>
|
||||
<Icon size="x-large" icon={survey.icon.ValidateFail} iconProps={{ opacity: 0.75 }} />
|
||||
</span>
|
||||
<div use:tooltip={{ label: survey.string.ValidateFail }}>
|
||||
<Icon size="x-large" icon={survey.icon.ValidateFail} fill="var(--theme-trans-color)" />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
<Button
|
||||
@ -102,9 +100,9 @@
|
||||
<div class="flex-col flex-grow flex-no-shrink">
|
||||
{#if preview}
|
||||
{#if poll !== undefined}
|
||||
<div class="antiSection-empty solid flex-row mt-3">
|
||||
<Icon icon={survey.icon.Info} size="large" />
|
||||
<span class="content-dark-color" style="margin-left:1em">
|
||||
<div class="antiSection-empty solid mb-8">
|
||||
<Icon icon={survey.icon.Info} size={'large'} />
|
||||
<span class="content-dark-color text-balance" style="margin-left:1em">
|
||||
<Label label={survey.string.ValidateInfo} />
|
||||
</span>
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { generateId } from '@hcengineering/core'
|
||||
import { EditBox, Icon, Label, tooltip } from '@hcengineering/ui'
|
||||
import { EditBox, Icon, Label, tooltip, ModernCheckbox, ModernRadioButton } from '@hcengineering/ui'
|
||||
import { AnsweredQuestion, QuestionKind } from '@hcengineering/survey'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import survey from '../plugin'
|
||||
@ -133,110 +133,105 @@
|
||||
}
|
||||
return []
|
||||
}
|
||||
$: console.log('[!!!] question: ', question)
|
||||
</script>
|
||||
|
||||
<div class="antiSection">
|
||||
<div class="antiSection-header">
|
||||
<span class="antiSection-header__title" style="display:flex">
|
||||
{question.name}
|
||||
{#if question.isMandatory && !readonly}
|
||||
<span style="margin-left:0.25em" use:tooltip={{ label: survey.string.QuestionTooltipMandatory }}>
|
||||
<Icon icon={survey.icon.QuestionIsMandatory} size="tiny" fill="var(--theme-urgent-color)" />
|
||||
</span>
|
||||
{/if}
|
||||
</span>
|
||||
<div class="question-answer-container flex-col flex-gap-3">
|
||||
<div class="flex-row-center flex-gap-1 flex-no-shrink">
|
||||
<span class="text-lg caption-color font-medium">{question.name}</span>
|
||||
{#if question.isMandatory && !readonly}
|
||||
<div
|
||||
class="flex-no-shrink"
|
||||
style:transform={'translateY(-0.25rem)'}
|
||||
use:tooltip={{ label: survey.string.QuestionTooltipMandatory }}
|
||||
>
|
||||
<Icon icon={survey.icon.QuestionIsMandatory} size={'xx-small'} fill="var(--theme-urgent-color)" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if readonly}
|
||||
{#each getReadonlyAnswers() as answer}
|
||||
{#if answer}
|
||||
<div class="answer">{answer}</div>
|
||||
<div class="pl-6">{answer}</div>
|
||||
{:else}
|
||||
<div class="answer empty">
|
||||
<div class="pl-6 content-halfcontent-color">
|
||||
<Label label={survey.string.NoAnswer} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{:else if question.kind === QuestionKind.OPTION}
|
||||
{#each question.options ?? [] as option, i}
|
||||
<div class="option">
|
||||
<input type="radio" id={`${id}-${i}`} value={i} bind:group={selectedOption} on:change={optionChange} />
|
||||
<label class="option__label" for={`${id}-${i}`}>
|
||||
{option}
|
||||
</label>
|
||||
</div>
|
||||
{/each}
|
||||
{#if question.hasCustomOption}
|
||||
<div class="option">
|
||||
<input
|
||||
type="radio"
|
||||
id={`${id}-custom`}
|
||||
value={customOption}
|
||||
<div class="flex-col flex-gap-2 px-6">
|
||||
{#each question.options ?? [] as option, i}
|
||||
<ModernRadioButton
|
||||
id={`${id}-${i}`}
|
||||
value={i}
|
||||
label={option}
|
||||
bind:group={selectedOption}
|
||||
on:change={optionChange}
|
||||
/>
|
||||
{/each}
|
||||
{#if question.hasCustomOption}
|
||||
<ModernRadioButton
|
||||
id={`${id}-custom`}
|
||||
value={customOption}
|
||||
labelIntl={survey.string.AnswerCustomOption}
|
||||
bind:group={selectedOption}
|
||||
on:change={optionChange}
|
||||
/>
|
||||
<label class="option__label" for={`${id}-custom`}>
|
||||
<Label label={survey.string.AnswerCustomOption} />
|
||||
</label>
|
||||
{#if selectedOption === customOption}
|
||||
<div class="option__custom">
|
||||
<EditBox bind:value={answer} on:change={answerChange} placeholder={survey.string.AnswerPlaceholder} />
|
||||
<div class="pl-6">
|
||||
<EditBox
|
||||
kind={'ghost-large'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
focusable
|
||||
autoFocus
|
||||
on:change={answerChange}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{:else if question.kind === QuestionKind.OPTIONS}
|
||||
{#each question.options ?? [] as option, i}
|
||||
<div class="option">
|
||||
<input type="checkbox" id={`${id}-${i}`} bind:checked={selectedOptions[i]} on:change={optionsChange} />
|
||||
<label class="option__label" for={`${id}-${i}`}>
|
||||
{option}
|
||||
</label>
|
||||
</div>
|
||||
{/each}
|
||||
{#if question.hasCustomOption}
|
||||
<div class="option">
|
||||
<input
|
||||
type="checkbox"
|
||||
<div class="flex-col flex-gap-2 px-6">
|
||||
{#each question.options ?? [] as option, i}
|
||||
<ModernCheckbox id={`${id}-${i}`} label={option} bind:checked={selectedOptions[i]} on:change={optionsChange} />
|
||||
{/each}
|
||||
{#if question.hasCustomOption}
|
||||
<ModernCheckbox
|
||||
id={`${id}-custom`}
|
||||
labelIntl={survey.string.AnswerCustomOption}
|
||||
bind:checked={selectedOptions[customOption]}
|
||||
on:change={optionsChange}
|
||||
/>
|
||||
<label class="option__label" for={`${id}-custom`}>
|
||||
<Label label={survey.string.AnswerCustomOption} />
|
||||
</label>
|
||||
{#if selectedOptions[customOption]}
|
||||
<div class="option__custom">
|
||||
<EditBox bind:value={answer} on:change={answerChange} placeholder={survey.string.AnswerPlaceholder} />
|
||||
<div class="pl-6">
|
||||
<EditBox
|
||||
kind={'ghost-large'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
focusable
|
||||
autoFocus
|
||||
on:change={answerChange}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="option">
|
||||
<EditBox bind:value={answer} on:change={answerChange} placeholder={survey.string.AnswerPlaceholder} />
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<EditBox
|
||||
kind={'ghost-large'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
focusable
|
||||
on:change={answerChange}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.option {
|
||||
margin-left: 1em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.option__label {
|
||||
cursor: pointer;
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
.option__custom {
|
||||
margin-left: 2em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.answer {
|
||||
margin-left: 2em;
|
||||
margin-top: 0.5em;
|
||||
|
||||
&.empty {
|
||||
opacity: 0.7;
|
||||
}
|
||||
:global(.question-answer-container + .question-answer-container) {
|
||||
padding-top: var(--spacing-2);
|
||||
border-top: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M12,22.5C6.2,22.5,1.5,17.8,1.5,12C1.5,6.2,6.2,1.5,12,1.5c5.8,0,10.5,4.7,10.5,10.5C22.5,17.8,17.8,22.5,12,22.5z M12,3.5c-4.7,0-8.5,3.8-8.5,8.5c0,4.7,3.8,8.5,8.5,8.5c4.7,0,8.5-3.8,8.5-8.5C20.5,7.3,16.7,3.5,12,3.5z"
|
||||
/>
|
||||
<path d="M12,18.3c-0.6,0-1-0.4-1-1s0.4-1,1-1s1,0.4,1,1v0C13,17.8,12.6,18.3,12,18.3z" />
|
||||
<path
|
||||
d="M12,14.6c-0.5,0-1-0.4-1-0.9c0-0.6,0.1-1.1,0.4-1.6c0.3-0.5,0.8-0.8,1.3-1c0.2-0.1,0.5-0.2,0.6-0.4c0.2-0.2,0.3-0.4,0.4-0.7c0.1-0.3,0.1-0.5,0-0.8c0-0.3-0.2-0.5-0.3-0.7c-0.2-0.2-0.4-0.4-0.6-0.5c-0.2-0.1-0.5-0.1-0.8-0.2c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.1-0.5,0.3-0.6,0.5c-0.3,0.4-1,0.5-1.4,0.2c-0.4-0.3-0.5-1-0.2-1.4c0.3-0.5,0.8-0.8,1.3-1.1c0.5-0.3,1.1-0.4,1.7-0.4c0.6,0,1.2,0.1,1.7,0.4c0.5,0.3,1,0.6,1.3,1.1c0.3,0.5,0.6,1,0.7,1.6c0.1,0.6,0.1,1.2-0.1,1.7c-0.2,0.6-0.5,1.1-0.8,1.5c-0.4,0.4-0.9,0.8-1.4,1c-0.1,0.1-0.2,0.1-0.3,0.2C13,13.3,13,13.4,13,13.5C13,14.1,12.6,14.5,12,14.6C12,14.6,12,14.6,12,14.6z"
|
||||
/>
|
||||
</svg>
|
@ -191,7 +191,10 @@
|
||||
d="M16.1,14.5c-0.3-0.3-0.8-0.3-1.1,0l-2.3,2.3V10c0-0.4-0.3-0.8-0.8-0.8s-0.8,0.3-0.8,0.8v6.7l-2.2-2.2 c-0.3-0.3-0.8-0.3-1.1,0c-0.3,0.3-0.3,0.8,0,1.1l3.5,3.5c0.3,0.3,0.8,0.3,1.1,0l3.6-3.5C16.4,15.2,16.4,14.8,16.1,14.5z"
|
||||
/>
|
||||
</symbol>
|
||||
<symbol id="note" viewBox="0 0 256 256">
|
||||
<rect width="256" height="256" fill="none"></rect><line x1="96" x2="160" y1="96" y2="96" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"></line><line x1="96" x2="160" y1="128" y2="128" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"></line><line x1="96" x2="128" y1="160" y2="160" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"></line><path fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" d="M156.68629,216H48a8,8,0,0,1-8-8V48a8,8,0,0,1,8-8H208a8,8,0,0,1,8,8V156.68629a8,8,0,0,1-2.34315,5.65686l-51.3137,51.3137A8,8,0,0,1,156.68629,216Z"></path><polyline fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" points="215.277 159.992 160 159.992 160 215.272"></polyline>
|
||||
<symbol id="note" viewBox="0 0 32 32">
|
||||
<path d="M28.1,5.8c0-2.1-1.7-3.8-3.8-3.8H7.6C5.6,2,3.9,3.7,3.9,5.8v20.4c0,2.1,1.7,3.8,3.8,3.8h12.1c0.1,0,0.3,0,0.4-0.1c0.1-0.1,0.2-0.1,0.3-0.2l7.4-7.4c0.1-0.1,0.2-0.2,0.2-0.3c0.1-0.1,0.1-0.3,0.1-0.4V5.8z M5.9,26.2V5.8c0-1,0.8-1.8,1.8-1.8h16.7c1,0,1.8,0.8,1.8,1.8v14.8h-3.6c-2.1,0-3.8,1.7-3.8,3.8V28H7.6C6.7,28,5.9,27.2,5.9,26.2z M24.7,22.6l-4,4v-2.2c0-1,0.8-1.8,1.8-1.8H24.7z" />
|
||||
<path d="M9.5,11.4h13c0.6,0,1-0.4,1-1s-0.4-1-1-1h-13c-0.6,0-1,0.4-1,1S8.9,11.4,9.5,11.4z" />
|
||||
<path d="M9.5,17h13c0.6,0,1-0.4,1-1s-0.4-1-1-1h-13c-0.6,0-1,0.4-1,1S8.9,17,9.5,17z" />
|
||||
<path d="M15.1,20.6H9.5c-0.6,0-1,0.4-1,1s0.4,1,1,1h5.6c0.6,0,1-0.4,1-1S15.6,20.6,15.1,20.6z" />
|
||||
</symbol>
|
||||
</svg>
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
@ -187,4 +187,9 @@
|
||||
<path d="M19.0615 8.60896C20.0321 9.011 20.914 9.60028 21.6569 10.3431L10.3431 21.6569C9.60028 20.914 9.011 20.0321 8.60896 19.0615C8.20693 18.0909 8 17.0506 8 16C8 14.9494 8.20693 13.9091 8.60896 12.9385C9.011 11.9679 9.60028 11.086 10.3431 10.3431C11.086 9.60028 11.9679 9.011 12.9385 8.60896C13.9091 8.20693 14.9494 8 16 8C17.0506 8 18.0909 8.20693 19.0615 8.60896Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30 16C30 23.732 23.732 30 16 30C8.26801 30 2 23.732 2 16C2 8.26801 8.26801 2 16 2C23.732 2 30 8.26801 30 16ZM28 16C28 22.6274 22.6274 28 16 28C9.37258 28 4 22.6274 4 16C4 9.37258 9.37258 4 16 4C22.6274 4 28 9.37258 28 16Z" />
|
||||
</symbol>
|
||||
<symbol id="labels" viewBox="0 0 24 24">
|
||||
<path d="M17.2,13.9c0-0.4-0.1-0.8-0.2-1.2c-0.2-0.4-0.4-0.7-0.7-1L9.8,5.3C9.3,4.7,8.5,4.4,7.6,4.4h-3C3.8,4.4,3,4.7,2.4,5.3C1.8,5.9,1.5,6.7,1.5,7.5v3c0,0.8,0.3,1.6,0.9,2.2l6.5,6.5c0.3,0.3,0.6,0.5,1,0.7c0.4,0.2,0.8,0.2,1.2,0.2s0.8-0.1,1.2-0.2c0.4-0.2,0.7-0.4,1-0.7l3-3c0.3-0.3,0.5-0.6,0.7-1C17.1,14.8,17.2,14.4,17.2,13.9z M15.1,14.4c-0.1,0.1-0.1,0.3-0.2,0.4l-3,3c-0.1,0.1-0.2,0.2-0.4,0.2c-0.3,0.1-0.6,0.1-0.9,0c-0.1-0.1-0.3-0.1-0.4-0.2l-6.5-6.5c-0.2-0.2-0.3-0.5-0.3-0.8v-3c0-0.3,0.1-0.6,0.3-0.8C4,6.5,4.3,6.4,4.6,6.4h3c0.3,0,0.6,0.1,0.8,0.3l6.5,6.5c0.1,0.1,0.2,0.2,0.2,0.4c0.1,0.1,0.1,0.3,0.1,0.4C15.2,14.1,15.2,14.2,15.1,14.4z" />
|
||||
<path d="M22.3,12.7c-0.2-0.4-0.4-0.7-0.7-1l-7.5-7.5c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l7.5,7.5c0.1,0.1,0.2,0.2,0.2,0.4c0.1,0.1,0.1,0.3,0.1,0.4s0,0.3-0.1,0.4c-0.1,0.1-0.1,0.3-0.2,0.4l-3,3c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3l3-3c0.3-0.3,0.5-0.6,0.7-1c0.2-0.4,0.2-0.8,0.2-1.2S22.4,13.1,22.3,12.7z" />
|
||||
<path d="M5.7,7.5c-0.6,0-1,0.4-1,1s0.4,1,1,1h0c0.6,0,1-0.4,1-1S6.2,7.5,5.7,7.5z" />
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 35 KiB |
@ -33,7 +33,7 @@ loadMetadata(tracker.icon, {
|
||||
Magnifier: `${icons}#magnifier`,
|
||||
Home: `${icons}#home`,
|
||||
RedCircle: `${icons}#red-circle`,
|
||||
Labels: `${icons}#priority-nopriority`, // TODO: add icon
|
||||
Labels: `${icons}#labels`,
|
||||
DueDate: `${icons}#dueDate`, // TODO: add icon
|
||||
Parent: `${icons}#parent-issue`, // TODO: add icon
|
||||
Milestone: `${icons}#milestone`,
|
||||
|
Loading…
Reference in New Issue
Block a user