Create Help Center (#2313)

Signed-off-by: muhtimur <timur.mukhamedishin@xored.com>
This commit is contained in:
Timur Mukhamedishin 2022-10-20 09:45:57 +07:00 committed by GitHub
parent 25a5c354bb
commit 2c1f088735
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 374 additions and 20 deletions

View File

@ -6,6 +6,10 @@ Tracker:
- Basic sprints - Basic sprints
Workbench:
- Help Center
## 0.6.31 ## 0.6.31
Core: Core:

View File

@ -200,20 +200,21 @@ export function createModel (builder: Builder): void {
}, },
setting.ids.EnumSetting setting.ids.EnumSetting
) )
builder.createDoc( // Currently remove Support item from settings
setting.class.SettingsCategory, // builder.createDoc(
core.space.Model, // setting.class.SettingsCategory,
{ // core.space.Model,
name: 'support', // {
label: setting.string.Support, // name: 'support',
icon: setting.icon.Support, // label: setting.string.Support,
component: setting.component.Support, // icon: setting.icon.Support,
group: 'main', // component: setting.component.Support,
secured: false, // group: 'main',
order: 5000 // secured: false,
}, // order: 5000
setting.ids.Support // },
) // setting.ids.Support
// )
builder.createDoc( builder.createDoc(
setting.class.SettingsCategory, setting.class.SettingsCategory,
core.space.Model, core.space.Model,

View File

@ -217,6 +217,12 @@
flex-shrink: 0; flex-shrink: 0;
height: 1rem; height: 1rem;
} }
.antiNav-footer {
align-items: flex-end;
display: flex;
flex: 1;
margin: 2rem .75rem;
}
/* Basic */ /* Basic */
.antiTitle { .antiTitle {

View File

@ -411,7 +411,7 @@
} }
} }
.notifyPopup { .notifyPopup, .helpAndSupportPopup {
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -437,6 +437,11 @@
} }
} }
.helpAndSupportPopup {
min-height: 100%;
min-width: 20rem;
}
// Remove highlights table rows and hide dots in popups // Remove highlights table rows and hide dots in popups
.popup .tr-body:hover, .popup-tooltip .tr-body:hover { background-color: transparent !important; } .popup .tr-body:hover, .popup-tooltip .tr-body:hover { background-color: transparent !important; }
.popup-tooltip .tr-body .menuRow { visibility: hidden !important; } .popup-tooltip .tr-body .menuRow { visibility: hidden !important; }

View File

@ -292,6 +292,11 @@ export function fitPopupElement (
newProps.bottom = '12px' newProps.bottom = '12px'
newProps.left = '50%' newProps.left = '50%'
newProps.transform = 'translateX(-50%)' newProps.transform = 'translateX(-50%)'
} else if (element === 'help-center') {
newProps.top = 'calc(var(--status-bar-height) + 12px)'
newProps.bottom = '12px'
newProps.right = '12px'
show = true
} }
} else { } else {
newProps.top = '50%' newProps.top = '50%'

View File

@ -135,6 +135,7 @@ export type PopupPosAlignment =
| 'full' | 'full'
| 'content' | 'content'
| 'middle' | 'middle'
| 'help-center'
export function isPopupPosAlignment (x: any): x is PopupPosAlignment { export function isPopupPosAlignment (x: any): x is PopupPosAlignment {
return ( return (
@ -145,7 +146,8 @@ export function isPopupPosAlignment (x: any): x is PopupPosAlignment {
x === 'account' || x === 'account' ||
x === 'full' || x === 'full' ||
x === 'content' || x === 'content' ||
x === 'middle') x === 'middle' ||
x === 'help-center')
) )
} }

View File

@ -16,6 +16,14 @@
"Join": "Join", "Join": "Join",
"BrowseSpaces": "Browse spaces", "BrowseSpaces": "Browse spaces",
"AccountDisabled": "Account is disabled", "AccountDisabled": "Account is disabled",
"AccountDisabledDescr": "Please contact the workspace administrator" "AccountDisabledDescr": "Please contact the workspace administrator",
"HelpAndSupport": "Help & Support",
"HelpCenter": "Help Center",
"KeyboardShortcuts": "Keyboard Shortcuts",
"Documentation": "Documentation",
"ContactUs": "Contact us",
"OpenPlatformGuide": "Open Platform Guide",
"AccessWorkspaceSettings": "Access your workspace settings",
"HowToWorkFaster": "Learn how to work faster"
} }
} }

