[go: nahoru, domu]

Skip to content

Commit

Permalink
Use logo for workspaces (hcengineering#4828)
Browse files Browse the repository at this point in the history
Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
Signed-off-by: Tiago Cruz <tcruz@netic.io>
  • Loading branch information
ThetaDR authored and tjaoc committed Mar 5, 2024
1 parent d6ed8c6 commit 6bcab04
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 16 deletions.
22 changes: 21 additions & 1 deletion models/setting/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
type Integration,
type IntegrationType,
type InviteSettings,
type WorkspaceSetting,
type SettingsCategory,
type UserMixin
} from '@hcengineering/setting'
Expand Down Expand Up @@ -99,6 +100,11 @@ export class TInviteSettings extends TConfiguration implements InviteSettings {
limit!: number
}

@Model(setting.class.WorkspaceSetting, core.class.Doc, DOMAIN_SETTING)
export class TWorkspaceSetting extends TDoc implements WorkspaceSetting {
icon?: string
}

export function createModel (builder: Builder): void {
builder.createModel(
TIntegration,
Expand All @@ -107,7 +113,8 @@ export function createModel (builder: Builder): void {
TWorkspaceSettingCategory,
TEditable,
TUserMixin,
TInviteSettings
TInviteSettings,
TWorkspaceSetting
)

builder.mixin(setting.class.Integration, core.class.Class, notification.mixin.ClassCollaborators, {
Expand Down Expand Up @@ -205,6 +212,19 @@ export function createModel (builder: Builder): void {
},
setting.ids.Configure
)
builder.createDoc(
setting.class.WorkspaceSettingCategory,
core.space.Model,
{
name: 'workspaceSettings',
label: setting.string.Branding,
icon: setting.icon.AccountSettings,
component: setting.component.WorkspaceSetting,
order: 1002,
secured: true
},
setting.ids.WorkspaceSetting
)
builder.createDoc(
setting.class.WorkspaceSettingCategory,
core.space.Model,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import presentation from '@hcengineering/presentation'
export let file: Blob
export let lessCrop: boolean = false
let inputRef: HTMLInputElement
const targetMimes = ['image/png', 'image/jpg', 'image/jpeg']
Expand Down Expand Up @@ -64,7 +65,7 @@
<div class="editavatar-container">
{#await CropperP then Cropper}
<div class="cropper">
<Cropper bind:this={cropper} image={file} />
<Cropper bind:this={cropper} image={file} {lessCrop} />
</div>
<div class="footer">
<Button label={presentation.string.Save} kind={'primary'} size={'large'} on:click={onCrop} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
export let direct: Blob | undefined = undefined
export let icon: Asset | AnySvelteComponent | undefined = undefined
export let disabled: boolean = false
export let imageOnly: boolean = false
export let lessCrop: boolean = false
$: [schema, uri] = avatar?.split('://') || []
Expand Down Expand Up @@ -91,6 +93,8 @@
name,
file: direct,
icon,
imageOnly,
lessCrop,
onSubmit: handlePopupSubmit
})
}
Expand Down
20 changes: 13 additions & 7 deletions plugins/contact-resources/src/components/SelectAvatarPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
export let email: string | undefined
export let file: Blob | undefined
export let icon: Asset | AnySvelteComponent | undefined = undefined
export let imageOnly: boolean = false
export let lessCrop: boolean = false
export let onSubmit: (avatarType?: AvatarType, avatar?: string, file?: Blob) => void
const [schema, uri] = avatar?.split('://') || []
Expand Down Expand Up @@ -110,18 +112,18 @@
if (selectedFile !== undefined) {
editableFile = selectedFile
} else if (selectedAvatar) {
} else if (selectedAvatar && !(imageOnly && selectedAvatar === initialSelectedAvatar)) {
const url = getFileUrl(selectedAvatar, 'full')
editableFile = await (await fetch(url)).blob()
} else {
inputRef.click()
return
}
showCropper(editableFile)
if (editableFile.size > 0) showCropper(editableFile)
}
function showCropper (editableFile: Blob) {
showPopup(EditAvatarPopup, { file: editableFile }, undefined, (blob) => {
showPopup(EditAvatarPopup, { file: editableFile, lessCrop }, undefined, (blob) => {
if (blob === undefined) {
if (!selectedFile && (!avatar || avatar.includes('://'))) {
selectedAvatarType = AvatarType.COLOR
Expand All @@ -131,7 +133,7 @@
}
if (blob === null) {
selectedAvatarType = AvatarType.COLOR
selectedAvatar = getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
selectedAvatar = imageOnly ? '' : getPlatformAvatarColorForTextDef(name ?? '', $themeStore.dark).name
selectedFile = undefined
} else {
selectedFile = blob
Expand Down Expand Up @@ -203,8 +205,12 @@
<div
class="cursor-pointer"
on:click|self={(e) => {
if (selectedAvatarType === AvatarType.IMAGE) handleImageAvatarClick()
else if (selectedAvatarType === AvatarType.COLOR) showColorPopup(e)
if (imageOnly) {
handleImageAvatarClick()
} else {
if (selectedAvatarType === AvatarType.IMAGE) handleImageAvatarClick()
else if (selectedAvatarType === AvatarType.COLOR) showColorPopup(e)
}
}}
>
<AvatarComponent
Expand All @@ -220,7 +226,7 @@
/>
</div>
<TabList
items={getAvatarTypeDropdownItems(hasGravatar)}
items={getAvatarTypeDropdownItems(hasGravatar, imageOnly)}
kind={'separated-free'}
bind:selected={selectedAvatarType}
on:select={handleDropdownSelection}
Expand Down
10 changes: 9 additions & 1 deletion plugins/contact-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,15 @@ function fillStores (): void {

fillStores()

export function getAvatarTypeDropdownItems (hasGravatar: boolean): TabItem[] {
export function getAvatarTypeDropdownItems (hasGravatar: boolean, imageOnly?: boolean): TabItem[] {
if (imageOnly === true) {
return [
{
id: AvatarType.IMAGE,
labelIntl: contact.string.UseImage
}
]
}
return [
{
id: AvatarType.COLOR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
export let image: Blob
export let cropSize = 1200
export let lessCrop: boolean = false
let imgRef: HTMLImageElement
let cropper: Cropper | undefined
Expand Down Expand Up @@ -86,7 +87,7 @@
}
</script>

<div class="w-full h-full flex">
<div class="w-full h-full flex" class:less-crop={lessCrop}>
<img class="image" bind:this={imgRef} alt="img" />
{#await init(image)}
Waiting...
Expand All @@ -99,6 +100,9 @@
:global(.cropper-view-box, .cropper-face) {
border-radius: 50%;
}
:global(.less-crop .cropper-view-box, .less-crop .cropper-face) {
border-radius: 10%;
}
.image {
max-width: 100%;
Expand Down
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"TaskTypes": "Task types",
"Automations": "Automations",
"Collections": "Collections",
"ClassColon": "Class:"
"ClassColon": "Class:",
"Branding": "Branding"
}
}
3 changes: 2 additions & 1 deletion plugins/setting-assets/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"TaskTypes": "Типы задач",
"Automations": "Автоматизация",
"Collections": "Коллекции",
"ClassColon": "Класс:"
"ClassColon": "Класс:",
"Branding": "Брендинг"
}
}
91 changes: 91 additions & 0 deletions plugins/setting-resources/src/components/WorkspaceSetting.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<!--
// Copyright © 2024 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, onDestroy } from 'svelte'
import contact, { Employee, PersonAccount, combineName, getFirstName, getLastName } from '@hcengineering/contact'
import { ChannelsEditor, EditableAvatar, employeeByIdStore } from '@hcengineering/contact-resources'
import { AttributeEditor, getClient, MessageBox } from '@hcengineering/presentation'
import {
Button,
createFocusManager,
EditBox,
FocusHandler,
showPopup,
Header,
Breadcrumb,
Label
} from '@hcengineering/ui'
import setting from '../plugin'
import { WorkspaceSetting } from '@hcengineering/setting'
import { getEmbeddedLabel } from '@hcengineering/platform'
export let visibleNav: boolean = true
const dispatch = createEventDispatcher()
let workspaceSettings: WorkspaceSetting | undefined = undefined
const client = getClient()
client.findOne(setting.class.WorkspaceSetting, {}).then((r) => {
workspaceSettings = r
})
let avatarEditor: EditableAvatar
async function onAvatarDone (e: any): Promise<void> {
if (workspaceSettings === undefined) {
const avatar = await avatarEditor.createAvatar()
await client.createDoc(
setting.class.WorkspaceSetting,
setting.space.Setting,
{ icon: avatar },
setting.ids.WorkspaceSetting
)
return
}
if (workspaceSettings.icon != null) {
await avatarEditor.removeAvatar(workspaceSettings.icon)
}
const avatar = await avatarEditor.createAvatar()
await client.update(workspaceSettings, {
icon: avatar
})
}
const manager = createFocusManager()
</script>

<FocusHandler {manager} />

<div class="hulyComponent p-10 flex ac-body row">
<EditableAvatar
avatar={workspaceSettings?.icon}
size={'x-large'}
bind:this={avatarEditor}
on:done={onAvatarDone}
imageOnly
lessCrop
/>
<div class="heading-medium-20 p-4">
<Label label={getEmbeddedLabel('Workspace Logo')} />
</div>
</div>

<style lang="scss">
.row {
flex-direction: row;
align-content: center;
}
</style>
2 changes: 2 additions & 0 deletions plugins/setting-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import NumberTypeEditor from './components/typeEditors/NumberTypeEditor.svelte'
import ArrayEditor from './components/typeEditors/ArrayEditor.svelte'
import RefEditor from './components/typeEditors/RefEditor.svelte'
import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte'
import WorkspaceSetting from './components/WorkspaceSetting.svelte'
import WorkspaceSettings from './components/WorkspaceSettings.svelte'
import InviteSetting from './components/InviteSetting.svelte'
import Configure from './components/Configure.svelte'
Expand Down Expand Up @@ -84,6 +85,7 @@ export default async (): Promise<Resources> => ({
Settings,
Profile,
Password,
WorkspaceSetting,
WorkspaceSettings,
Integrations,
Support,
Expand Down
15 changes: 13 additions & 2 deletions plugins/setting/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ export interface InviteSettings extends Configuration {
limit: number
}

/**
* @public
*/
export interface WorkspaceSetting extends Doc {
icon?: string
}

/**
* @public
*/
Expand All @@ -114,7 +121,8 @@ export default plugin(settingId, {
Terms: '' as Ref<Doc>,
ClassSetting: '' as Ref<Doc>,
Owners: '' as Ref<Doc>,
InviteSettings: '' as Ref<Doc>
InviteSettings: '' as Ref<Doc>,
WorkspaceSetting: '' as Ref<Doc>
},
mixin: {
Editable: '' as Ref<Mixin<Editable>>,
Expand All @@ -128,12 +136,14 @@ export default plugin(settingId, {
WorkspaceSettingCategory: '' as Ref<Class<SettingsCategory>>,
Integration: '' as Ref<Class<Integration>>,
IntegrationType: '' as Ref<Class<IntegrationType>>,
InviteSettings: '' as Ref<Class<InviteSettings>>
InviteSettings: '' as Ref<Class<InviteSettings>>,
WorkspaceSetting: '' as Ref<Class<WorkspaceSetting>>
},
component: {
Settings: '' as AnyComponent,
Profile: '' as AnyComponent,
Password: '' as AnyComponent,
WorkspaceSetting: '' as AnyComponent,
WorkspaceSettings: '' as AnyComponent,
Integrations: '' as AnyComponent,
Support: '' as AnyComponent,
Expand All @@ -145,6 +155,7 @@ export default plugin(settingId, {
Settings: '' as IntlString,
Setting: '' as IntlString,
WorkspaceSettings: '' as IntlString,
Branding: '' as IntlString,
Integrations: '' as IntlString,
Support: '' as IntlString,
Privacy: '' as IntlString,
Expand Down
Loading

0 comments on commit 6bcab04

Please sign in to comment.