Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
617a5c8
Restructured print document architecture
nguyen-katie Apr 1, 2026
3085ab4
fixed breadcrumbs not showing, print design changes
nguyen-katie Apr 1, 2026
36b9a61
printing design changes and component rendered all the time
nguyen-katie Apr 5, 2026
e7bb8c1
header and footer added to print preview
nguyen-katie Apr 6, 2026
d061bd7
put body text into columns with segmentation
nguyen-katie Apr 6, 2026
56a5eb7
empty last page stub
nguyen-katie Apr 6, 2026
ccc2d49
empty last page stub
nguyen-katie Apr 6, 2026
865a53d
created print-layout.tsx
nguyen-katie Apr 6, 2026
e6e254a
created printing components for document tabs
nguyen-katie Apr 6, 2026
66fac2d
removed unnecessary variables in components
nguyen-katie Apr 6, 2026
d98092b
style migration
nguyen-katie Apr 7, 2026
a18da67
condensed print document architecture and design
nguyen-katie Apr 8, 2026
5551937
Merge remote-tracking branch 'origin' into 574-update-to-printing-tools
nguyen-katie Apr 8, 2026
c6312f0
document info design
nguyen-katie Apr 9, 2026
16237f4
erased unnecessary components and finished metadata & og doc design
nguyen-katie Apr 9, 2026
e2f0876
fixed phonetics formatting and designs for original docs and metadata…
nguyen-katie Apr 11, 2026
193b6c2
fixed bug where content still loading in print
nguyen-katie Apr 11, 2026
4185683
Merge branch 'main' into 574-update-to-printing-tools
nguyen-katie Apr 11, 2026
780f16e
migrated change dialog component from user-management-frontend branch…
nguyen-katie May 6, 2026
6385435
Merge branch 'main' into 574-update-to-printing-tools
nguyen-katie May 6, 2026
1b85211
Merge remote-tracking branch 'origin' into 574-update-to-printing-tools
nguyen-katie May 6, 2026
67f2c8d
overlap bug fix in doc info and dialog update
nguyen-katie May 7, 2026
8118060
Merge branch '574-update-to-printing-tools' of https://github.com/NEU…
nguyen-katie May 7, 2026
9e05cf7
initialized glossary in print
nguyen-katie May 7, 2026
c78fb23
commented out some print features
nguyen-katie May 12, 2026
8de0747
made print menu its own component
nguyen-katie May 12, 2026
75ea71a
finished glossary implementation
nguyen-katie May 12, 2026
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
165 changes: 165 additions & 0 deletions website/src/components/user-management/change-dialog.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { globalStyle, style } from "@vanilla-extract/css"
import {
hspace,
layers,
mediaQueries,
radii,
space,
thickness,
vspace,
} from "src/style/constants"

export const backdrop = style({
position: "fixed",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(0, 0, 0, 0.5)",
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: layers.top,
})

export const dialog = style({
position: "relative",
backgroundColor: "white",
borderRadius: radii.large,
border: `${thickness.thin} solid #585858`,
padding: `${vspace.one} ${hspace.edge}`,
width: "90%",
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
"@media": {
[mediaQueries.medium]: {
width: "28.75rem",
height: "31.4375rem",
},
},
})

export const closeButtonContainer = style({
position: "absolute",
top: space.large,
right: space.large,
})

export const title = style({
font: `normal 400 1.625rem/1.2 'Charis SIL'`,
marginBottom: space.large,
marginTop: 0,
textAlign: "center",
color: "black",
})

export const subtitle = style({
font: `normal 400 1rem/1.2 'Charis SIL'`,
marginBottom: vspace.quarter,
marginTop: 0,
color: "black",
textAlign: "center",
})

export const body = style({
font: `normal 400 1.125rem/1.2 'Charis SIL'`,
textAlign: "center",
paddingBottom: "4rem",
"@media": {
[mediaQueries.medium]: {
paddingBottom: 0,
},
},
})

export const cancelButton = style({
width: "8.625rem",
height: "1.9375rem",
cursor: "pointer",
border: `${thickness.thin} solid #5c3b37`,
borderRadius: radii.large,
backgroundColor: "#ffffff",
font: `normal 400 0.9375rem/1.2 'Charis SIL'`,
})

export const closeButton = style({
width: "2rem",
height: "1.5rem",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
backgroundColor: "#965f5a",
border: `${thickness.thin} solid #5c3b37`,
font: `normal 400 1rem/1.2 'Charis SIL'`,
color: "white",
})

export const submitButton = style({
width: "8.625rem",
height: "1.9375rem",
cursor: "pointer",
border: `${thickness.thin} solid #5c3b37`,
borderRadius: radii.large,
backgroundColor: "#415373",
color: "white",
font: `normal 400 0.9375rem/1.2 'Charis SIL'`,
})

export const buttons = style({
display: "flex",
gap: space.medium,
justifyContent: "space-between",
marginTop: vspace.one,
"@media": {
[mediaQueries.medium]: {
position: "absolute",
bottom: "4.1875rem",
left: "3.5rem",
right: "3.5rem",
marginTop: 0,
},
},
})

export const dropdownGroup = style({
display: "flex",
flexDirection: "column",
})

export const dropdownLabel = style({
fontSize: "0.85rem",
fontWeight: 500,
margin: 0,
textAlign: "left",
alignSelf: "stretch",
paddingLeft: hspace.edge,
})

