[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use logo for workspaces #4828

Merged
merged 1 commit into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Use logo for workspaces
Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
  • Loading branch information
ThetaDR committed Feb 29, 2024
commit 88ed39dde2126c77538e55a7920176a9cfab2cc4
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