Skip to content

Commit 3c62068

Browse files
committed
WIP
Tool: gitpod/catfood.gitpod.cloud
1 parent 71e2b01 commit 3c62068

File tree

5 files changed

+1362
-4
lines changed

5 files changed

+1362
-4
lines changed

components/dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@tanstack/react-query": "^4.29.19",
2727
"@tanstack/react-query-devtools": "^4.29.19",
2828
"@tanstack/react-query-persist-client": "^4.29.19",
29+
"@uiw/react-md-editor": "^4.0.5",
2930
"@xterm/addon-fit": "^0.10.0",
3031
"@xterm/xterm": "^5.5.0",
3132
"buffer": "^4.3.0",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) 2025 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import * as React from "react";
8+
9+
import { cn } from "@podkit/lib/cn";
10+
11+
const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<"textarea">>(
12+
({ className, ...props }, ref) => {
13+
return (
14+
<textarea
15+
className={cn(
16+
"flex min-h-[80px] w-full rounded-md border border-input bg-pk-surface-primary px-3 py-2 text-base ring-offset-background placeholder:text-pk-content-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
17+
className,
18+
)}
19+
ref={ref}
20+
{...props}
21+
/>
22+
);
23+
},
24+
);
25+
Textarea.displayName = "Textarea";
26+
27+
export { Textarea };

components/dashboard/src/index.css

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,19 @@
9595
margin: 0 auto !important;
9696
}
9797
p {
98-
@apply text-sm text-gray-400 dark:text-gray-600;
98+
@apply text-sm text-pk-content-secondary;
99+
}
100+
101+
.md-preview p {
102+
@apply text-base;
103+
}
104+
105+
.md-preview ol {
106+
@apply list-decimal list-inside;
107+
}
108+
109+
.md-preview ul {
110+
@apply list-disc list-inside;
99111
}
100112

101113
.app-container {
@@ -118,7 +130,7 @@
118130
}
119131

120132
code {
121-
@apply bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded-md text-sm font-mono font-medium;
133+
@apply bg-gray-100 dark:bg-gray-800 text-pk-content-primary px-1.5 py-0.5 rounded-md text-sm font-mono font-medium;
122134
}
123135

124136
textarea,

components/dashboard/src/teams/TeamOnboarding.tsx

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ import type { PlainMessage } from "@bufbuild/protobuf";
1919
import { InputField } from "../components/forms/InputField";
2020
import { TextInput } from "../components/forms/TextInputField";
2121
import { LoadingButton } from "@podkit/buttons/LoadingButton";
22+
import MDEditor from "@uiw/react-md-editor";
23+
import { Textarea } from "@podkit/forms/TextArea";
24+
import Modal, { ModalFooter, ModalBody, ModalHeader } from "../components/Modal";
25+
import { Button } from "@podkit/buttons/Button";
26+
import { SwitchInputField } from "@podkit/switch/Switch";
27+
28+
const sampleMarkdown = `“With Gitpod, you'll boost your productivity and streamline your workflow, giving you the freedom to work how you want while helping our team meet its efficiency goals.”
29+
30+
**Hannah Cole** - CTO Acme, Inc.
31+
`;
2232