export const dropdownSelect = style({
width: "24rem",
height: "1.3rem",
maxWidth: "100%",
fontSize: "0.75rem",
textAlign: "center",
alignSelf: "center",
})

globalStyle(`${dropdownSelect} option`, {
textAlign: "center",
})

export const roleSelect = style({
width: "8rem",
height: "1.9375rem",
appearance: "none",
backgroundColor: "white",
border: `${thickness.thin} solid black`,
borderRadius: radii.large,
padding: "0 1.75rem 0 0.5rem",
font: `normal 400 0.9375rem/1.2 'Charis SIL'`,
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpolygon points='0,0 10,0 5,6' fill='%239f4d43'/%3E%3C/svg%3E"), linear-gradient(to left, #f8eeed 1.75rem, white 1.75rem)`,
backgroundRepeat: "no-repeat, no-repeat",
backgroundPosition: "right 0.6rem center, 0 0",
backgroundSize: "auto, 100%",
cursor: "pointer",
})
222 changes: 222 additions & 0 deletions website/src/components/user-management/change-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import React, { ReactNode, useEffect } from "react"
import { Button, Dialog, DialogBackdrop, useDialogState } from "reakit"
import { Link } from "src/components"
import { UserGroup } from "src/graphql/dailp"
import * as css from "./change-dialog.css"

interface CancelButtonProps {
onClick?: () => void
href?: string
children?: React.ReactNode
}

export const CancelButton = ({
onClick,
href,
children = "Cancel",
}: CancelButtonProps) => {
const button = (
<button type="button" onClick={onClick} className={css.cancelButton}>
{children}
</button>
)

return href ? <Link href={href}>{button}</Link> : button
}

interface CloseButtonProps {
onClick: () => void
className?: string
}

export const CloseButton = ({ onClick, className }: CloseButtonProps) => {
return (
<Button
className={`${css.closeButton}${className ? ` ${className}` : ""}`}
onClick={onClick}
aria-label="Close"
>
X
</Button>
)
}

interface SubmitButtonProps {
onClick?: () => void
type?: "submit" | "button"
children?: React.ReactNode
disabled?: boolean
}

export const SubmitButton = ({
onClick,
type = "button",
children = "Submit",
disabled,
}: SubmitButtonProps) => {
return (
<button
type={type}
onClick={onClick}
className={css.submitButton}
disabled={disabled}
>
{children}
</button>
)
}

interface EmptyDialogProps {
isOpen: boolean
onClose: () => void
title?: string
subtitle?: string
children: ReactNode
}

export const EmptyDialog = ({
isOpen,
onClose,
title,
subtitle,
children,
}: EmptyDialogProps) => {
const dialog = useDialogState()

useEffect(() => {
if (isOpen) {
dialog.show()
} else {
dialog.hide()
}
}, [isOpen])

const handleClose = () => {
onClose()
dialog.hide()
}

return (
<DialogBackdrop {...dialog} className={css.backdrop}>
<Dialog
{...dialog}
className={css.dialog}
aria-label={title || "Dialog"}
hideOnClickOutside={false}
>
<div className={css.closeButtonContainer}>
<CloseButton onClick={handleClose} />
</div>

{title && <h1 className={css.title}>{title}</h1>}
{subtitle && <h2 className={css.subtitle}>{subtitle}</h2>}

<div className={css.body}>{children}</div>
</Dialog>
</DialogBackdrop>
)
}

interface ConfirmationDialogProps {
isOpen: boolean
onClose: () => void
onConfirm: () => void
title?: string
subtitle?: string
children: React.ReactNode
cancelText?: string
confirmText?: string
}

export const ConfirmationDialog = ({
isOpen,
onClose,
onConfirm,
title,
subtitle,
children,
}: ConfirmationDialogProps) => {
return (
<EmptyDialog
isOpen={isOpen}
onClose={onClose}
title={title}
subtitle={subtitle}
>
{children}

<div className={css.buttons}>
<CancelButton onClick={onClose} />
<SubmitButton onClick={onConfirm} />
</div>
</EmptyDialog>
)
}

interface DropdownProps {
label: string
options: string[]
value: string
onChange: (value: string) => void
}

export const Dropdown = ({
label,
options,
value,
onChange,
}: DropdownProps) => (
<div className={css.dropdownGroup}>
<p className={css.dropdownLabel}>{label}</p>
<select
className={css.dropdownSelect}
value={value}
onChange={(e) => onChange(e.target.value)}
>
{options.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
</div>
)

const userRoles: { value: UserGroup; label: string }[] = [
{ value: UserGroup.Readers, label: "Reader" },
{ value: UserGroup.Contributors, label: "Contributor" },
{ value: UserGroup.Editors, label: "Editor" },
{ value: UserGroup.Administrators, label: "Admin" },
]

interface RoleDropdownProps
extends Omit<React.ComponentProps<"select">, "onChange" | "value"> {
value: UserGroup
onChange: (role: UserGroup) => void
}

export const RoleDropdown = ({
value,
onChange,
...props
}: RoleDropdownProps) => {
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const role = userRoles.find((r) => r.value === e.target.value)?.value
if (role) onChange(role)
}

return (
<select
{...props}
className={css.roleSelect}
value={value}
onChange={handleChange}
>
{userRoles.map((r) => (
<option key={r.value} value={r.value}>
{r.label}
</option>
))}
</select>
)
}
Loading
Loading