Skip to content

Commit 8ba8f69

Browse files
authored
Consolidate buttons and related components (Stirling-Tools#6787)
SegmentedControl, Chip, ChipFlow. Bring in the portal dark mode theme and other small fixes to issues I found during testing
1 parent be97268 commit 8ba8f69

592 files changed

Lines changed: 6393 additions & 5051 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare module "*.css" {}

frontend/.storybook/preview.tsx

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ void React;
1414

1515
import { TierProvider, type Tier } from "@portal/contexts/TierContext";
1616
import { LinkProvider, type LinkState } from "@portal/contexts/LinkContext";
17-
import { ThemeProvider } from "@portal/contexts/ThemeContext";
17+
import { ThemeProvider, useTheme } from "@portal/contexts/ThemeContext";
1818
import { UIProvider } from "@portal/contexts/UIContext";
1919
import { SuiProvider } from "@portal/theme/SuiProvider";
2020
import { handlers } from "@portal/mocks/handlers";
@@ -78,13 +78,21 @@ function TierKey({
7878
);
7979
}
8080

81-
/** Keeps useTheme() and the data-theme attribute in sync. */
82-
function ThemeWatcher() {
81+
/**
82+
* Makes the Storybook toolbar the SINGLE source of truth for the theme.
83+
*/
84+
function ThemeBridge({
85+
theme,
86+
children,
87+
}: {
88+
theme: "light" | "dark";
89+
children: React.ReactNode;
90+
}) {
91+
const { setTheme } = useTheme();
8392
useEffect(() => {
84-
// The addon-themes decorator already sets data-theme on <html>.
85-
// We just read it on mount so ThemeProvider picks it up.
86-
}, []);
87-
return null;
93+
setTheme(theme);
94+
}, [theme, setTheme]);
95+
return <>{children}</>;
8896
}
8997

9098
const withProviders: Decorator = (Story, context) => {
@@ -101,20 +109,21 @@ const withProviders: Decorator = (Story, context) => {
101109
return (
102110
<MemoryRouter initialEntries={["/"]}>
103111
<ThemeProvider>
104-
<SuiProvider colorScheme={colorScheme}>
105-
{/* LinkProvider must wrap TierProvider: TierContext derives its tier
106-
from useLink() (matches App.tsx's nesting). */}
107-
<LinkProvider key={linkState} initialState={linkState}>
108-
<TierKey tier={tier}>
109-
<UIProvider>
110-
<ThemeWatcher />
111-
<Suspense fallback={null}>
112-
<Story />
113-
</Suspense>
114-
</UIProvider>
115-
</TierKey>
116-
</LinkProvider>
117-
</SuiProvider>
112+
<ThemeBridge theme={colorScheme}>
113+
<SuiProvider colorScheme={colorScheme}>
114+
{/* LinkProvider must wrap TierProvider: TierContext derives its tier
115+
from useLink() (matches App.tsx's nesting). */}
116+
<LinkProvider key={linkState} initialState={linkState}>
117+
<TierKey tier={tier}>
118+
<UIProvider>
119+
<Suspense fallback={null}>
120+
<Story />
121+
</Suspense>
122+
</UIProvider>
123+
</TierKey>
124+
</LinkProvider>
125+
</SuiProvider>
126+
</ThemeBridge>
118127
</ThemeProvider>
119128
</MemoryRouter>
120129
);

frontend/.storybook/tsconfig.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2022",
4+
"jsx": "react-jsx",
5+
"module": "esnext",
6+
"moduleResolution": "bundler",
7+
"paths": {
8+
"@app/*": [
9+
"../editor/src/desktop/*",
10+
"../editor/src/proprietary/*",
11+
"../editor/src/core/*"
12+
],
13+
"@core/*": ["../editor/src/core/*"],
14+
"@proprietary/*": ["../editor/src/proprietary/*"],
15+
"@portal/*": ["../editor/src/portal/*"]
16+
},
17+
"resolveJsonModule": true,
18+
"esModuleInterop": true,
19+
"forceConsistentCasingInFileNames": true,
20+
"strict": true,
21+
"skipLibCheck": true
22+
},
23+
"include": ["./**/*"]
24+
}

