Skip to content

Commit

Permalink
Merge pull request #825 from traPtitech/fix/issue-820
Browse files Browse the repository at this point in the history
  • Loading branch information
eyemono-moe authored Dec 11, 2023
2 parents 186646a + a5b7daa commit feb95c1
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 79 deletions.
3 changes: 3 additions & 0 deletions dashboard/src/components/UI/UserAvater.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const UserAvatar: Component<UserAvatarProps> = (props) => {
style={{
width: addedProps.size ? `${addedProps.size}px` : '100%',
}}
width={addedProps.size}
height={addedProps.size}
loading="lazy"
alt={addedProps.user.name}
{...originalImgProps}
/>
Expand Down
128 changes: 88 additions & 40 deletions dashboard/src/components/templates/OwnerList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { style } from '@macaron-css/core'
import { styled } from '@macaron-css/solid'
import { createVirtualizer } from '@tanstack/solid-virtual'
import Fuse from 'fuse.js'
import { Component, For, Show, createMemo, createSignal } from 'solid-js'
import { User } from '/@/api/neoshowcase/protobuf/gateway_pb'
Expand All @@ -23,24 +25,29 @@ const AddOwnersContainer = styled('div', {
width: '100%',
height: '100%',
maxHeight: '100%',
display: 'grid',
gridTemplateRows: 'auto 1fr',
display: 'flex',
flexDirection: 'column',
gap: '16px',
},
})
const UsersContainer = styled('div', {
base: {
width: '100%',
height: '100%',
height: 'auto',
maxHeight: '100%',
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',

border: `1px solid ${colorVars.semantic.ui.border}`,
borderRadius: '8px',
},
})
const bordered = style({
selectors: {
'&:not(:last-child)': {
borderBottom: `1px solid ${colorVars.semantic.ui.border}`,
},
},
})
const UserRowContainer = styled('div', {
base: {
width: '100%',
Expand All @@ -49,12 +56,6 @@ const UserRowContainer = styled('div', {
flexDirection: 'row',
alignItems: 'center',
gap: '8px',

selectors: {
'&:not(:last-child)': {
borderBottom: `1px solid ${colorVars.semantic.ui.border}`,
},
},
},
})
const UserName = styled('div', {
Expand All @@ -67,12 +68,19 @@ const UserName = styled('div', {
const UserPlaceholder = styled('div', {
base: {
width: '100%',
height: '100%',
padding: '16px 20px',
display: 'flex',
flexDirection: 'column',
gap: '24px',
alignItems: 'center',
justifyContent: 'center',
color: colorVars.semantic.text.grey,
...textVars.text.medium,

border: `1px solid ${colorVars.semantic.ui.border}`,
borderRadius: '8px',
background: colorVars.semantic.ui.primary,
color: colorVars.semantic.text.black,
...textVars.h4.medium,
},
})

Expand All @@ -96,6 +104,16 @@ const AddOwners: Component<{
.map((result) => result.item)
})

const [containerRef, setContainerRef] = createSignal<HTMLDivElement | null>(null)
const virtualizer = createMemo(() =>
createVirtualizer({
count: filteredUsers().length,
getScrollElement: containerRef,
estimateSize: () => 64,
}),
)
const items = () => virtualizer().getVirtualItems()

return (
<AddOwnersContainer>
<TextField
Expand All @@ -104,22 +122,50 @@ const AddOwners: Component<{
value={searchUserQuery()}
onInput={(e) => setSearchUserQuery(e.currentTarget.value)}
/>
<UsersContainer>
<For each={filteredUsers()}>
{(user) => (
<UserRowContainer>
<UserAvatar user={user} size={32} />
<UserName>{user.name}</UserName>
<Button variants="ghost" size="small" onClick={() => props.addOwner(user)}>
Add
</Button>
</UserRowContainer>
)}
</For>
<Show when={filteredUsers().length === 0}>
<UserPlaceholder>No Users Found</UserPlaceholder>
</Show>
</UsersContainer>
<Show
when={filteredUsers().length !== 0}
fallback={
<UserPlaceholder>
<MaterialSymbols displaySize={80}>search</MaterialSymbols>
No Users Found
</UserPlaceholder>
}
>
<UsersContainer ref={setContainerRef}>
<div
style={{
width: '100%',
height: `${virtualizer().getTotalSize()}px`,
position: 'relative',
}}
>
<For each={items() ?? []}>
{(vRow) => (
<div
data-index={vRow.index}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${vRow.size}px`,
transform: `translateY(${vRow.start}px)`,
}}
class={bordered}
>
<UserRowContainer>
<UserAvatar user={filteredUsers()[vRow.index]} size={32} />
<UserName>{filteredUsers()[vRow.index].name}</UserName>
<Button variants="ghost" size="small" onClick={() => props.addOwner(filteredUsers()[vRow.index])}>
Add
</Button>
</UserRowContainer>
</div>
)}
</For>
</div>
</UsersContainer>
</Show>
</AddOwnersContainer>
)
}
Expand All @@ -132,15 +178,17 @@ const OwnerRow: Component<{

return (
<>
<UserRowContainer>
<UserAvatar user={props.user} size={32} />
<UserName>{props.user.name}</UserName>
<Show when={props.deleteOwner !== undefined}>
<Button variants="textError" size="small" onClick={openDeleteUserModal}>
Delete
</Button>
</Show>
</UserRowContainer>
<div class={bordered}>
<UserRowContainer>
<UserAvatar user={props.user} size={32} />
<UserName>{props.user.name}</UserName>
<Show when={props.deleteOwner !== undefined}>
<Button variants="textError" size="small" onClick={openDeleteUserModal}>
Delete
</Button>
</Show>
</UserRowContainer>
</div>
<DeleteUserModal.Container>
<DeleteUserModal.Header>Delete Owner</DeleteUserModal.Header>
<DeleteUserModal.Body>
Expand Down Expand Up @@ -221,9 +269,9 @@ const OwnerList: Component<{
>
Add Owners
</Button>
<AddUserModal.Container>
<AddUserModal.Container fit={false}>
<AddUserModal.Header>Add Owner</AddUserModal.Header>
<AddUserModal.Body>
<AddUserModal.Body fit={false}>
<AddOwners addOwner={props.handleAddOwner} nonOwners={nonOwners()} />
</AddUserModal.Body>
</AddUserModal.Container>
Expand Down
114 changes: 75 additions & 39 deletions dashboard/src/libs/useModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dialog } from '@kobalte/core'
import { As, Dialog } from '@kobalte/core'
import { keyframes, style } from '@macaron-css/core'
import { styled } from '@macaron-css/solid'
import { ParentComponent, Show, createSignal, mergeProps } from 'solid-js'
Expand Down Expand Up @@ -61,25 +61,39 @@ const contentHide = keyframes({
transform: 'scale(0.95)',
},
})
const contentStyle = style({
position: 'relative',
width: '100%',
maxWidth: '568px',
height: 'auto',
maxHeight: '100%',
display: 'flex',
flexDirection: 'column',
background: colorVars.semantic.ui.primary,
borderRadius: '12px',
opacity: 1,
overflow: 'hidden',
const Content = styled('div', {
base: {
position: 'relative',
width: '100%',
maxWidth: '568px',
maxHeight: '100%',
display: 'flex',
flexDirection: 'column',
background: colorVars.semantic.ui.primary,
borderRadius: '12px',
opacity: 1,
overflow: 'hidden',

animation: `${contentHide} 0.3s`,
selectors: {
'&[data-expanded]': {
animation: `${contentShow} 0.3s`,
animation: `${contentHide} 0.3s`,
selectors: {
'&[data-expanded]': {
animation: `${contentShow} 0.3s`,
},
},
},
variants: {
fit: {
true: {
height: 'auto',
},
false: {
height: '100%',
},
},
},
defaultVariants: {
fit: true,
},
})
const DialogHeader = styled('div', {
base: {
Expand All @@ -91,30 +105,39 @@ const DialogHeader = styled('div', {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',

selectors: {
'&:not(:last-child)': {
borderBottom: `2px solid ${colorVars.semantic.ui.border}`,
},
},
},
})
const titleStyle = style({
color: colorVars.semantic.text.black,
...textVars.h2.medium,
})
const descriptionStyle = style({
width: '100%',
height: 'auto',
maxHeight: '100%',
display: 'flex',
overflowY: 'hidden',
padding: '24px 32px',
selectors: {
'&:not(:last-child)': {
borderBottom: `2px solid ${colorVars.semantic.ui.border}`,
const Description = styled('div', {
base: {
width: '100%',
height: 'auto',
maxHeight: '100%',
display: 'flex',
overflowY: 'hidden',
padding: '24px 32px',
selectors: {
[`${DialogHeader.selector({})}~&`]: {
borderTop: `2px solid ${colorVars.semantic.ui.border}`,
},
},
},
variants: {
fit: {
true: {
height: 'auto',
},
false: {
height: '100%',
},
},
},
defaultVariants: {
fit: true,
},
})
const ModalFooter = styled('div', {
base: {
Expand All @@ -127,6 +150,11 @@ const ModalFooter = styled('div', {
justifyContent: 'flex-end',
alignItems: 'center',
gap: '8px',
selectors: {
[`${Description.selector({})}~&`]: {
borderTop: `2px solid ${colorVars.semantic.ui.border}`,
},
},
},
})
const closeButtonStyle = style({
Expand Down Expand Up @@ -168,18 +196,22 @@ const useModal = (options?: {
// モーダルを閉じるときはclose()を呼ぶ
const close = () => setIsOpen(false)

const Container: ParentComponent = (props) => {
const Container: ParentComponent<{
fit?: boolean
}> = (props) => {
return (
<Dialog.Root open={isOpen()}>
<Dialog.Portal>
<Dialog.Overlay class={overlayStyle} />
<DialogPositioner>
<Dialog.Content
class={contentStyle}
onEscapeKeyDown={close}
onPointerDownOutside={mergedProps.closeOnClickOutside ? close : undefined}
asChild
>
{props.children}
<As component={Content} fit={props.fit}>
{props.children}
</As>
</Dialog.Content>
</DialogPositioner>
</Dialog.Portal>
Expand All @@ -200,10 +232,14 @@ const useModal = (options?: {
)
}

const Body: ParentComponent = (props) => {
const Body: ParentComponent<{
fit?: boolean
}> = (props) => {
return (
<Dialog.Description as="div" class={descriptionStyle}>
{props.children}
<Dialog.Description asChild>
<As component={Description} fit={props.fit}>
{props.children}
</As>
</Dialog.Description>
)
}
Expand Down

0 comments on commit feb95c1

Please sign in to comment.