Replace modals for people actions

This commit is contained in:
viktorstrate
2021-07-13 13:56:05 +02:00
parent 1fa92c4fe1
commit 6b5cd89db3
8 changed files with 197 additions and 215 deletions

View File

@@ -2,8 +2,8 @@ import { gql, useMutation } from '@apollo/client'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useHistory } from 'react-router-dom'
import { Button, Modal } from 'semantic-ui-react'
import { isNil } from '../../../helpers/utils'
import Modal from '../../../primitives/Modal'
import { MY_FACES_QUERY } from '../PeoplePage'
import {
myFaces_myFaceGroups,
@@ -83,46 +83,42 @@ const DetachImageFacesModal = ({
return (
<Modal
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
open={open}
>
<Modal.Header>
{t('people_page.modal.detach_image_faces.title', 'Detach Image Faces')}
</Modal.Header>
<Modal.Content scrolling>
<Modal.Description>
<p>
{t(
'people_page.modal.detach_image_faces.description',
'Detach selected images of this face group and move them to a new face groups'
)}
</p>
<SelectImageFacesTable
imageFaces={imageFaces}
selectedImageFaces={selectedImageFaces}
setSelectedImageFaces={setSelectedImageFaces}
title={t(
'people_page.modal.detach_image_faces.action.select_images',
'Select images to detach'
)}
/>
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button
disabled={selectedImageFaces.length == 0}
content={t(
title={t(
'people_page.modal.detach_image_faces.title',
'Detach Image Faces'
)}
description={t(
'people_page.modal.detach_image_faces.description',
'Detach selected images of this face group and move them to a new face groups'
)}
actions={[
{
key: 'cancel',
label: 'Cancel',
onClick: () => setOpen(false),
},
{
key: 'detach',
label: t(
'people_page.modal.detach_image_faces.action.detach',
'Detach image faces'
)}
labelPosition="right"
icon="checkmark"
onClick={() => detachImageFaces()}
positive
/>
</Modal.Actions>
),
variant: 'positive',
onClick: () => detachImageFaces(),
},
]}
onClose={() => setOpen(false)}
open={open}
>
<SelectImageFacesTable
imageFaces={imageFaces}
selectedImageFaces={selectedImageFaces}
setSelectedImageFaces={setSelectedImageFaces}
title={t(
'people_page.modal.detach_image_faces.action.select_images',
'Select images to detach'
)}
/>
</Modal>
)
}

View File

@@ -1,9 +1,9 @@
import { useMutation } from '@apollo/client'
import React, { useState, useEffect, createRef } from 'react'
import { useTranslation } from 'react-i18next'
import { Dropdown, Input } from 'semantic-ui-react'
import styled from 'styled-components'
import { Input } from 'semantic-ui-react'
import { isNil } from '../../../helpers/utils'
import { Button } from '../../../primitives/form/Input'
import { SET_GROUP_LABEL_MUTATION } from '../PeoplePage'
import {
setGroupLabel,
@@ -14,26 +14,6 @@ import MergeFaceGroupsModal from './MergeFaceGroupsModal'
import MoveImageFacesModal from './MoveImageFacesModal'
import { singleFaceGroup_faceGroup } from './__generated__/singleFaceGroup'
const TitleWrapper = styled.div`
min-height: 3.5em;
`
const TitleLabel = styled.h1<{ labeled: boolean }>`
display: inline-block;
color: ${({ labeled }) => (labeled ? 'black' : '#888')};
margin-right: 12px;
`
const TitleDropdown = styled(Dropdown)`
vertical-align: middle;
margin-top: -10px;
color: #888;
&:hover {
color: #1e70bf;
}
`
type FaceGroupTitleProps = {
faceGroup?: singleFaceGroup_faceGroup
}
@@ -92,12 +72,80 @@ const FaceGroupTitle = ({ faceGroup }: FaceGroupTitleProps) => {
let title
if (!editLabel) {
title = (
<TitleWrapper>
<TitleLabel labeled={!!faceGroup?.label}>
<>
<h1
className={`text-2xl font-semibold ${
faceGroup?.label ? 'text-black' : 'text-gray-600'
}`}
>
{faceGroup?.label ??
t('people_page.face_group.unlabeled_person', 'Unlabeled person')}
</TitleLabel>
<TitleDropdown
</h1>
</>
)
} else {
title = (
<>
<Input
loading={setLabelLoading}
ref={inputRef}
placeholder={t('people_page.face_group.label_placeholder', 'Label')}
icon="arrow right"
value={inputValue}
onKeyUp={onKeyUp}
onChange={e => setInputValue(e.target.value)}
onBlur={() => {
resetLabel()
}}
/>
</>
)
}
let modals = null
if (faceGroup) {
modals = (
<>
<MergeFaceGroupsModal
open={mergeModalOpen}
setOpen={setMergeModalOpen}
sourceFaceGroup={faceGroup}
/>
<MoveImageFacesModal
open={moveModalOpen}
setOpen={setMoveModalOpen}
faceGroup={faceGroup}
/>
<DetachImageFacesModal
open={detachModalOpen}
setOpen={setDetachModalOpen}
faceGroup={faceGroup}
/>
</>
)
}
return (
<>
<div>
<div className="mb-2">{title}</div>
<ul className="flex gap-2 flex-wrap mb-6">
<li>
<Button onClick={() => setEditLabel(true)}>Change label</Button>
</li>
<li>
<Button onClick={() => setMergeModalOpen(true)}>Merge face</Button>
</li>
<li>
<Button onClick={() => setDetachModalOpen(true)}>
Detach face
</Button>
</li>
<li>
<Button onClick={() => setMoveModalOpen(true)}>Move faces</Button>
</li>
</ul>
{/* <TitleDropdown
icon={{
name: 'settings',
size: 'large',
@@ -135,54 +183,8 @@ const FaceGroupTitle = ({ faceGroup }: FaceGroupTitleProps) => {
onClick={() => setMoveModalOpen(true)}
/>
</Dropdown.Menu>
</TitleDropdown>
</TitleWrapper>
)
} else {
title = (
<TitleWrapper>
<Input
loading={setLabelLoading}
ref={inputRef}
placeholder={t('people_page.face_group.label_placeholder', 'Label')}
icon="arrow right"
value={inputValue}
onKeyUp={onKeyUp}
onChange={e => setInputValue(e.target.value)}
onBlur={() => {
resetLabel()
}}
/>
</TitleWrapper>
)
}
let modals = null
if (faceGroup) {
modals = (
<>
<MergeFaceGroupsModal
open={mergeModalOpen}
setOpen={setMergeModalOpen}
sourceFaceGroup={faceGroup}
/>
<MoveImageFacesModal
open={moveModalOpen}
setOpen={setMoveModalOpen}
faceGroup={faceGroup}
/>
<DetachImageFacesModal
open={detachModalOpen}
setOpen={setDetachModalOpen}
faceGroup={faceGroup}
/>
</>
)
}
return (
<>
{title}
</TitleDropdown> */}
</div>
{modals}
</>
)

View File

@@ -2,8 +2,8 @@ import { gql, useMutation, useQuery } from '@apollo/client'
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useHistory } from 'react-router-dom'
import { Button, Modal } from 'semantic-ui-react'
import { isNil } from '../../../helpers/utils'
import Modal from '../../../primitives/Modal'
import { MY_FACES_QUERY } from '../PeoplePage'
import {
myFaces,
@@ -78,45 +78,39 @@ const MergeFaceGroupsModal = ({
return (
<Modal
title={t(
'people_page.modal.merge_face_groups.title',
'Merge Face Groups'
)}
description={t(
'people_page.modal.merge_face_groups.description',
'All images within this face group will be merged into the selected face group.'
)}
actions={[
{
key: 'cancel',
label: t('general.action.cancel', 'Cancel'),
onClick: () => setOpen(false),
},
{
key: 'merge',
label: t('people_page.modal.action.merge', 'Merge'),
onClick: () => mergeFaceGroups(),
variant: 'positive',
},
]}
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
open={open}
>
<Modal.Header>
{t('people_page.modal.merge_face_groups.title', 'Merge Face Groups')}
</Modal.Header>
<Modal.Content scrolling>
<Modal.Description>
<p>
{t(
'people_page.modal.merge_face_groups.description',
'All images within this face group will be merged into the selected face group.'
)}
</p>
<SelectFaceGroupTable
title={t(
'people_page.modal.merge_face_groups.destination_table.title',
'Select the destination face'
)}
faceGroups={filteredFaceGroups}
selectedFaceGroup={selectedFaceGroup}
setSelectedFaceGroup={setSelectedFaceGroup}
/>
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button onClick={() => setOpen(false)}>
{t('general.action.cancel', 'Cancel')}
</Button>
<Button
disabled={selectedFaceGroup == null}
content={t('people_page.modal.action.merge', 'Merge')}
labelPosition="right"
icon="checkmark"
onClick={() => mergeFaceGroups()}
positive
/>
</Modal.Actions>
<SelectFaceGroupTable
title={t(
'people_page.modal.merge_face_groups.destination_table.title',
'Select the destination face'
)}
faceGroups={filteredFaceGroups}
selectedFaceGroup={selectedFaceGroup}
setSelectedFaceGroup={setSelectedFaceGroup}
/>
</Modal>
)
}

View File

@@ -1,7 +1,6 @@
import { gql, useLazyQuery, useMutation } from '@apollo/client'
import React, { useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { Button, Modal } from 'semantic-ui-react'
import SelectFaceGroupTable from './SelectFaceGroupTable'
import SelectImageFacesTable from './SelectImageFacesTable'
import { MY_FACES_QUERY } from '../PeoplePage'
@@ -21,6 +20,7 @@ import {
moveImageFacesVariables,
} from './__generated__/moveImageFaces'
import { useTranslation } from 'react-i18next'
import Modal, { ModalAction } from '../../../primitives/Modal'
const MOVE_IMAGE_FACES_MUTATION = gql`
mutation moveImageFaces($faceIDs: [ID!]!, $destFaceGroupID: ID!) {
@@ -141,63 +141,48 @@ const MoveImageFacesModal = ({
}
}
let positiveButton = null
let positiveButton: ModalAction
if (!imagesSelected) {
positiveButton = (
<Button
disabled={selectedImageFaces.length == 0}
content={t(
'people_page.modal.move_image_faces.image_select_table.next_action',
'Next'
)}
labelPosition="right"
icon="arrow right"
onClick={() => setImagesSelected(true)}
positive
/>
)
positiveButton = {
key: 'next',
label: t(
'people_page.modal.move_image_faces.image_select_table.next_action',
'Next'
),
onClick: () => setImagesSelected(true),
variant: 'positive',
}
} else {
positiveButton = (
<Button
disabled={!selectedFaceGroup}
content={t(
'people_page.modal.move_image_faces.destination_face_group_table.move_action',
'Move image faces'
)}
labelPosition="right"
icon="checkmark"
onClick={() => moveImageFaces()}
positive
/>
)
positiveButton = {
key: 'move',
label: t(
'people_page.modal.move_image_faces.destination_face_group_table.move_action',
'Move image faces'
),
onClick: () => moveImageFaces(),
variant: 'positive',
}
}
return (
<Modal
title={t('people_page.modal.move_image_faces.title', 'Move Image Faces')}
description={t(
'people_page.modal.move_image_faces.description',
'Move selected images of this face group to another face group'
)}
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
open={open}
actions={[
{
key: 'cancel',
label: t('general.action.cancel', 'Cancel'),
onClick: () => setOpen(false),
},
positiveButton,
]}
>
<Modal.Header>
{t('people_page.modal.move_image_faces.title', 'Move Image Faces')}
</Modal.Header>
<Modal.Content scrolling>
<Modal.Description>
<p>
{t(
'people_page.modal.move_image_faces.description',
'Move selected images of this face group to another face group'
)}
</p>
{table}
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button onClick={() => setOpen(false)}>
{t('general.action.cancel', 'Cancel')}
</Button>
{positiveButton}
</Modal.Actions>
{table}
</Modal>
)
}

View File

@@ -95,8 +95,8 @@ const UsersTable = () => {
<TableRow>
<TableHeaderCell colSpan={4} className="text-right">
<Button
className="bg-white"
variant="positive"
background="white"
disabled={showAddUser}
onClick={() => setShowAddUser(true)}
>

View File

@@ -14,7 +14,7 @@ type MenuButtonProps = {
to: string
exact: boolean
label: string
gradient: string
background: string
activeClasses?: string
className?: string
icon?: React.ReactChild
@@ -24,7 +24,7 @@ const MenuButton = ({
to,
exact,
label,
gradient,
background,
icon,
activeClasses,
className,
@@ -38,7 +38,8 @@ const MenuButton = ({
>
<li className="flex items-center">
<div
className={`w-12 h-12 p-1.5 lg:w-8 lg:h-8 lg:p-1 bg-gradient-to-br ${gradient} w-full h-full rounded-lg`}
className={`w-12 h-12 p-1.5 lg:w-8 lg:h-8 lg:p-1 w-full h-full rounded-lg`}
style={{ backgroundColor: background }}
>
{icon}
</div>
@@ -66,7 +67,7 @@ export const MainMenu = () => {
to="/photos"
exact
label={t('sidemenu.photos', 'Timeline')}
gradient="from-[#AAD4F8] to-[#80B2E8]"
background="#8ac5f4"
activeClasses="ring-[#f1f8ff] bg-[#f1f8ff]"
className="outline-none focus:ring-2 focus:ring-blue-200 focus:ring-offset-2"
icon={
@@ -83,7 +84,7 @@ export const MainMenu = () => {
to="/albums"
exact
label={t('sidemenu.albums', 'Albums')}
gradient="from-[#F8AAAA] to-[#E88380]"
background="#fd9293"
activeClasses="ring-[#fff1f2] bg-[#fff1f2]"
className="outline-none focus:ring-2 focus:ring-red-200 focus:ring-offset-2"
icon={
@@ -101,7 +102,7 @@ export const MainMenu = () => {
to="/places"
exact
label={t('sidemenu.places', 'Places')}
gradient="from-[#B8EF7F] to-[#8CD77B]"
background="#92e072"
activeClasses="ring-[#e3fee5] bg-[#e3fee5]"
className="outline-none focus:ring-2 focus:ring-green-100 focus:ring-offset-2"
icon={
@@ -120,7 +121,7 @@ export const MainMenu = () => {
to="/people"
exact
label={t('sidemenu.people', 'People')}
gradient="from-[#F6F16E] to-[#F3C688]"
background="#fbcd78"
activeClasses="ring-[#fff7e4] bg-[#fff7e4]"
className="outline-none focus:ring-2 focus:ring-yellow-100 focus:ring-offset-2"
icon={
@@ -138,7 +139,7 @@ export const MainMenu = () => {
to="/settings"
exact
label={t('sidemenu.settings', 'Settings')}
gradient="from-[#C7E2E2] to-[#96AFBA]"
background="#aacbd0"
activeClasses="ring-[#e4f0f8] bg-[#e4f0f8]"
className="outline-none focus:ring-2 focus:ring-gray-200 focus:ring-offset-2"
icon={

View File

@@ -2,7 +2,7 @@ import React from 'react'
import { Dialog } from '@headlessui/react'
import { Button } from './form/Input'
type ModalAction = {
export type ModalAction = {
key: string
label: string
variant?: 'negative' | 'positive' | 'default'
@@ -31,7 +31,7 @@ const Modal = ({
key={x.key}
onClick={e => x.onClick(e)}
variant={x.variant}
className="bg-white"
background="white"
>
{x.label}
</Button>

View File

@@ -135,24 +135,27 @@ export const TextField = forwardRef(
type ButtonProps = {
variant?: 'negative' | 'positive' | 'default'
background?: 'default' | 'white'
}
const buttonStyles = ({ variant }: ButtonProps) =>
const buttonStyles = ({ variant, background }: ButtonProps) =>
classNames(
'bg-gray-50 px-6 py-0.5 rounded border border-gray-200 focus:outline-none focus:border-blue-300 text-[#222] hover:bg-gray-100 whitespace-nowrap',
'px-6 py-0.5 rounded border border-gray-200 focus:outline-none focus:border-blue-300 text-[#222] hover:bg-gray-100 whitespace-nowrap',
variant == 'negative' &&
'text-red-600 hover:bg-red-600 hover:border-red-700 hover:text-white transition-colors focus:border-red-600 focus:hover:border-red-700',
variant == 'positive' &&
'text-green-600 hover:bg-green-600 hover:border-green-700 hover:text-white transition-colors focus:border-green-600 focus:hover:border-green-700'
'text-green-600 hover:bg-green-600 hover:border-green-700 hover:text-white transition-colors focus:border-green-600 focus:hover:border-green-700',
background == 'white' ? 'bg-white' : 'bg-gray-50'
)
export const Submit = ({
className,
variant,
background,
...props
}: ButtonProps & React.ButtonHTMLAttributes<HTMLInputElement>) => (
<input
className={classNames(buttonStyles({ variant }), className)}
className={classNames(buttonStyles({ variant, background }), className)}
type="submit"
{...props}
/>
@@ -161,11 +164,12 @@ export const Submit = ({
export const Button = ({
children,
variant,
background,
className,
...props
}: ButtonProps & React.ButtonHTMLAttributes<HTMLButtonElement>) => (
<button
className={classNames(buttonStyles({ variant }), className)}
className={classNames(buttonStyles({ variant, background }), className)}
{...props}
>
{children}