frontend/editor/public/locales/en-US/translation.toml

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ black = "Black"
77
blue = "Blue"
88
cancel = "Cancel"
99
chooseFile = "Choose File"
10+
clear = "Clear"
1011
close = "Close"
1112
comingSoon = "Coming soon"
1213
confirm = "Confirm"
@@ -87,6 +88,7 @@ processingCompleteMultiple = "{{count}} files are ready."
8788
property = "Property"
8889
quickPosition = "Quick Position"
8990
red = "Red"
91+
remove = "Remove"
9092
reset = "Reset"
9193
review = "Review"
9294
save = "Save"
@@ -180,6 +182,7 @@ addMoreFiles = "Add more files..."
180182
attachments = "Select Attachments"
181183
info = "Select files to attach to your PDF. These files will be embedded and accessible through the PDF's attachment panel."
182184
placeholder = "Choose files..."
185+
removeFile = "Remove file"
183186
selectedFiles = "Selected Files"
184187
submit = "Add Attachments"
185188

@@ -1628,6 +1631,9 @@ title = "Do you want to help make Stirling PDF better?"
16281631
tags = "annotate,highlight,draw,markup,comment,notes,review,redline,feedback,markup tools,sticky notes,shapes,arrows,text box,freehand"
16291632

16301633
[annotation]
1634+
alignCenter = "Align center"
1635+
alignLeft = "Align left"
1636+
alignRight = "Align right"
16311637
annotationStyle = "Annotation style"
16321638
backgroundColor = "Background color"
16331639
borderOff = "Border: Off"
@@ -2531,6 +2537,7 @@ title = "Rule of thumb"
25312537

25322538
[certSign.source]
25332539
device = "This device"
2540+
noOtherSources = "No other certificate sources are available."
25342541
server = "Server"
25352542
stepTitle = "Certificate source"
25362543
upload = "Upload"
@@ -3595,7 +3602,9 @@ makeCopy = "Make a copy"
35953602
mobileShort = "Mobile"
35963603
mobileUpload = "Mobile Upload"
35973604
mobileUploadNotAvailable = "Mobile upload not enabled"
3605+
moreOptions = "More options"
35983606
myFiles = "My Files"
3607+
nextFile = "Next file"
35993608
noFiles = "No files available"
36003609
noFilesFound = "No files found matching your search"
36013610
noRecentFiles = "No recent files found"
@@ -3605,6 +3614,7 @@ openInFileEditor = "Open in File Editor"
36053614
openInPageEditor = "Open in Page Editor"
36063615
owner = "Owner"
36073616
ownerUnknown = "Unknown"
3617+
previousFile = "Previous file"
36083618
recent = "Recent"
36093619
removeBoth = "Remove from both"
36103620
removeFilePrompt = "This file is saved on this device and on your server. Where would you like to remove it from?"
@@ -4614,10 +4624,10 @@ welcomeTitle = "You've been invited!"
46144624
[landing]
46154625
addFiles = "Add Files"
46164626
heroSubtitle = "Drop in or add an existing PDF to get started."
4617-
heroTitle = "Stirling PDF"
46184627
mobileUpload = "Upload from Mobile"
46194628
openFromComputer = "Open from computer"
46204629
uploadFromComputer = "Upload from computer"
4630+
workbenchEmptyStateHero = "Drop a PDF anywhere"
46214631

46224632
[language]
46234633
direction = "ltr"
@@ -4930,6 +4940,7 @@ title = "Output"
49304940
[onboarding]
49314941
activeFiles = "The <strong>Active Files</strong> view shows all of the PDFs you have loaded into the tool, and allows you to select which ones to process."
49324942
allTools = "This is the <strong>Tools</strong> panel, where you can browse and select from all available PDF tools."
4943+
close = "Close"
49334944
cropSettings = "Now that we've selected the file we want crop, we can configure the Crop tool to choose the area that we want to crop the PDF to."
49344945
fileCheckbox = "Clicking one of the files selects it for processing. You can select multiple files for batch operations."
49354946
fileReplacement = "The modified file will replace the original file in the Workbench automatically, allowing you to easily run it through more tools."
@@ -4955,6 +4966,7 @@ skipTheTour = "Skip the tour"
49554966

49564967
[onboarding.desktopInstall]
49574968
body = "Stirling works best as a desktop app. You can use it offline, access documents faster, and make edits locally on your computer."
4969+
selectOs = "Select operating system"
49584970
title = "Download"
49594971
titleWithOs = "Download for {{osLabel}}"
49604972

@@ -5566,7 +5578,9 @@ viewLabel = "PDF Editor"
55665578

