frontend indentation set to 2

This commit is contained in:
Oliver Bryan
2026-01-21 17:47:04 +00:00
parent 70504b3056
commit 5a5e40659c
117 changed files with 7548 additions and 7785 deletions

View File

@@ -5,7 +5,7 @@
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 4,
"indentWidth": 2,
"lineWidth": 110
},
"css": {

View File

@@ -131,10 +131,7 @@ function Account({ trigger }: { trigger?: ReactNode }) {
</div>
<div className="flex flex-col items-start gap-1">
<Label className="text-sm">Icon Style</Label>
<Select
value={iconPreference}
onValueChange={(v) => setIconPreference(v as IconStyle)}
>
<Select value={iconPreference} onValueChange={(v) => setIconPreference(v as IconStyle)}>
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>

View File

@@ -111,10 +111,7 @@ export function AddMember({
Cancel
</Button>
</DialogClose>
<Button
type="submit"
disabled={submitting || (username.trim() === "" && submitAttempted)}
>
<Button type="submit" disabled={submitting || (username.trim() === "" && submitAttempted)}>
{submitting ? "Adding..." : "Add"}
</Button>
</div>

View File

@@ -286,9 +286,7 @@ export function IssueDetails({
} catch (error) {
console.error(`error deleting issue ${issueID(projectKey, issueData.Issue.number)}`, error);
toast.error(
`Error deleting issue ${issueID(projectKey, issueData.Issue.number)}: ${parseError(
error as Error,
)}`,
`Error deleting issue ${issueID(projectKey, issueData.Issue.number)}: ${parseError(error as Error)}`,
{
dismissible: false,
},
@@ -303,9 +301,7 @@ export function IssueDetails({
{showHeader && (
<div className="flex flex-row items-center justify-end border-b h-[25px]">
<span className="w-full">
<p className="text-sm w-fit px-1 font-700">
{issueID(projectKey, issueData.Issue.number)}
</p>
<p className="text-sm w-fit px-1 font-700">{issueID(projectKey, issueData.Issue.number)}</p>
</span>
<div className="flex items-center">
<IconButton onClick={handleCopyLink} title={linkCopied ? "Copied" : "Copy link"}>
@@ -334,11 +330,7 @@ export function IssueDetails({
chevronClassName="hidden"
isOpen={isOpen}
>
<StatusTag
status={value}
colour={statuses[value]}
className="hover:opacity-85"
/>
<StatusTag status={value} colour={statuses[value]} className="hover:opacity-85" />
</SelectTrigger>
)}
/>

View File

@@ -153,11 +153,7 @@ export function IssueForm({ trigger }: { trigger?: React.ReactNode }) {
chevronClassName="hidden"
isOpen={isOpen}
>
<StatusTag
status={value}
colour={statuses[value]}
className="hover:opacity-85"
/>
<StatusTag status={value} colour={statuses[value]} className="hover:opacity-85" />
</SelectTrigger>
)}
/>
@@ -203,11 +199,7 @@ export function IssueForm({ trigger }: { trigger?: React.ReactNode }) {
{members.length > 0 && (
<div className="flex items-start gap-2 mt-4">
<Label className="text-sm pt-2">Assignees</Label>
<MultiAssigneeSelect
users={members}
assigneeIds={assigneeIds}
onChange={setAssigneeIds}
/>
<MultiAssigneeSelect users={members} assigneeIds={assigneeIds} onChange={setAssigneeIds} />
</div>
)}
@@ -231,8 +223,7 @@ export function IssueForm({ trigger }: { trigger?: React.ReactNode }) {
submitting ||
((title.trim() === "" || title.trim().length > ISSUE_TITLE_MAX_LENGTH) &&
submitAttempted) ||
(description.trim().length > ISSUE_DESCRIPTION_MAX_LENGTH &&
submitAttempted)
(description.trim().length > ISSUE_DESCRIPTION_MAX_LENGTH && submitAttempted)
}
>
{submitting ? "Creating..." : "Create"}

View File

@@ -64,11 +64,7 @@ export function IssueTimer({ issueId, onEnd }: { issueId: number; onEnd?: (data:
<Button onClick={handleToggle}>
{!timerState ? "Start" : timerState.isRunning ? "Pause" : "Resume"}
</Button>
<Button
onClick={handleEnd}
variant="outline"
disabled={!timerState || timerState.endedAt != null}
>
<Button onClick={handleEnd} variant="outline" disabled={!timerState || timerState.endedAt != null}>
End
</Button>
</div>

View File

@@ -87,10 +87,7 @@ export function IssuesTable({
className="flex items-center gap-2 min-w-0 w-full h-full px-2 py-1 text-inherit hover:underline decoration-transparent"
>
{(columns.status == null || columns.status === true) && (
<StatusTag
status={issueData.Issue.status}
colour={statuses[issueData.Issue.status]}
/>
<StatusTag status={issueData.Issue.status} colour={statuses[issueData.Issue.status]} />
)}
<span className="truncate">{issueData.Issue.title}</span>
</a>

View File

@@ -4,9 +4,7 @@ export default function Loading({ message, children }: { message?: string; child
return (
<div className="flex flex-col items-center justify-center gap-4 w-full h-[100vh]">
<Spinner className="size-6" />
{message && (
<span className="text-xs px-2 py-1 border-2 border-input border-dashed">{message}</span>
)}
{message && <span className="text-xs px-2 py-1 border-2 border-input border-dashed">{message}</span>}
{children}
</div>
);

View File

@@ -158,8 +158,8 @@ export default function LogInForm() {
<Icon icon="alertTriangle" className="w-16 h-16 text-yellow-500" />
<div className="text-center text-sm text-muted-foreground font-500">
<p>
This application is currently under construction. Your data is very likely to be
lost at some point.
This application is currently under construction. Your data is very likely to be lost at some
point.
</p>
<p className="font-700 underline underline-offset-3 text-foreground/85 decoration-yellow-500 mt-2">
It is not recommended for production use.
@@ -191,16 +191,10 @@ export default function LogInForm() {
</div>
<div className="text-sm text-muted-foreground space-y-1">
<p>
<span className="font-medium text-foreground">
Username:
</span>{" "}
{user.username}
<span className="font-medium text-foreground">Username:</span> {user.username}
</p>
<p>
<span className="font-medium text-foreground">
Password:
</span>{" "}
{user.password}
<span className="font-medium text-foreground">Password:</span> {user.password}
</p>
</div>
</button>

View File

@@ -68,11 +68,7 @@ export default function OrgIcon({
)}
>
{iconURL ? (
<img
src={iconURL}
alt={name}
className={`rounded-md object-cover w-${size || 6} h-${size || 6}`}
/>
<img src={iconURL} alt={name} className={`rounded-md object-cover w-${size || 6} h-${size || 6}`} />
) : (
<span className={textClass}>{getInitials(name)}</span>
)}

View File

@@ -92,10 +92,7 @@ export function OrganisationSelect({
<SelectGroup>
<SelectLabel>Organisations</SelectLabel>
{organisations.map((organisation) => (
<SelectItem
key={organisation.Organisation.id}
value={`${organisation.Organisation.id}`}
>
<SelectItem key={organisation.Organisation.id} value={`${organisation.Organisation.id}`}>
<OrgIcon
name={organisation.Organisation.name}
slug={organisation.Organisation.slug}

View File

@@ -186,12 +186,9 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
});
} catch (err) {
console.error(err);
toast.error(
`Error ${action.slice(0, -1)}ing ${memberName} to ${newRole}: ${String(err)}`,
{
toast.error(`Error ${action.slice(0, -1)}ing ${memberName} to ${newRole}: ${String(err)}`, {
dismissible: false,
},
);
});
}
},
});
@@ -217,12 +214,9 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
userId: memberUserId,
});
closeConfirmDialog();
toast.success(
`Removed ${memberName} from ${selectedOrganisation.Organisation.name} successfully`,
{
toast.success(`Removed ${memberName} from ${selectedOrganisation.Organisation.name} successfully`, {
dismissible: false,
},
);
});
} catch (err) {
console.error(err);
toast.error(
@@ -259,8 +253,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
if (statusAdded) {
toast.success(
<>
Created <StatusTag status={statusAdded.name} colour={statusAdded.colour} /> status
successfully
Created <StatusTag status={statusAdded.name} colour={statusAdded.colour} /> status successfully
</>,
{
dismissible: false,
@@ -279,8 +272,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
} else if (statusMoved) {
toast.success(
<>
Moved <StatusTag status={statusMoved.name} colour={statusMoved.colour} /> from
position
Moved <StatusTag status={statusMoved.name} colour={statusMoved.colour} /> from position
{statusMoved.currentIndex + 1} to {statusMoved.nextIndex + 1} successfully
</>,
{
@@ -304,8 +296,8 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
} else if (statusRemoved) {
toast.error(
<>
Error removing <StatusTag status={statusRemoved.name} colour={statusRemoved.colour} />{" "}
from {selectedOrganisation.Organisation.name}: {String(err)}
Error removing <StatusTag status={statusRemoved.name} colour={statusRemoved.colour} /> from{" "}
{selectedOrganisation.Organisation.name}: {String(err)}
</>,
{
dismissible: false,
@@ -314,8 +306,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
} else if (statusMoved) {
toast.error(
<>
Error moving <StatusTag status={statusMoved.name} colour={statusMoved.colour} /> from
position
Error moving <StatusTag status={statusMoved.name} colour={statusMoved.colour} /> from position
{statusMoved.currentIndex + 1} to {statusMoved.nextIndex + 1}{" "}
{selectedOrganisation.Organisation.name}: {String(err)}
</>,
@@ -414,18 +405,17 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
newStatus: reassignToStatus,
});
const newStatuses = Object.keys(statuses).filter((item) => item !== statusToRemove);
await updateStatuses(
Object.fromEntries(newStatuses.map((status) => [status, statuses[status]])),
{ name: statusToRemove, colour: statuses[statusToRemove] },
);
await updateStatuses(Object.fromEntries(newStatuses.map((status) => [status, statuses[status]])), {
name: statusToRemove,
colour: statuses[statusToRemove],
});
setStatusToRemove(null);
setReassignToStatus("");
} catch (error) {
console.error("error replacing status:", error);
toast.error(
<>
Error removing <StatusTag status={statusToRemove} colour={statuses[statusToRemove]} />{" "}
from
Error removing <StatusTag status={statusToRemove} colour={statuses[statusToRemove]} /> from
{selectedOrganisation.Organisation.name}: {String(error)}
</>,
{
@@ -460,9 +450,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full min-w-0">
<div className="flex flex-wrap gap-2 items-center w-full min-w-0">
<OrganisationSelect
contentClass={
"data-[side=bottom]:translate-y-2 data-[side=bottom]:translate-x-0.25"
}
contentClass={"data-[side=bottom]:translate-y-2 data-[side=bottom]:translate-x-0.25"}
/>
<TabsList>
<TabsTrigger value="info">Info</TabsTrigger>
@@ -477,9 +465,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
<div className="flex justify-between">
<div className="flex flex-col gap-0 mb-2">
{" "}
<h2 className="text-xl font-600 break-all">
{selectedOrganisation.Organisation.name}
</h2>
<h2 className="text-xl font-600 break-all">{selectedOrganisation.Organisation.name}</h2>
<p className="text-sm text-muted-foreground break-all">
Slug: {selectedOrganisation.Organisation.slug}
</p>
@@ -498,22 +484,14 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
</div>
<div className="flex flex-col gap-1">
{selectedOrganisation.Organisation.description ? (
<p className="text-sm break-words">
{selectedOrganisation.Organisation.description}
</p>
<p className="text-sm break-words">{selectedOrganisation.Organisation.description}</p>
) : (
<p className="text-sm text-muted-foreground break-words">
No description
</p>
<p className="text-sm text-muted-foreground break-words">No description</p>
)}
</div>
{isAdmin && (
<div className="flex gap-2 mt-3">
<Button
variant="outline"
size="sm"
onClick={() => setEditOrgOpen(true)}
>
<Button variant="outline" size="sm" onClick={() => setEditOrgOpen(true)}>
<Icon icon="edit" className="size-4" />
Edit
</Button>
@@ -531,9 +509,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
variant: "destructive",
onConfirm: async () => {
try {
await deleteOrganisation.mutateAsync(
selectedOrganisation.Organisation.id,
);
await deleteOrganisation.mutateAsync(selectedOrganisation.Organisation.id);
closeConfirmDialog();
toast.success(
`Deleted organisation "${selectedOrganisation.Organisation.name}"`,
@@ -593,38 +569,20 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
handleRoleChange(
member.User.id,
member.User.name,
member.OrganisationMember
.role,
member.OrganisationMember.role,
)
}
variant={
member.OrganisationMember.role ===
"admin"
? "yellow"
: "green"
}
variant={member.OrganisationMember.role === "admin" ? "yellow" : "green"}
>
{member.OrganisationMember.role ===
"admin" ? (
<Icon
icon="chevronDown"
className="size-5"
/>
{member.OrganisationMember.role === "admin" ? (
<Icon icon="chevronDown" className="size-5" />
) : (
<Icon
icon="chevronUp"
className="size-5"
/>
<Icon icon="chevronUp" className="size-5" />
)}
</IconButton>
<IconButton
variant="destructive"
onClick={() =>
handleRemoveMember(
member.User.id,
member.User.name,
)
}
onClick={() => handleRemoveMember(member.User.id, member.User.name)}
>
<Icon icon="x" className="size-5" />
</IconButton>
@@ -680,11 +638,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
</div>
{isAdmin && (
<div className="flex gap-2 mt-3">
<Button
variant="outline"
size="sm"
onClick={() => setEditProjectOpen(true)}
>
<Button variant="outline" size="sm" onClick={() => setEditProjectOpen(true)}>
<Icon icon="edit" className="size-4" />
Edit
</Button>
@@ -702,10 +656,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
variant: "destructive",
onConfirm: async () => {
try {
await deleteProject.mutateAsync(
selectedProject
.Project.id,
);
await deleteProject.mutateAsync(selectedProject.Project.id);
closeConfirmDialog();
toast.success(
`Deleted project "${selectedProject.Project.name}"`,
@@ -719,10 +670,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
});
}}
>
<Icon
icon="trash"
className="size-4"
/>
<Icon icon="trash" className="size-4" />
Delete
</Button>
)}
@@ -730,9 +678,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
)}
</>
) : (
<p className="text-sm text-muted-foreground">
Select a project to view details.
</p>
<p className="text-sm text-muted-foreground">Select a project to view details.</p>
)}
</div>
<div className="flex flex-col gap-2 min-w-0 flex-1">
@@ -746,17 +692,13 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
<div
key={sprintItem.id}
className={`flex items-center justify-between p-2 border ${
isCurrent
? "border-emerald-500/60 bg-emerald-500/10"
: ""
isCurrent ? "border-emerald-500/60 bg-emerald-500/10" : ""
}`}
>
<SmallSprintDisplay sprint={sprintItem} />
<div className="flex items-center gap-2">
{dateRange && (
<span className="text-xs text-muted-foreground">
{dateRange}
</span>
<span className="text-xs text-muted-foreground">{dateRange}</span>
)}
{isAdmin && (
<DropdownMenu>
@@ -766,10 +708,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
noStyle
className="hover:opacity-80 cursor-pointer"
>
<Icon
icon="ellipsisVertical"
className="size-4 text-foreground"
/>
<Icon icon="ellipsisVertical" className="size-4 text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
@@ -778,19 +717,12 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
>
<DropdownMenuItem
onSelect={() => {
setEditingSprint(
sprintItem,
);
setEditSprintOpen(
true,
);
setEditingSprint(sprintItem);
setEditSprintOpen(true);
}}
className="hover:bg-primary-foreground"
>
<Icon
icon="edit"
className="size-4 text-muted-foreground"
/>
<Icon icon="edit" className="size-4 text-muted-foreground" />
Edit
</DropdownMenuItem>
<DropdownMenuItem
@@ -800,37 +732,24 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
open: true,
title: "Delete Sprint",
message: `Are you sure you want to delete "${sprintItem.name}"? Issues assigned to this sprint will become unassigned.`,
confirmText:
"Delete",
processingText:
"Deleting...",
variant:
"destructive",
onConfirm:
async () => {
confirmText: "Delete",
processingText: "Deleting...",
variant: "destructive",
onConfirm: async () => {
try {
await deleteSprint.mutateAsync(
sprintItem.id,
);
await deleteSprint.mutateAsync(sprintItem.id);
closeConfirmDialog();
toast.success(
`Deleted sprint "${sprintItem.name}"`,
);
toast.success(`Deleted sprint "${sprintItem.name}"`);
await invalidateSprints();
} catch (error) {
console.error(
error,
);
console.error(error);
}
},
});
}}
className="hover:bg-destructive/10"
>
<Icon
icon="trash"
className="size-4"
/>
<Icon icon="trash" className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
@@ -845,11 +764,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
projectId={selectedProject?.Project.id}
trigger={
<Button variant="outline" size="sm">
Create sprint{" "}
<Icon
icon="plus"
className="size-4"
/>
Create sprint <Icon icon="plus" className="size-4" />
</Button>
}
sprints={sprints}
@@ -857,9 +772,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
)}
</div>
) : (
<p className="text-sm text-muted-foreground">
Select a project to view sprints.
</p>
<p className="text-sm text-muted-foreground">Select a project to view sprints.</p>
)}
</div>
</div>
@@ -900,16 +813,10 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
<div className="flex flex-col gap-2 w-full">
<div className="flex flex-col gap-2 max-h-86 overflow-y-scroll grid grid-cols-2">
{Object.keys(statuses).map((status, index) => (
<div
key={status}
className="flex items-center justify-between p-2 border"
>
<div key={status} className="flex items-center justify-between p-2 border">
<div className="flex items-center gap-2">
<span className="text-sm">{index + 1}</span>
<StatusTag
status={status}
colour={statuses[status]}
/>
<StatusTag status={status} colour={statuses[status]} />
</div>
{isAdmin && (
<DropdownMenu>
@@ -919,53 +826,29 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
noStyle
className="hover:opacity-80 cursor-pointer"
>
<Icon
icon="ellipsisVertical"
className="size-4 text-foreground"
/>
<Icon icon="ellipsisVertical" className="size-4 text-foreground" />
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
sideOffset={4}
className="bg-background"
>
<DropdownMenuContent align="end" sideOffset={4} className="bg-background">
<DropdownMenuItem
disabled={index === 0}
onSelect={() =>
void moveStatus(status, "up")
}
onSelect={() => void moveStatus(status, "up")}
className="hover:bg-primary-foreground"
>
<Icon
icon="chevronUp"
className="size-4 text-muted-foreground"
/>
<Icon icon="chevronUp" className="size-4 text-muted-foreground" />
Move up
</DropdownMenuItem>
<DropdownMenuItem
disabled={
index ===
Object.keys(statuses).length - 1
}
onSelect={() =>
void moveStatus(status, "down")
}
disabled={index === Object.keys(statuses).length - 1}
onSelect={() => void moveStatus(status, "down")}
className="hover:bg-primary-foreground"
>
<Icon
icon="chevronDown"
className="size-4 text-muted-foreground"
/>
<Icon icon="chevronDown" className="size-4 text-muted-foreground" />
Move down
</DropdownMenuItem>
<DropdownMenuItem
variant="destructive"
disabled={
Object.keys(statuses).length <= 1
}
onSelect={() =>
void handleRemoveStatusClick(status)
}
disabled={Object.keys(statuses).length <= 1}
onSelect={() => void handleRemoveStatusClick(status)}
className="hover:bg-destructive/10"
>
<Icon icon="x" className="size-4" />
@@ -1012,19 +895,12 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
variant="outline"
size="md"
onClick={() => void handleCreateStatus()}
disabled={
newStatusName.trim().length >
ISSUE_STATUS_MAX_LENGTH
}
disabled={newStatusName.trim().length > ISSUE_STATUS_MAX_LENGTH}
>
<Icon icon="plus" className="size-4" />
</IconButton>
</div>
{statusError && (
<p className="text-xs text-destructive">
{statusError}
</p>
)}
{statusError && <p className="text-xs text-destructive">{statusError}</p>}
</>
) : (
<Button
@@ -1045,9 +921,7 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
) : (
<div className="flex flex-col gap-2 w-full min-w-0">
<OrganisationSelect
contentClass={
"data-[side=bottom]:translate-y-2 data-[side=bottom]:translate-x-0.25"
}
contentClass={"data-[side=bottom]:translate-y-2 data-[side=bottom]:translate-x-0.25"}
/>
<p className="text-sm text-muted-foreground">No organisations yet.</p>
</div>
@@ -1083,8 +957,8 @@ function Organisations({ trigger }: { trigger?: ReactNode }) {
{statusToRemove ? (
<StatusTag status={statusToRemove} colour={statuses[statusToRemove]} />
) : null}{" "}
status? <span className="font-700 text-foreground">{issuesUsingStatus}</span>{" "}
issues are using it. Which status would you like these issues to use instead?
status? <span className="font-700 text-foreground">{issuesUsingStatus}</span> issues are using
it. Which status would you like these issues to use instead?
</p>
<Select value={reassignToStatus} onValueChange={setReassignToStatus}>
<SelectTrigger className="w-min">

View File

@@ -84,12 +84,7 @@ export function ProjectSelect({
<ProjectForm
organisationId={selectedOrganisationId ?? undefined}
trigger={
<Button
size={"sm"}
variant="ghost"
className={"w-full"}
disabled={!selectedOrganisationId}
>
<Button size={"sm"} variant="ghost" className={"w-full"} disabled={!selectedOrganisationId}>
Create Project
</Button>
}

View File

@@ -113,11 +113,7 @@ export function ServerConfiguration({ trigger }: { trigger?: ReactNode }) {
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogTrigger asChild>
{trigger || (
<IconButton
size="lg"
className="absolute top-2 right-2"
title={"Server Configuration"}
>
<IconButton size="lg" className="absolute top-2 right-2" title={"Server Configuration"}>
<Icon icon="serverIcon" className="size-4" />
</IconButton>
)}
@@ -164,9 +160,7 @@ export function ServerConfiguration({ trigger }: { trigger?: ReactNode }) {
<Icon icon="undo2" className="size-4" />
</IconButton>
</div>
{!isValid && (
<Label className="text-destructive text-sm">Please enter a valid URL</Label>
)}
{!isValid && <Label className="text-destructive text-sm">Please enter a valid URL</Label>}
{healthError && <Label className="text-destructive text-sm">{healthError}</Label>}
</div>
</div>

View File

@@ -303,8 +303,7 @@ export function SprintForm({
type="submit"
disabled={
submitting ||
((name.trim() === "" || name.trim().length > SPRINT_NAME_MAX_LENGTH) &&
submitAttempted) ||
((name.trim() === "" || name.trim().length > SPRINT_NAME_MAX_LENGTH) && submitAttempted) ||
(dateError !== "" && submitAttempted)
}
>

View File

@@ -83,10 +83,7 @@ function Calendar({
),
week: cn("flex w-full mt-2", defaultClassNames.week),
week_number_header: cn("select-none w-(--cell-size)", defaultClassNames.week_number_header),
week_number: cn(
"text-[0.8rem] select-none text-muted-foreground",
defaultClassNames.week_number,
),
week_number: cn("text-[0.8rem] select-none text-muted-foreground", defaultClassNames.week_number),
day: cn(
"relative w-full h-full p-0 text-center group/day aspect-square select-none",
defaultClassNames.day,
@@ -95,10 +92,7 @@ function Calendar({
range_middle: cn(defaultClassNames.range_middle),
range_end: cn("bg-accent", defaultClassNames.range_end),
today: cn("border border-dashed -m-px", defaultClassNames.today),
outside: cn(
"text-muted-foreground aria-selected:text-muted-foreground",
defaultClassNames.outside,
),
outside: cn("text-muted-foreground aria-selected:text-muted-foreground", defaultClassNames.outside),
disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
@@ -113,9 +107,7 @@ function Calendar({
}
if (orientation === "right") {
return (
<Icon icon="chevronRightIcon" className={cn("size-4", className)} {...props} />
);
return <Icon icon="chevronRightIcon" className={cn("size-4", className)} {...props} />;
}
return <Icon icon="chevronDownIcon" className={cn("size-4", className)} {...props} />;
@@ -171,10 +163,7 @@ function CalendarDayButton({
size="icon"
data-day={day.date.toLocaleDateString()}
data-selected-single={
modifiers.selected &&
!modifiers.range_start &&
!modifiers.range_end &&
!modifiers.range_middle
modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle
}
data-range-start={modifiers.range_start}
data-range-end={modifiers.range_end}

View File

@@ -18,11 +18,7 @@ export default function ColourPicker({
return (
<Popover>
<PopoverTrigger asChild={asChild}>
<Button
type="button"
className={cn("w-8 h-8", className)}
style={{ backgroundColor: colour }}
/>
<Button type="button" className={cn("w-8 h-8", className)} style={{ backgroundColor: colour }} />
</PopoverTrigger>
<PopoverContent className="w-fit grid gap-2 p-2" align="start" side={"top"}>
<HexColorPicker color={colour} onChange={onChange} className="p-0 m-0" />

View File

@@ -36,9 +36,7 @@ function IconButton({
size,
...props
}: React.ComponentProps<"button"> & VariantProps<typeof iconButtonVariants>) {
return (
<button type="button" className={cn(iconButtonVariants({ variant, size, className }))} {...props} />
);
return <button type="button" className={cn(iconButtonVariants({ variant, size, className }))} {...props} />;
}
export { IconButton, iconButtonVariants };

View File

@@ -15,9 +15,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
}
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
return (
<tbody data-slot="table-body" className={cn("[&_tr:last-child]:border-0", className)} {...props} />
);
return <tbody data-slot="table-body" className={cn("[&_tr:last-child]:border-0", className)} {...props} />;
}
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {

View File

@@ -4,9 +4,7 @@ import type * as React from "react";
import { cn } from "@/lib/utils";
function Tabs({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
return (
<TabsPrimitive.Root data-slot="tabs" className={cn("flex flex-col gap-2", className)} {...props} />
);
return <TabsPrimitive.Root data-slot="tabs" className={cn("flex flex-col gap-2", className)} {...props} />;
}
function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {

View File

@@ -40,14 +40,9 @@ export function UploadAvatar({
onAvatarUploaded(url);
setUploading(false);
toast.success(
<div className="flex flex-col items-center gap-4">
Avatar uploaded successfully
</div>,
{
toast.success(<div className="flex flex-col items-center gap-4">Avatar uploaded successfully</div>, {
dismissible: false,
},
);
});
} catch (err) {
const message = parseError(err as Error);
setError(message);

View File

@@ -42,9 +42,7 @@ export function UploadOrgIcon({
setUploading(false);
toast.success(
<div className="flex flex-col items-center gap-4">
Organisation icon uploaded successfully
</div>,
<div className="flex flex-col items-center gap-4">Organisation icon uploaded successfully</div>,
{
dismissible: false,
},

View File

@@ -16,9 +16,7 @@ export default function Landing() {
{!isLoading && user ? (
<>
{user && (
<h1 className="text-xl font-basteleur font-400">
Welcome back {user.name.split(" ")[0]}!
</h1>
<h1 className="text-xl font-basteleur font-400">Welcome back {user.name.split(" ")[0]}!</h1>
)}
<Button asChild variant="outline" size="sm">
<Link to="/app">Open app</Link>
@@ -34,9 +32,7 @@ export default function Landing() {
<main className="flex-1 flex flex-col items-center justify-center gap-8">
<div className="max-w-3xl text-center space-y-4">
<h1 className="text-[54px] font-basteleur font-700">
Need a snappy project management tool?
</h1>
<h1 className="text-[54px] font-basteleur font-700">Need a snappy project management tool?</h1>
<p className="text-[24px] font-goudy text-muted-foreground">
Build your next project with <span className="font-goudy font-700">Sprint.</span>
</p>

View File

@@ -245,11 +245,7 @@ export default function Timeline() {
const barStyle = getSprintBarStyle(sprint);
const showTodayLabel = sprintIndex === 0;
return (
<div
key={sprint.id}
className="grid border-b"
style={{ gridTemplateColumns }}
>
<div key={sprint.id} className="grid border-b" style={{ gridTemplateColumns }}>
<div
className={`px-${BREATHING_ROOM} pt-0.5 py-${BREATHING_ROOM} flex flex-col gap-${BREATHING_ROOM} bg-background relative z-20 border-r`}
>
@@ -267,9 +263,7 @@ export default function Timeline() {
{getSprintDateRange(sprint)}
</div>
{sprintIssues.length === 0 && (
<div className="text-xs text-muted-foreground text-pretty">
No issues assigned.
</div>
<div className="text-xs text-muted-foreground text-pretty">No issues assigned.</div>
)}
{sprintIssues.length > 0 && (
<div className={`flex flex-col gap-${BREATHING_ROOM}`}>
@@ -277,30 +271,21 @@ export default function Timeline() {
<IssueLine
key={issue.Issue.id}
issue={issue}
statusColour={
statuses[issue.Issue.status] ??
DEFAULT_STATUS_COLOUR
}
statusColour={statuses[issue.Issue.status] ?? DEFAULT_STATUS_COLOUR}
/>
))}
</div>
)}
</div>
<div
className={cn(
`py-${BREATHING_ROOM} relative min-h-12`,
"border-l",
)}
className={cn(`py-${BREATHING_ROOM} relative min-h-12`, "border-l")}
style={{ gridColumn: "2 / -1" }}
>
<div className="absolute inset-0 flex z-10 pointer-events-none">
{weeks.map((week, index) => (
<div
key={`${week.toISOString()}-${sprint.id}`}
className={cn(
"flex-1",
index === 0 ? "" : "border-l",
)}
className={cn("flex-1", index === 0 ? "" : "border-l")}
/>
))}
</div>
@@ -344,13 +329,9 @@ export default function Timeline() {
<div
className={`px-${BREATHING_ROOM} pt-0.5 py-${BREATHING_ROOM} flex flex-col gap-${BREATHING_ROOM} bg-background relative z-20 border-r`}
>
<div className="text-sm font-medium text-muted-foreground">
Backlog
</div>
<div className="text-sm font-medium text-muted-foreground">Backlog</div>
{issueGroup.unassigned.length === 0 && (
<div className="text-xs text-muted-foreground text-pretty">
No unassigned issues.
</div>
<div className="text-xs text-muted-foreground text-pretty">No unassigned issues.</div>
)}
{issueGroup.unassigned.length > 0 && (
<div className={`flex flex-col gap-${BREATHING_ROOM}`}>
@@ -358,10 +339,7 @@ export default function Timeline() {
<IssueLine
key={issue.Issue.id}
issue={issue}
statusColour={
statuses[issue.Issue.status] ??
DEFAULT_STATUS_COLOUR
}
statusColour={statuses[issue.Issue.status] ?? DEFAULT_STATUS_COLOUR}
/>
))}
</div>