View File

@ -16,6 +16,14 @@
"Join": "Присоедениться", "Join": "Присоедениться",
"BrowseSpaces": "Обзор пространств", "BrowseSpaces": "Обзор пространств",
"AccountDisabled": "Аккаунт отключен", "AccountDisabled": "Аккаунт отключен",
"AccountDisabledDescr": "Пожалуйста свяжитесь с администратором" "AccountDisabledDescr": "Пожалуйста свяжитесь с администратором",
"HelpAndSupport": "Помощь",
"HelpCenter": "Центр помощи",
"KeyboardShortcuts": "Сочетания клавиш",
"Documentation": "Документация",
"ContactUs": "Связаться с нами",
"OpenPlatformGuide": "Открыть руководство пользователя",
"AccessWorkspaceSettings": "Открыть настройки рабочего пространства",
"HowToWorkFaster": "Узнайте как работать эффективнее"
} }
} }

View File

@ -31,6 +31,8 @@
locationToUrl locationToUrl
} from '@hcengineering/ui' } from '@hcengineering/ui'
import view from '@hcengineering/view' import view from '@hcengineering/view'
import HelpAndSupport from './HelpAndSupport.svelte'
import workbench from '../plugin'
let items: SettingsCategory[] = [] let items: SettingsCategory[] = []
@ -90,6 +92,10 @@
showPopup(login.component.InviteLink, {}) showPopup(login.component.InviteLink, {})
} }
function helpAndSupport (): void {
showPopup(HelpAndSupport, {}, 'help-center')
}
function filterItems (items: SettingsCategory[], keys: string[]): SettingsCategory[] { function filterItems (items: SettingsCategory[], keys: string[]): SettingsCategory[] {
return items.filter( return items.filter(
(p) => p._id !== setting.ids.Profile && p._id !== setting.ids.Password && keys.includes(p.group ?? '') (p) => p._id !== setting.ids.Profile && p._id !== setting.ids.Password && keys.includes(p.group ?? '')
@ -149,6 +155,12 @@
action: async () => inviteWorkspace(), action: async () => inviteWorkspace(),
group: 'end' group: 'end'
}, },
{
icon: setting.icon.Support,
label: workbench.string.HelpAndSupport,
action: async () => helpAndSupport(),
group: 'end'
},
{ {
icon: setting.icon.Signout, icon: setting.icon.Signout,
label: setting.string.Signout, label: setting.string.Signout,

View File

@ -0,0 +1,241 @@
<script lang="ts">
import {
Button,
closePopup,
getCurrentLocation,
Icon,
IconArrowLeft,
Label,
ListView,
navigate,
Scroller
} from '@hcengineering/ui'
import setting, { settingId } from '@hcengineering/setting'
import view, { Action, ActionCategory } from '@hcengineering/view'
import { getClient } from '@hcengineering/presentation'
import RightArrowIcon from './icons/Collapsed.svelte'
import KeyboardIcon from './icons/Keyboard.svelte'
import DocumentationIcon from './icons/Documentation.svelte'
import workbench from '../plugin'
let shortcuts = false
let actions: Action[] = []
let categories: ActionCategory[] = []
const client = getClient()
function navigateToSettings () {
closePopup()
const loc = getCurrentLocation()
loc.path[2] = loc.path[3] = settingId
loc.path.length = 4
navigate(loc)
}
function formatKey (key: string): string[][] {
const thens = key.split('->')
const result: string[][] = []
for (const r of thens) {
result.push(
r.split('+').map((it) =>
it
.replaceAll('key', '')
.replaceAll(/Meta|meta/g, '⌘')
.replaceAll('ArrowUp', '↑')
.replaceAll('ArrowDown', '↓')
.replaceAll('ArrowLeft', '←')
.replaceAll('ArrowRight', '→')
.replaceAll('Backspace', '⌫')
)
)
}
return result
}
async function getActions () {
categories = await getClient().findAll(view.class.ActionCategory, [])
const rawActions = await client.findAll(view.class.Action, [])
const openAction = rawActions.find(
(action) => action.label === 'view:string:Open' && action.category === 'view:category:General'
)
const deleteAction = rawActions.find(
(action) => action.label === 'view:string:Delete' && action.category === 'view:category:General'
)
actions = rawActions.filter(
(action) =>
action.keyBinding &&
action.keyBinding.length !== 0 &&
action.label !== 'view:string:Open' &&
action.label !== 'view:string:Delete'
)
deleteAction && actions.unshift(deleteAction)
openAction && actions.unshift(openAction)
actions.sort((a, b) => a.category.localeCompare(b.category))
}
$: getActions()
const cards = [
{
icon: DocumentationIcon,
title: workbench.string.Documentation,
description: workbench.string.OpenPlatformGuide,
disabled: true
},
{
icon: view.icon.Setting,
title: setting.string.Settings,
description: workbench.string.AccessWorkspaceSettings,
onClick: navigateToSettings
},
{
icon: KeyboardIcon,
title: workbench.string.KeyboardShortcuts,
description: workbench.string.HowToWorkFaster,
onClick: () => {
shortcuts = true
}
}
]
</script>
<div class="helpAndSupportPopup">
<div class="header">
{#if shortcuts}
<div class="mr-4 cursor-pointer" on:click={() => (shortcuts = !shortcuts)}>
<Icon icon={IconArrowLeft} size={'medium'} fill={'var(--content-color)'} />
</div>
{/if}
<span class="fs-title overflow-label">
<Label label={shortcuts ? workbench.string.KeyboardShortcuts : workbench.string.HelpCenter} />
</span>
</div>
{#if !shortcuts}
{#each cards as card}
<div class="clear-mins card {!card.disabled ? 'cursor-pointer focused-button' : ''}">
<div class="container" on:click={card.onClick}>
<Icon icon={card.icon} size={'small'} fill={'var(--content-color)'} />
<div class="content">
<div class="fs-title">
<Label label={card.title} />
</div>
<div class="text-sm content-dark-color"><Label label={card.description} /></div>
</div>
<div class="rightIcon">
<Icon icon={RightArrowIcon} size={'small'} />
</div>
</div>
</div>
{/each}
{:else}
<!-- Keyboard shortcuts -->
<Scroller>
<ListView count={actions.length}>
<svelte:fragment slot="category" let:item>
{@const action = actions[item]}
{#if item === 0 || (item > 0 && actions[item - 1].category !== action.category)}
{#if action.category}
{@const category = categories.find((cat) => cat._id === action.category)}
{#if category?.label && category.label !== categories.find((cat) => cat._id === actions[item - 1]?.category)?.label}
<div class="category-box">
<Label label={category.label} />
</div>
{/if}
{/if}
{/if}
</svelte:fragment>
<svelte:fragment slot="item" let:item>
{@const action = actions[item]}
<div class="flex-row-center flex-between flex-grow ml-2 p-3 text-base">
<div class="mr-4">
<Icon icon={action.icon ?? IconArrowLeft} size={'small'} />
</div>
<div class="flex-grow">
<Label label={action.label} />
</div>
<div class="mr-2 text-md flex-row-center">
{#if action.keyBinding}
{#each action.keyBinding as key, i}
{#if i !== 0}
<div class="ml-2 mr-2">or</div>
{/if}
<div class="flex-row-center">
{#each formatKey(key) as k, jj}
{#if jj !== 0}
<div class="ml-1 mr-1">then</div>
{/if}
{#each k as kk, j}
<div class="flex-center text-sm key-box">
{kk}
</div>
{/each}
{/each}
</div>
{/each}
{/if}
</div>
</div>
</svelte:fragment>
</ListView>
</Scroller>
{/if}
<div class="footer">
<Button
id="contact-us"
icon={setting.icon.Support}
kind={'transparent'}
disabled={true}
label={workbench.string.ContactUs}
/>
</div>
</div>
<style lang="scss">
.card {
border: 1px solid var(--theme-bg-accent-color);
border-radius: 0.75rem;
margin: 16px 1rem 0 1rem;
}
.container {
display: flex;
flex-direction: row;
padding: 16px;
width: 100%;
}
.content {
padding: 0 10px;
width: 100%;
}
.rightIcon {
align-self: center;
}
.footer {
align-items: flex-end;
border-top: 1px solid var(--popup-divider);
display: flex;
flex: 1;
justify-content: flex-end;
margin: 0 16px;
padding-top: 10px;
}
.key-box {
background-color: var(--button-bg-color);
color: var(--caption-color);
min-width: 1.5rem;
padding: 0 0.5rem;
border: 1px solid var(--button-border-color);
border-radius: 0.25rem;
}
.key-box + .key-box {
margin-left: 0.5rem;
}
.category-box {
display: inline-block;
background-color: var(--divider-color);
color: var(--caption-color);
padding: 0.5rem;
}
</style>

View File

@ -16,8 +16,9 @@
import core, { Doc, Ref, SortingOrder, Space, getCurrentAccount } from '@hcengineering/core' import core, { Doc, Ref, SortingOrder, Space, getCurrentAccount } from '@hcengineering/core'
import { getResource } from '@hcengineering/platform' import { getResource } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation' import { createQuery, getClient } from '@hcengineering/presentation'
import { Scroller } from '@hcengineering/ui' import { Button, Scroller, showPopup } from '@hcengineering/ui'
import type { NavigatorModel, SpecialNavModel } from '@hcengineering/workbench' import type { NavigatorModel, SpecialNavModel } from '@hcengineering/workbench'
import setting from '@hcengineering/setting'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import preferece, { SpacePreference } from '@hcengineering/preference' import preferece, { SpacePreference } from '@hcengineering/preference'
import { getSpecialSpaceClass } from '../utils' import { getSpecialSpaceClass } from '../utils'
@ -26,6 +27,8 @@
import SpecialElement from './navigator/SpecialElement.svelte' import SpecialElement from './navigator/SpecialElement.svelte'
import StarredNav from './navigator/StarredNav.svelte' import StarredNav from './navigator/StarredNav.svelte'
import TreeSeparator from './navigator/TreeSeparator.svelte' import TreeSeparator from './navigator/TreeSeparator.svelte'
import HelpAndSupport from './HelpAndSupport.svelte'
import workbench from '../plugin'
export let model: NavigatorModel | undefined export let model: NavigatorModel | undefined
export let currentSpace: Ref<Space> | undefined export let currentSpace: Ref<Space> | undefined
@ -158,5 +161,16 @@
/> />
{/each} {/each}
<div class="antiNav-space" /> <div class="antiNav-space" />
<div class="antiNav-footer">
<Button
id="contact-us"
icon={setting.icon.Support}
kind={'transparent'}
size={'small'}
label={workbench.string.HelpAndSupport}
on:click={() => showPopup(HelpAndSupport, {}, 'help-center')}
/>
</div>
</Scroller> </Scroller>
{/if} {/if}

View File

@ -0,0 +1,30 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let fill: string = 'var(--theme-caption-color)'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<g>
<path
d="M 6.492188 7.214844 C 6.492188 7.472656 6.703125 7.6875 6.960938 7.6875 L 11.152344 7.6875 C 11.414062 7.6875 11.625 7.472656 11.625 7.214844 C 11.625 6.953125 11.414062 6.742188 11.152344 6.742188 L 6.960938 6.742188 C 6.703125 6.742188 6.492188 6.953125 6.492188 7.214844 Z M 6.492188 7.214844 "
/>
<path
d="M 11.152344 9.308594 L 6.960938 9.308594 C 6.703125 9.308594 6.492188 9.519531 6.492188 9.78125 C 6.492188 10.039062 6.703125 10.25 6.960938 10.25 L 11.152344 10.25 C 11.414062 10.25 11.625 10.039062 11.625 9.78125 C 11.625 9.519531 11.414062 9.308594 11.152344 9.308594 Z M 11.152344 9.308594 "
/>
<path
d="M 11.152344 11.875 L 6.960938 11.875 C 6.703125 11.875 6.492188 12.085938 6.492188 12.347656 C 6.492188 12.605469 6.703125 12.816406 6.960938 12.816406 L 11.152344 12.816406 C 11.414062 12.816406 11.625 12.605469 11.625 12.347656 C 11.625 12.085938 11.414062 11.875 11.152344 11.875 Z M 11.152344 11.875 "
/>
<path
d="M 5.832031 7.214844 C 5.832031 7.484375 5.609375 7.707031 5.339844 7.707031 C 5.066406 7.707031 4.847656 7.484375 4.847656 7.214844 C 4.847656 6.941406 5.066406 6.722656 5.339844 6.722656 C 5.609375 6.722656 5.832031 6.941406 5.832031 7.214844 Z M 5.832031 7.214844 "
/>
<path
d="M 5.832031 9.78125 C 5.832031 10.050781 5.609375 10.273438 5.339844 10.273438 C 5.066406 10.273438 4.847656 10.050781 4.847656 9.78125 C 4.847656 9.507812 5.066406 9.289062 5.339844 9.289062 C 5.609375 9.289062 5.832031 9.507812 5.832031 9.78125 Z M 5.832031 9.78125 "
/>
<path
d="M 5.832031 12.347656 C 5.832031 12.617188 5.609375 12.839844 5.339844 12.839844 C 5.066406 12.839844 4.847656 12.617188 4.847656 12.347656 C 4.847656 12.074219 5.066406 11.855469 5.339844 11.855469 C 5.609375 11.855469 5.832031 12.074219 5.832031 12.347656 Z M 5.832031 12.347656 "
/>
<path
d="M 13.992188 3.699219 L 10.429688 0.136719 C 10.339844 0.0507812 10.222656 0 10.097656 0 L 2.34375 0 C 2.082031 0 1.871094 0.210938 1.871094 0.472656 L 1.871094 15.527344 C 1.871094 15.789062 2.082031 16 2.34375 16 L 13.65625 16 C 13.917969 16 14.128906 15.789062 14.128906 15.527344 L 14.128906 4.03125 C 14.128906 3.90625 14.078125 3.789062 13.992188 3.699219 Z M 10.464844 1.503906 L 12.625 3.667969 L 10.464844 3.667969 Z M 13.1875 15.058594 L 2.8125 15.058594 L 2.8125 0.941406 L 9.519531 0.941406 L 9.519531 4.136719 C 9.519531 4.398438 9.730469 4.609375 9.992188 4.609375 L 13.1875 4.609375 Z M 13.1875 15.058594 "
/>
</g>
</svg>

View File

@ -0,0 +1,10 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let fill: string = 'var(--theme-caption-color)'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M 7.382812 8.617188 L 7.382812 9.847656 L 6.152344 9.847656 L 6.152344 8.617188 Z M 9.847656 8.617188 L 9.847656 9.847656 L 8.617188 9.847656 L 8.617188 8.617188 Z M 12.308594 8.617188 L 12.308594 9.847656 L 11.078125 9.847656 L 11.078125 8.617188 Z M 3.691406 8.617188 L 4.921875 8.617188 L 4.921875 9.847656 L 3.691406 9.847656 Z M 12.308594 12.921875 L 3.691406 12.921875 L 3.691406 11.691406 L 12.308594 11.691406 Z M 14.769531 16 L 1.230469 16 C 0.550781 15.996094 0.00390625 15.449219 0 14.769531 L 0 6.769531 C 0.00390625 6.089844 0.550781 5.539062 1.230469 5.539062 L 3.691406 5.539062 L 3.691406 3.691406 C 3.695312 3.011719 4.246094 2.464844 4.921875 2.460938 L 12.308594 2.460938 L 12.308594 0 L 13.539062 0 L 13.539062 2.460938 C 13.535156 3.140625 12.988281 3.691406 12.308594 3.691406 L 4.921875 3.691406 L 4.921875 6.769531 L 1.230469 6.769531 L 1.230469 14.769531 L 14.769531 14.769531 L 14.769531 6.769531 L 6.769531 6.769531 C 6.429688 6.769531 6.152344 6.492188 6.152344 6.152344 C 6.152344 5.8125 6.429688 5.539062 6.769531 5.539062 L 14.769531 5.539062 C 15.449219 5.539062 15.996094 6.089844 16 6.769531 L 16 14.769531 C 15.996094 15.449219 15.449219 15.996094 14.769531 16 Z M 14.769531 16 "
/>
</svg>

View File

@ -36,7 +36,15 @@ export default mergeIds(workbenchId, workbench, {
Join: '' as IntlString, Join: '' as IntlString,
BrowseSpaces: '' as IntlString, BrowseSpaces: '' as IntlString,
AccountDisabled: '' as IntlString, AccountDisabled: '' as IntlString,
AccountDisabledDescr: '' as IntlString AccountDisabledDescr: '' as IntlString,
HelpAndSupport: '' as IntlString,
HelpCenter: '' as IntlString,
KeyboardShortcuts: '' as IntlString,
Documentation: '' as IntlString,
ContactUs: '' as IntlString,
OpenPlatformGuide: '' as IntlString,
AccessWorkspaceSettings: '' as IntlString,
HowToWorkFaster: '' as IntlString
}, },
component: { component: {
SpacePanel: '' as AnyComponent SpacePanel: '' as AnyComponent