55675579
[pdfTextEditor.actions]
55685580
applyChanges = "Apply Changes"
5581+
clearText = "Clear text"
55695582
downloadCopy = "Download Copy"
5583+
moreOptions = "More options"
55705584
reset = "Reset Changes"
55715585

55725586
[pdfTextEditor.badges]
@@ -9670,7 +9684,9 @@ memberRemoved = "Member removed successfully"
96709684
namePlaceholder = "Enter team name"
96719685
personal = "Personal"
96729686
removeError = "Failed to remove member"
9687+
renameCancel = "Cancel rename"
96739688
renameError = "Failed to rename team"
9689+
renameSubmit = "Save team name"
96749690
renameSuccess = "Team renamed successfully"
96759691

96769692
[team.invitationBanner]
@@ -9686,6 +9702,7 @@ sendButton = "Send Invitation"
96869702
title = "Invite Team Member"
96879703

96889704
[team.members]
9705+
actions = "Member actions"
96899706
emailColumn = "Email"
96909707
empty = "No team members yet"
96919708
nameColumn = "Name"
@@ -10041,14 +10058,23 @@ zoomOut = "Zoom Out"
1004110058
[viewer.attachments]
1004210059
addAttachment = "Add attachment"
1004310060
close = "Close attachments"
10061+
closeSidebar = "Close attachments sidebar"
10062+
download = "Download attachment"
1004410063
empty = "No attachments in this document"
1004510064
loading = "Loading attachments..."
1004610065
noDocument = "Open a PDF to view its attachments."
1004710066
noMatch = "No attachments match your search"
1004810067
noSupport = "Attachment support is unavailable for this viewer."
10068+
retry = "Retry"
1004910069
searchPlaceholder = "Search attachments"
1005010070
title = "Attachments"
1005110071

10072+
[viewer.bookmarks]
10073+
bookmarkTitle = "Bookmark title"
10074+
closeSidebar = "Close bookmarks sidebar"
10075+
collapseAll = "Collapse all bookmarks"
10076+
expandAll = "Expand all bookmarks"
10077+
1005210078
[viewer.comments]
1005310079
addComment = "Add comment"
1005410080
addCommentPlaceholder = "Add comment..."
@@ -10059,6 +10085,7 @@ clearAll = "Clear all comments"
1005910085
clearAllDescription = "This removes comments and replies from the sidebar while keeping any attached annotations in the document."
1006010086
clearAllTitle = "Clear all comments?"
1006110087
close = "Close comments"
10088+
closeSidebar = "Close comments sidebar"
1006210089
deleteAnnotationAndComment = "Delete annotation & comment"
1006310090
deleteDescription = "This annotation has a comment attached. You can remove just the comment from the sidebar while keeping the annotation, or delete everything."
1006410091
deleteTitle = "Remove annotation from comments?"
@@ -10090,6 +10117,11 @@ title = "Form Fields"
1009010117
unsavedBadge = "Unsaved"
1009110118
unsavedDesc = "You have unsaved changes"
1009210119

10120+
[viewer.layers]
10121+
closeSidebar = "Close layers sidebar"
10122+
hideAll = "Hide all layers"
10123+
showAll = "Show all layers"
10124+
1009310125
[viewer.link]
1009410126
delete = "Delete link"
1009510127

@@ -10120,6 +10152,9 @@ resultsOf = "of {{total}}"
1012010152
[viewer.signature]
1012110153
delete = "Delete signature"
1012210154

10155+
[viewer.thumbnails]
10156+
closeSidebar = "Close thumbnails sidebar"
10157+
1012310158
[viewPdf]
1012410159
tags = "view,read,annotate,text,image,highlight,edit"
1012510160
title = "View/Edit PDF"
@@ -10546,6 +10581,7 @@ loading = "Loading people..."
1054610581
locked = "locked"
1054710582
lockedBadge = "Locked"
1054810583
loginRequired = "Enable login mode first"
10584+
memberActions = "Member actions"
1054910585
noMembersFound = "No members found"
1055010586
role = "Role"
1055110587
searchMembers = "Search members..."
@@ -10555,6 +10591,7 @@ unlockAccount = "Unlock Account"
1055510591
unlockUserError = "Failed to unlock user account"
1055610592
unlockUserSuccess = "User account unlocked successfully"
1055710593
user = "User"
10594+
userInfo = "User info"
1055810595