2333
export default function TeamOnboardingPage() {
2434
useDocumentTitle("Organization Settings - Onboarding");
@@ -30,7 +40,9 @@ export default function TeamOnboardingPage() {
3040
const updateTeamSettings = useUpdateOrgSettingsMutation();
3141

3242
const [internalLink, setInternalLink] = useState<string | undefined>(undefined);
33-
43+
const [welcomeMessage, setWelcomeMessage] = useState<string>(sampleMarkdown);
44+
const [showWelcomeMessage, setShowWelcomeMessage] = useState<boolean>(true);
45+
const [welcomeMessageEditorOpen, setWelcomeMessageEditorOpen] = useState<boolean>(false);
3446
const handleUpdateTeamSettings = useCallback(
3547
async (newSettings: Partial<PlainMessage<OrganizationSettings>>, options?: { throwMutateError?: boolean }) => {
3648
if (!org?.id) {
@@ -99,7 +111,100 @@ export default function TeamOnboardingPage() {
99111
</LoadingButton>
100112
</form>
101113
</ConfigurationSettingsField>
114+
115+
<ConfigurationSettingsField>
116+
<Heading3>Welcome message</Heading3>
117+
<Subheading>
118+
A welcome message to your organization members. This message will be shown to your organization
119+
members once they sign up and join your organization.
120+
</Subheading>
121+
122+
<span className="text-pk-content-secondary text-sm">
123+
Here's a preview of the welcome message that will be shown to your organization members:
124+
</span>
125+
<WelcomeMessagePreview
126+
welcomeMessage={welcomeMessage}
127+
setWelcomeMessageEditorOpen={setWelcomeMessageEditorOpen}
128+
/>
129+
130+
<Modal onClose={() => setWelcomeMessageEditorOpen(false)} visible={welcomeMessageEditorOpen}>
131+
<ModalHeader>Edit welcome message</ModalHeader>
132+
<ModalBody>
133+
<InputField
134+
label="Enabled"
135+
hint={<>Enable showing the message to new organization members.</>}
136+
id="show-welcome-message"
137+
>
138+
<SwitchInputField
139+
id="show-welcome-message"
140+
checked={showWelcomeMessage}
141+
disabled={!isOwner || updateTeamSettings.isLoading}
142+
onCheckedChange={setShowWelcomeMessage}
143+
label=""
144+
/>
145+
</InputField>
146+
<WelcomeMessageEditor
147+
welcomeMessage={welcomeMessage}
148+
setWelcomeMessage={setWelcomeMessage}
149+
disabled={!showWelcomeMessage}
150+
/>
151+
</ModalBody>
152+
<ModalFooter>
153+
<Button variant="secondary" onClick={() => setWelcomeMessageEditorOpen(false)}>
154+
Cancel
155+
</Button>
156+
<LoadingButton type="submit" loading={updateTeamSettings.isLoading} disabled={!isOwner}>
157+
Save
158+
</LoadingButton>
159+
</ModalFooter>
160+
</Modal>
161+
</ConfigurationSettingsField>
102162
</div>
103163
</OrgSettingsPage>
104164
);
105165
}
166+
167+
type WelcomeMessagePreviewProps = {
168+
welcomeMessage: string;
169+
setWelcomeMessageEditorOpen: (open: boolean) => void;
170+
};
171+
const WelcomeMessagePreview = ({ welcomeMessage, setWelcomeMessageEditorOpen }: WelcomeMessagePreviewProps) => {
172+
return (
173+
<div className="max-w-2xl mx-auto">
174+
<div className="flex justify-between gap-2 items-center">
175+
<Heading2 className="py-6">Welcome to Gitpod</Heading2>
176+
<Button variant="secondary" onClick={() => setWelcomeMessageEditorOpen(true)}>
177+
Edit
178+
</Button>
179+
</div>
180+
<Subheading>
181+
Gitpod’s sandboxed, ephemeral development environments enable you to use your existing tools without
182+
worrying about vulnerabilities impacting their local machines.
183+
</Subheading>
184+
{/* todo: sanitize md */}
185+
<MDEditor.Markdown
186+
source={welcomeMessage}
187+
className="md-preview space-y-4 p-8 my-4 bg-pk-surface-secondary text-pk-content-primary rounded-xl text-center"
188+
/>
189+
</div>
190+
);
191+
};
192+
193+
type WelcomeMessageEditorProps = {
194+
welcomeMessage: string;
195+
setWelcomeMessage: (welcomeMessage: string) => void;
196+
disabled?: boolean;
197+
};
198+
const WelcomeMessageEditor = ({ welcomeMessage, setWelcomeMessage, disabled }: WelcomeMessageEditorProps) => {
199+
return (
200+
<InputField label="Welcome message" error={undefined} className="mb-4">
201+
<Textarea
202+
className="bg-pk-surface-secondary text-pk-content-primary w-full p-4 rounded-xl min-h-[400px]"
203+
value={welcomeMessage}
204+
placeholder="Write a welcome message to your organization members. Markdown formatting is supported."
205+
onChange={(e) => setWelcomeMessage(e.target.value)}
206+
disabled={disabled}
207+
/>
208+
</InputField>
209+
);
210+
};

0 commit comments

Comments
 (0)