Skip to content

Commit 706a53c

Browse files
authored
feat: export types and fix styling for projects with global css resets (#23)
1 parent 2cb7250 commit 706a53c

File tree

11 files changed

+546
-102
lines changed

11 files changed

+546
-102
lines changed

dev/app/components/EmbeddedWidgetComponent.tsx

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
"use client";
22

33
import { useEffect, useRef, useState } from "react";
4-
54
import { AirbyteEmbeddedWidget, WidgetEvent } from "@/src/EmbeddedWidget";
6-
import styles from "../page.module.css";
7-
8-
// Debug logging to check if AirbyteEmbeddedWidget is available
9-
console.log("AirbyteEmbeddedWidget imported:", Boolean(AirbyteEmbeddedWidget));
105

116
interface EmbeddedWidgetComponentProps {
127
onEvent?: (event: WidgetEvent) => void;
@@ -21,43 +16,25 @@ export function EmbeddedWidgetComponent({ onEvent, className }: EmbeddedWidgetCo
2116

2217
useEffect(() => {
2318
let isMounted = true;
24-
2519
const initializeWidget = async () => {
26-
if (initialized) {
27-
return;
28-
}
29-
20+
if (initialized) return;
3021
try {
3122
const response = await fetch("/api/widget_token");
3223
const data = await response.json();
33-
34-
// Check if component is still mounted after async operations
35-
if (!isMounted) {
36-
return;
37-
}
38-
39-
console.log("Token response:", data);
40-
41-
if (!data.token) {
42-
console.error("Token response:", data);
43-
throw new Error("Missing token in response");
44-
}
45-
24+
if (!isMounted) return;
25+
if (!data.token) throw new Error("Missing token in response");
4626
try {
4727
widgetRef.current = new AirbyteEmbeddedWidget({
4828
token: data.token,
4929
onEvent: (event: WidgetEvent) => {
50-
if (onEvent) {
51-
onEvent(event);
52-
}
30+
onEvent?.(event);
5331
fetch("/api/embedded_response", {
5432
method: "POST",
5533
headers: { "Content-Type": "application/json" },
5634
body: JSON.stringify(event),
5735
}).catch((err) => console.error("Error sending event data:", err));
5836
},
5937
});
60-
6138
if (isMounted) {
6239
setInitialized(true);
6340
setLoading(false);
@@ -72,32 +49,25 @@ export function EmbeddedWidgetComponent({ onEvent, className }: EmbeddedWidgetCo
7249
}
7350
}
7451
};
75-
76-
// Reset initialized state on each mount to handle StrictMode remounting
7752
setInitialized(false);
78-
79-
// Execute initialization
8053
initializeWidget();
81-
8254
return () => {
8355
isMounted = false;
8456
};
8557
}, [onEvent]);
8658

8759
const handleOpenWidget = () => {
88-
if (widgetRef.current) {
89-
widgetRef.current.open();
90-
}
60+
widgetRef.current?.open();
9161
};
9262

9363
return (
94-
<div className={styles.widgetComponentWrapper}>
95-
{loading && <div className={styles.loading}>Loading widget...</div>}
96-
{error && <div className={styles.error}>Error: {error}</div>}
64+
<div className="flex flex-col items-center gap-4">
65+
{loading && <div className="text-gray-600 text-base">Loading widget...</div>}
66+
{error && <div className="text-red-600 text-base p-4 bg-red-100 rounded border border-red-200">Error: {error}</div>}
9767
{initialized && (
98-
<button
68+
<button
9969
onClick={handleOpenWidget}
100-
className={`${styles.widgetButton} ${className || ""}`}
70+
className={`px-6 py-3 text-base font-medium text-white bg-indigo-600 rounded-md shadow hover:bg-indigo-700 active:bg-indigo-800 transition-colors duration-200 ${className || ""}`}
10171
>
10272
Open Airbyte
10373
</button>

dev/app/globals.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import "tailwindcss";
2+
3+
@tailwind base;
4+
@tailwind components;
5+
@tailwind utilities;

dev/app/layout.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import "./globals.css";
12
import type { Metadata } from "next";
23

34
export const metadata: Metadata = {
@@ -11,7 +12,9 @@ export default function RootLayout({
1112
}>) {
1213
return (
1314
<html lang="en">
14-
<body>{children}</body>
15+
<body className="min-h-screen text-black">
16+
{children}
17+
</body>
1518
</html>
1619
);
1720
}

dev/app/page.tsx

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,73 @@
11
"use client";
22

33
import { EmbeddedWidgetComponent } from "./components/EmbeddedWidgetComponent";
4-
import styles from "./page.module.css";
54

65
export default function Home() {
76
const handleWidgetEvent = (event: any) => {
87
console.log("Widget event handled in Home component:", event);
98
};
109

1110
return (
12-
<div className={styles.container}>
13-
<header className={styles.header}>
14-
<h1 className={styles.heading}>Airbyte Embedded Widget</h1>
11+
<div className="min-h-screen bg-gradient-to-br from-indigo-50 via-blue-50 to-indigo-100 flex flex-col">
12+
<header className="w-full py-10 shadow-md mb-12 border-b border-indigo-100">
13+
<div className="max-w-2xl mx-auto flex flex-col items-center px-6">
14+
<h1 className="text-5xl font-black text-indigo-700 tracking-tight drop-shadow-sm mb-2 text-center">
15+
Airbyte Embedded Widget
16+
</h1>
17+
<p className="text-lg text-indigo-400 font-medium text-center">
18+
A beautiful developer playground for your widget
19+
</p>
20+
</div>
1521
</header>
1622

17-
<div className={styles.widgetContainer}>
18-
<p className={styles.note}>Click the button below to open the Airbyte widget.</p>
19-
<div className={styles.buttonContainer}>
20-
<EmbeddedWidgetComponent onEvent={handleWidgetEvent} />
23+
<main className="flex-1 flex flex-col items-center justify-center px-2 pb-12">
24+
<div className=" p-10 rounded-3xl shadow-2xl w-full max-w-lg text-center mb-12 border border-indigo-100 transition-all duration-300">
25+
<p className="text-base opacity-90 mb-8 text-gray-700">
26+
Click the button below to open the Airbyte widget.
27+
</p>
28+
<div className="flex justify-center mt-2">
29+
<EmbeddedWidgetComponent onEvent={handleWidgetEvent} />
30+
</div>
2131
</div>
22-
</div>
2332

24-
<div className={styles.envContainer}>
25-
<h2 className={styles.headingSmall}>Environment Variables:</h2>
26-
<EnvVar label="NEXT_PUBLIC_WORKSPACE_ID" value={process.env.NEXT_PUBLIC_WORKSPACE_ID} />
27-
<EnvVar label="NEXT_PUBLIC_CLIENT_ID" value={process.env.NEXT_PUBLIC_CLIENT_ID} />
28-
<EnvVar
29-
label="NEXT_PUBLIC_CLIENT_SECRET"
30-
value={process.env.NEXT_PUBLIC_CLIENT_SECRET ? "******" : "Not set"}
31-
/>
32-
<EnvVar label="NEXT_PUBLIC_BASE_URL" value={process.env.NEXT_PUBLIC_BASE_URL} />
33-
<p className={styles.envNote}>
34-
Note: Environment variables must be prefixed with <code>NEXT_PUBLIC_</code> to be visible on the client side.
35-
</p>
36-
</div>
33+
<div className="w-full max-w-lg border border-indigo-100 p-8 rounded-2xl bg-white/90 shadow-lg">
34+
<h2 className="text-xl font-bold mb-6 text-indigo-700 flex items-center gap-2">
35+
<span className="inline-block w-3 h-3 bg-indigo-400 rounded-full animate-pulse" />
36+
Environment Variables
37+
</h2>
38+
<div className="space-y-3 mb-4">
39+
<EnvVar
40+
label="NEXT_PUBLIC_WORKSPACE_ID"
41+
value={process.env.NEXT_PUBLIC_WORKSPACE_ID}
42+
/>
43+
<EnvVar label="NEXT_PUBLIC_CLIENT_ID" value={process.env.NEXT_PUBLIC_CLIENT_ID} />
44+
<EnvVar
45+
label="NEXT_PUBLIC_CLIENT_SECRET"
46+
value={process.env.NEXT_PUBLIC_CLIENT_SECRET ? "******" : "Not set"}
47+
/>
48+
<EnvVar label="NEXT_PUBLIC_BASE_URL" value={process.env.NEXT_PUBLIC_BASE_URL} />
49+
</div>
50+
<p className="mt-3 text-xs text-gray-500 text-left">
51+
<span className="font-semibold text-indigo-500">Note:</span> Environment variables must be prefixed with{" "}
52+
<code className="bg-indigo-50 px-1 rounded text-indigo-700">NEXT_PUBLIC_</code> to be visible on the client side.
53+
</p>
54+
</div>
55+
</main>
3756
</div>
3857
);
3958
}
4059

41-
function EnvVar({ label, value }: { label: string; value: string | undefined }) {
60+
function EnvVar({
61+
label,
62+
value,
63+
}: {
64+
label: string;
65+
value: string | undefined;
66+
}) {
4267
return (
43-
<div>
44-
<b>{label}:</b> {value || "Not set"}
68+
<div className="flex items-center justify-between bg-indigo-50/80 px-4 py-2 rounded-lg text-base border border-indigo-100">
69+
<span className="font-semibold text-indigo-800 tracking-wide">{label}:</span>
70+
<span className="ml-3 text-gray-700 font-mono break-all">{value || "Not set"}</span>
4571
</div>
4672
);
4773
}

dev/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515
"react-dom": "^18"
1616
},
1717
"devDependencies": {
18+
"@tailwindcss/postcss": "^4.1.10",
1819
"@types/node": "^20.11.24",
1920
"@types/react": "^18",
2021
"@types/react-dom": "^18",
22+
"autoprefixer": "^10.4.21",
2123
"eslint": "^9.23.0",
2224
"eslint-config-next": "14.2.5",
25+
"postcss": "^8.5.6",
26+
"tailwindcss": "^4.1.10",
2327
"typescript": "5.8.2"
2428
}
2529
}

dev/postcss.config.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const config = {
2+
plugins: {
3+
"@tailwindcss/postcss": {},
4+
},
5+
};
6+
export default config;

dev/tailwind.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = {
2+
content: [
3+
"./app/**/*.{js,ts,jsx,tsx}",
4+
],
5+
theme: {
6+
extend: {},
7+
},
8+
plugins: [],
9+
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@airbyte-embedded/airbyte-embedded-widget",
3-
"version": "0.4.2",
3+
"version": "0.4.3",
44
"description": "Embedded widget for Airbyte",
55
"type": "module",
66
"main": "dist/index.cjs.js",

0 commit comments

Comments
 (0)