1055910596
[workspace.people.actions]
1056010597
upgrade = "Upgrade"
@@ -10700,6 +10737,7 @@ removeMemberError = "Failed to remove user from team"
1070010737
removeMemberSuccess = "User removed from team"
1070110738
renameTeamLabel = "Rename Team"
1070210739
system = "System"
10740+
teamActions = "Team actions"
1070310741
teamName = "Team Name"
1070410742
teamNotFound = "Team not found"
1070510743
title = "Teams"

frontend/editor/src/cloud/components/onboarding/renderButtons.tsx

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React from "react";
2-
import { Button, Group, ActionIcon } from "@mantine/core";
2+
import { Group } from "@mantine/core";
3+
import { Button } from "@app/ui/Button";
4+
import { ActionIcon } from "@app/ui/ActionIcon";
35
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
46
import { TFunction } from "i18next";
57
import {
@@ -31,22 +33,6 @@ export function renderButtons({
3133
(btn) => btn.group === "right",
3234
);
3335

34-
const buttonStyles = (variant: ButtonDefinition["variant"]) =>
35-
variant === "primary"
36-
? {
37-
root: {
38-
background: "var(--onboarding-primary-button-bg)",
39-
color: "var(--onboarding-primary-button-text)",
40-
},
41-
}
42-
: {
43-
root: {
44-
background: "var(--onboarding-secondary-button-bg)",
45-
border: "1px solid var(--onboarding-secondary-button-border)",
46-
color: "var(--onboarding-secondary-button-text)",
47-
},
48-
};
49-
5036
const resolveButtonLabel = (button: ButtonDefinition) => {
5137
// Translate the label (it's a translation key)
5238
const label = button.label ?? "";
@@ -65,20 +51,15 @@ export function renderButtons({
6551
<ActionIcon
6652
key={button.key}
6753
onClick={() => onAction(button.action)}
68-
radius="md"
69-
size={40}
54+
size="lg"
55+
variant="secondary"
56+
accent="neutral"
7057
disabled={disabled}
71-
styles={{
72-
root: {
73-
background: "var(--onboarding-secondary-button-bg)",
74-
border: "1px solid var(--onboarding-secondary-button-border)",
75-
color: "var(--onboarding-secondary-button-text)",
76-
},
77-
}}
58+
aria-label={t("onboarding.buttons.back", "Back")}
7859
>
79-
{button.icon === "chevron-left" && (
60+
{button.icon === "chevron-left" ? (
8061
<ChevronLeftIcon fontSize="small" />
81-
)}
62+
) : null}
8263
</ActionIcon>
8364
);
8465
}
@@ -91,7 +72,8 @@ export function renderButtons({
9172
key={button.key}
9273
onClick={() => onAction(button.action)}
9374
disabled={disabled}
94-
styles={buttonStyles(variant)}
75+
variant={variant === "primary" ? "primary" : "secondary"}
76+
accent="neutral"
9577
>
9678
{label}
9779
</Button>

frontend/editor/src/cloud/components/onboarding/slides/TeamSlide.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useEffect, useState } from "react";
2-
import { Badge, Button, TextInput } from "@mantine/core";
2+
import { Badge, TextInput } from "@mantine/core";
3+
import { Button } from "@app/ui/Button";
34
import { useTranslation } from "react-i18next";
45
import { SlideConfig } from "@app/types/types";
56
import { createLightSlideBackground } from "@app/components/onboarding/slides/unifiedBackgroundConfig";

frontend/editor/src/cloud/components/shared/FreeLimitReachedModal.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useMemo } from "react";
2-
import { Modal, Stack, Button } from "@mantine/core";
2+
import { Modal, Stack } from "@mantine/core";
3+
import { Button } from "@app/ui/Button";
34
import { useTranslation } from "react-i18next";
45
import CelebrationIcon from "@mui/icons-material/CelebrationOutlined";
56
import AnimatedSlideBackground from "@app/components/onboarding/slides/AnimatedSlideBackground";
@@ -169,7 +170,7 @@ export function FreeLimitReachedModal({ onClose }: FreeLimitReachedModalProps) {
169170
>
170171
<Button
171172
onClick={onClose}
172-
variant="default"
173+
variant="secondary"
173174
size="sm"
174175
className="free-limit-modal-button"
175176
style={{

0 commit comments

Comments
 (0)