mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-29 14:34:12 +03:00
Add ChannelsDropdown (#1459)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
30095a6929
commit
6df202f166
@ -49,6 +49,7 @@ input {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
color: var(--caption-color);
|
color: var(--caption-color);
|
||||||
|
&::placeholder { color: var(--dark-color); }
|
||||||
&.wrong-input { background-color: var(--system-error-color) !important; }
|
&.wrong-input { background-color: var(--system-error-color) !important; }
|
||||||
}
|
}
|
||||||
audio, canvas, embed, iframe, img, object, svg, video {
|
audio, canvas, embed, iframe, img, object, svg, video {
|
||||||
|
@ -42,8 +42,29 @@
|
|||||||
color: #d6d6d6;
|
color: #d6d6d6;
|
||||||
border: none;
|
border: none;
|
||||||
caret-color: var(--caret-color);
|
caret-color: var(--caret-color);
|
||||||
|
}
|
||||||
&::placeholder { color: var(--content-color); }
|
.clear-btn {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: .75rem;
|
||||||
|
height: .75rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: .625rem;
|
||||||
|
height: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
color: var(--content-color);
|
||||||
|
background-color: var(--button-border-color);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent-color);
|
||||||
|
background-color: var(--button-border-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +101,7 @@
|
|||||||
.icon {
|
.icon {
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
|
color: var(--content-color);
|
||||||
}
|
}
|
||||||
.color {
|
.color {
|
||||||
width: .875rem;
|
width: .875rem;
|
||||||
@ -105,7 +127,11 @@
|
|||||||
margin-right: .75rem;
|
margin-right: .75rem;
|
||||||
}
|
}
|
||||||
.check-right { margin: 0 0 0 2rem; }
|
.check-right { margin: 0 0 0 2rem; }
|
||||||
&:hover { background-color: var(--popup-bg-hover); }
|
&:hover {
|
||||||
|
background-color: var(--popup-bg-hover);
|
||||||
|
|
||||||
|
.icon { color: var(--accent-color); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.sticky-wrapper {
|
.sticky-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
export let width: string | undefined = undefined
|
export let width: string | undefined = undefined
|
||||||
export let resetIconSize: boolean = false
|
export let resetIconSize: boolean = false
|
||||||
export let focus: boolean = false
|
export let focus: boolean = false
|
||||||
|
export let click: boolean = false
|
||||||
export let title: string | undefined = undefined
|
export let title: string | undefined = undefined
|
||||||
|
|
||||||
export let input: HTMLButtonElement | undefined = undefined
|
export let input: HTMLButtonElement | undefined = undefined
|
||||||
@ -43,6 +44,10 @@
|
|||||||
input.focus()
|
input.focus()
|
||||||
focus = false
|
focus = false
|
||||||
}
|
}
|
||||||
|
if (click && input) {
|
||||||
|
input.click()
|
||||||
|
click = false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -128,6 +133,8 @@
|
|||||||
&:disabled {
|
&:disabled {
|
||||||
color: rgb(var(--caption-color) / 40%);
|
color: rgb(var(--caption-color) / 40%);
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.btn-icon { opacity: .5; }
|
||||||
}
|
}
|
||||||
|
|
||||||
&.jf-left { justify-content: flex-start; }
|
&.jf-left { justify-content: flex-start; }
|
||||||
|
@ -39,14 +39,14 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{#each actions as action}
|
{#each actions as action}
|
||||||
<div
|
<div
|
||||||
class="ap-menuItem flex-row-center"
|
class="ap-menuItem flex-row-center withIcon"
|
||||||
on:click={(evt) => {
|
on:click={(evt) => {
|
||||||
dispatch('close')
|
dispatch('close')
|
||||||
action.action(evt, ctx)
|
action.action(evt, ctx)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#if action.icon}
|
{#if action.icon}
|
||||||
<Icon icon={action.icon} size={'small'} />
|
<div class="icon"><Icon icon={action.icon} size={'small'} /></div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="ml-3 pr-1"><Label label={action.label} /></div>
|
<div class="ml-3 pr-1"><Label label={action.label} /></div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,3 +55,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ap-space" />
|
<div class="ap-space" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.withIcon {
|
||||||
|
.icon { color: var(--content-color); }
|
||||||
|
&:hover .icon { color: var(--accent-color); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2022 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, onMount } from 'svelte'
|
||||||
|
import type { IntlString } from '@anticrm/platform'
|
||||||
|
import { translate } from '@anticrm/platform'
|
||||||
|
import contact from '@anticrm/contact'
|
||||||
|
import { Button, Icon, IconClose, IconBlueCheck, Label } from '@anticrm/ui'
|
||||||
|
|
||||||
|
export let value: string = ''
|
||||||
|
export let placeholder: IntlString
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
let input: HTMLInputElement
|
||||||
|
let phTraslate: string
|
||||||
|
translate(placeholder, {}).then(tr => phTraslate = tr)
|
||||||
|
|
||||||
|
onMount(() => { if (input) input.focus() })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="selectPopup">
|
||||||
|
<div class="header no-border">
|
||||||
|
<div class="flex-between flex-grow pr-2">
|
||||||
|
<div class="flex-grow">
|
||||||
|
<input
|
||||||
|
bind:this={input}
|
||||||
|
type="text"
|
||||||
|
bind:value
|
||||||
|
placeholder={phTraslate}
|
||||||
|
style="width: 100%;"
|
||||||
|
on:keypress={(ev) => {
|
||||||
|
if (ev.key === 'Enter') dispatch('close', value)
|
||||||
|
}}
|
||||||
|
on:change
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="buttons-group small-gap">
|
||||||
|
<div class="clear-btn" class:show={value !== ''} on:click={() => {
|
||||||
|
value = ''
|
||||||
|
input.focus()
|
||||||
|
}}>
|
||||||
|
{#if value !== ''}<div class="icon"><Icon icon={IconClose} size={'inline'} /></div>{/if}
|
||||||
|
</div>
|
||||||
|
<Button kind={'transparent'} size={'small'} icon={IconBlueCheck} on:click={() => dispatch('close', value)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
184
plugins/contact-resources/src/components/ChannelsDropdown.svelte
Normal file
184
plugins/contact-resources/src/components/ChannelsDropdown.svelte
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||||
|
// Copyright © 2021 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Channel, ChannelProvider } from '@anticrm/contact'
|
||||||
|
import contact from '@anticrm/contact'
|
||||||
|
import type { AttachedData, Doc, Ref, Timestamp } from '@anticrm/core'
|
||||||
|
import type { Asset, IntlString } from '@anticrm/platform'
|
||||||
|
import { AnyComponent, showPopup, Tooltip, Button, Menu } from '@anticrm/ui'
|
||||||
|
import type { Action, ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||||
|
import presentation from '@anticrm/presentation'
|
||||||
|
import { getChannelProviders } from '../utils'
|
||||||
|
import ChannelsPopup from './ChannelsPopup.svelte'
|
||||||
|
import ChannelEditor from './ChannelEditor.svelte'
|
||||||
|
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||||
|
|
||||||
|
export let value: AttachedData<Channel>[] | Channel | null
|
||||||
|
export let editable = true
|
||||||
|
export let kind: ButtonKind = 'no-border'
|
||||||
|
export let size: ButtonSize = 'small'
|
||||||
|
export let length: 'short' | 'full' = 'full'
|
||||||
|
export let reverse: boolean = false
|
||||||
|
export let integrations: Set<Ref<Doc>> = new Set<Ref<Doc>>()
|
||||||
|
const notificationClient = NotificationClientImpl.getClient()
|
||||||
|
const lastViews = notificationClient.getLastViews()
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
label: IntlString
|
||||||
|
icon: Asset
|
||||||
|
value: string
|
||||||
|
presenter?: AnyComponent
|
||||||
|
placeholder: IntlString
|
||||||
|
provider: Ref<ChannelProvider>
|
||||||
|
integration: boolean
|
||||||
|
notification: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProvider (
|
||||||
|
item: AttachedData<Channel>,
|
||||||
|
map: Map<Ref<ChannelProvider>, ChannelProvider>,
|
||||||
|
lastViews: Map<Ref<Doc>, Timestamp>
|
||||||
|
): any | undefined {
|
||||||
|
const provider = map.get(item.provider)
|
||||||
|
if (provider) {
|
||||||
|
const notification = (item as Channel)._id !== undefined ? isNew((item as Channel), lastViews) : false
|
||||||
|
return {
|
||||||
|
label: provider.label,
|
||||||
|
icon: provider.icon as Asset,
|
||||||
|
value: item.value,
|
||||||
|
presenter: provider.presenter,
|
||||||
|
placeholder: provider.placeholder,
|
||||||
|
provider: provider._id,
|
||||||
|
notification,
|
||||||
|
integration: provider.integrationType !== undefined ? integrations.has(provider.integrationType) : false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('provider not found: ', item.provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNew (item: Channel, lastViews: Map<Ref<Doc>, Timestamp>): boolean {
|
||||||
|
const lastView = (item as Channel)._id !== undefined ? lastViews.get((item as Channel)._id) : undefined
|
||||||
|
return lastView ? lastView < item.modifiedOn : (item.items ?? 0) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
async function update (value: AttachedData<Channel>[] | Channel | null, lastViews: Map<Ref<Doc>, Timestamp>) {
|
||||||
|
if (value === null) {
|
||||||
|
displayItems = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const result = []
|
||||||
|
const map = await getChannelProviders()
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (const item of value) {
|
||||||
|
const provider = getProvider(item, map, lastViews)
|
||||||
|
if (provider !== undefined) {
|
||||||
|
result.push(provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const provider = getProvider(value, map, lastViews)
|
||||||
|
if (provider !== undefined) {
|
||||||
|
result.push(provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayItems = result
|
||||||
|
updateMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (value) update(value, $lastViews)
|
||||||
|
|
||||||
|
let providers: Map<Ref<ChannelProvider>, ChannelProvider>
|
||||||
|
let displayItems: Item[] = []
|
||||||
|
let actions: Action[] = []
|
||||||
|
let addBtn: HTMLButtonElement
|
||||||
|
|
||||||
|
function filterUndefined (channels: AttachedData<Channel>[]): AttachedData<Channel>[] {
|
||||||
|
return channels.filter((channel) => channel.value !== undefined && channel.value.length > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
getChannelProviders().then(pr => providers = pr)
|
||||||
|
|
||||||
|
const updateMenu = (): void => {
|
||||||
|
actions = []
|
||||||
|
providers.forEach(pr => {
|
||||||
|
if (displayItems.filter(it => it.provider === pr._id).length == 0) {
|
||||||
|
actions.push({
|
||||||
|
icon: pr.icon ?? contact.icon.SocialEdit,
|
||||||
|
label: pr.label,
|
||||||
|
action: async () => {
|
||||||
|
const provider = getProvider({ provider: pr._id, value: '' }, providers, $lastViews)
|
||||||
|
if (provider !== undefined) {
|
||||||
|
if (displayItems.filter(it => it.provider === pr._id).length === 0) {
|
||||||
|
displayItems = [...displayItems, provider]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$: if (providers) updateMenu()
|
||||||
|
|
||||||
|
const editChannel = (channel: Item, n: number, ev: MouseEvent): void => {
|
||||||
|
showPopup(
|
||||||
|
ChannelEditor,
|
||||||
|
{ value: channel.value, placeholder: channel.placeholder },
|
||||||
|
ev.target as HTMLElement,
|
||||||
|
result => {
|
||||||
|
if (result !== undefined) {
|
||||||
|
if (result == null || result === '') {
|
||||||
|
displayItems = displayItems.filter((it, i) => i !== n)
|
||||||
|
} else {
|
||||||
|
displayItems[n].value = result
|
||||||
|
value = filterUndefined(displayItems)
|
||||||
|
}
|
||||||
|
updateMenu()
|
||||||
|
if (actions.length > 0 && addBtn) addBtn.click()
|
||||||
|
}
|
||||||
|
value = filterUndefined(displayItems)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const showMenu = (ev: MouseEvent): void => {
|
||||||
|
showPopup(Menu, { actions }, ev.target as HTMLElement)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each displayItems as item, i}
|
||||||
|
{#if item.value === ''}
|
||||||
|
<Button
|
||||||
|
icon={item.icon} {kind} {size} click={item.value === ''}
|
||||||
|
on:click={(ev) => { if (editable) editChannel(item, i, ev) }}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<Tooltip component={ChannelsPopup} props={{ value: item }} label={undefined}>
|
||||||
|
<Button
|
||||||
|
icon={item.icon} {kind} {size} click={item.value === ''}
|
||||||
|
on:click={(ev) => { if (editable) editChannel(item, i, ev) }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{#if actions.length > 0}
|
||||||
|
<Button
|
||||||
|
bind:input={addBtn}
|
||||||
|
icon={contact.icon.SocialEdit}
|
||||||
|
label={presentation.string.AddSocialLinks}
|
||||||
|
{kind} {size}
|
||||||
|
on:click={showMenu}
|
||||||
|
/>
|
||||||
|
{/if}
|
@ -22,6 +22,7 @@
|
|||||||
import { Button, EditBox, eventToHTMLElement, IconInfo, Label, showPopup } from '@anticrm/ui'
|
import { Button, EditBox, eventToHTMLElement, IconInfo, Label, showPopup } from '@anticrm/ui'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import contact from '../plugin'
|
import contact from '../plugin'
|
||||||
|
import { ChannelsDropdown } from '..'
|
||||||
import ChannelsView from './ChannelsView.svelte'
|
import ChannelsView from './ChannelsView.svelte'
|
||||||
import PersonPresenter from './PersonPresenter.svelte'
|
import PersonPresenter from './PersonPresenter.svelte'
|
||||||
|
|
||||||
@ -102,29 +103,18 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<div class="flex-row-center">
|
<div class="flex-row-center">
|
||||||
<div class="mr-4">
|
<div class="flex-grow flex-col">
|
||||||
<EditableAvatar avatar={object.avatar} size={'large'} on:done={onAvatarDone} on:remove={removeAvatar} />
|
|
||||||
</div>
|
|
||||||
<div class="flex-col">
|
|
||||||
<EditBox placeholder={contact.string.PersonFirstNamePlaceholder} bind:value={firstName} kind={'large-style'} maxWidth={'32rem'} focus />
|
<EditBox placeholder={contact.string.PersonFirstNamePlaceholder} bind:value={firstName} kind={'large-style'} maxWidth={'32rem'} focus />
|
||||||
<EditBox placeholder={contact.string.PersonLastNamePlaceholder} bind:value={lastName} kind={'large-style'} maxWidth={'32rem'} />
|
<EditBox placeholder={contact.string.PersonLastNamePlaceholder} bind:value={lastName} kind={'large-style'} maxWidth={'32rem'} />
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<EditBox placeholder={contact.string.PersonLocationPlaceholder} bind:value={object.city} kind={'small-style'} maxWidth={'32rem'} />
|
<EditBox placeholder={contact.string.PersonLocationPlaceholder} bind:value={object.city} kind={'small-style'} maxWidth={'32rem'} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ml-4">
|
||||||
|
<EditableAvatar avatar={object.avatar} size={'large'} on:done={onAvatarDone} on:remove={removeAvatar} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if channels.length > 0}
|
<svelte:fragment slot="pool">
|
||||||
<div class="ml-22"><ChannelsView value={channels} size={'small'} on:click /></div>
|
<ChannelsDropdown bind:value={channels} />
|
||||||
{/if}
|
|
||||||
<svelte:fragment slot="footer">
|
|
||||||
<Button
|
|
||||||
icon={contact.icon.SocialEdit}
|
|
||||||
kind={'transparent'}
|
|
||||||
on:click={(ev) =>
|
|
||||||
showPopup(contact.component.SocialEditor, { values: channels }, eventToHTMLElement(ev), (result) => {
|
|
||||||
if (result !== undefined) channels = result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -22,6 +22,7 @@ import Channels from './components/Channels.svelte'
|
|||||||
import ChannelsEditor from './components/ChannelsEditor.svelte'
|
import ChannelsEditor from './components/ChannelsEditor.svelte'
|
||||||
import ChannelsPresenter from './components/ChannelsPresenter.svelte'
|
import ChannelsPresenter from './components/ChannelsPresenter.svelte'
|
||||||
import ChannelsView from './components/ChannelsView.svelte'
|
import ChannelsView from './components/ChannelsView.svelte'
|
||||||
|
import ChannelsDropdown from './components/ChannelsDropdown.svelte'
|
||||||
import ContactPresenter from './components/ContactPresenter.svelte'
|
import ContactPresenter from './components/ContactPresenter.svelte'
|
||||||
import Contacts from './components/Contacts.svelte'
|
import Contacts from './components/Contacts.svelte'
|
||||||
import CreateOrganization from './components/CreateOrganization.svelte'
|
import CreateOrganization from './components/CreateOrganization.svelte'
|
||||||
@ -38,7 +39,7 @@ import EmployeeAccountPresenter from './components/EmployeeAccountPresenter.svel
|
|||||||
import OrganizationEditor from './components/OrganizationEditor.svelte'
|
import OrganizationEditor from './components/OrganizationEditor.svelte'
|
||||||
import OrganizationSelector from './components/OrganizationSelector.svelte'
|
import OrganizationSelector from './components/OrganizationSelector.svelte'
|
||||||
|
|
||||||
export { Channels, ChannelsEditor, ContactPresenter, ChannelsView, OrganizationSelector }
|
export { Channels, ChannelsEditor, ContactPresenter, ChannelsView, OrganizationSelector, ChannelsDropdown }
|
||||||
|
|
||||||
async function queryContact (_class: Ref<Class<Contact>>, client: Client, search: string): Promise<ObjectSearchResult[]> {
|
async function queryContact (_class: Ref<Class<Contact>>, client: Client, search: string): Promise<ObjectSearchResult[]> {
|
||||||
return (await client.findAll(_class, { name: { $like: `%${search}%` } }, { limit: 200 })).map(e => ({
|
return (await client.findAll(_class, { name: { $like: `%${search}%` } }, { limit: 200 })).map(e => ({
|
||||||
|
@ -151,29 +151,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.clear-btn {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: .75rem;
|
|
||||||
height: .75rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: .625rem;
|
|
||||||
height: .625rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.show {
|
|
||||||
color: var(--content-color);
|
|
||||||
background-color: var(--button-border-color);
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
color: var(--accent-color);
|
|
||||||
background-color: var(--button-border-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.counter {
|
.counter {
|
||||||
padding-right: .125rem;
|
padding-right: .125rem;
|
||||||
min-width: 1.5rem;
|
min-width: 1.5rem;
|
||||||
|
Loading…
Reference in New Issue
Block a user