Skip to content

Commit 99ba29f

Browse files
committed
Merge branch 'FRAGt4g-feature/dap-banner'
2 parents 1ec6b90 + cdbbd84 commit 99ba29f

12 files changed

Lines changed: 1277 additions & 47 deletions

File tree

entrypoints/components/banner.tsx

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,50 @@
1-
const Banner = (): React.ReactNode => {
2-
return (
3-
<div className="fixed top-0 left-0 w-full bg-gradient-to-r from-orange-500 to-red-500 text-white p-4 shadow-lg z-50">
4-
<div className="text-center">
5-
<h2 className="text-xl font-bold mb-1">🎓 Degree Audit Plus</h2>
6-
<p className="text-sm opacity-90">
7-
Enhanced degree audit experience - Powered by Longhorn Developers
8-
</p>
9-
</div>
10-
</div>
11-
);
1+
import { AnimatePresence, motion } from "framer-motion";
2+
import { XIcon } from "lucide-react";
3+
import { useState } from "react";
4+
import "~/entrypoints/styles/content.css";
5+
import ArrowTopRightIcon from "../svgs/arrow-top-right";
6+
import LHDLogo from "../svgs/lhd-logo";
7+
8+
const TryDAPBanner = () => {
9+
const [isOpen, setIsOpen] = useState(true);
10+
11+
const handleClose = () => {
12+
setIsOpen(false);
13+
};
14+
15+
return (
16+
<AnimatePresence>
17+
{isOpen && (
18+
<motion.div
19+
className="bg-amber-700 relative w-full p-4 flex justify-start items-center gap-6 flex-row text-white shadow-lg shadow-black/20 rounded-lg"
20+
initial={{ opacity: 0, y: 100 }}
21+
animate={{ opacity: 1, y: 0 }}
22+
exit={{ opacity: 0, y: -100 }}
23+
transition={{ duration: 0.3 }}
24+
>
25+
<LHDLogo />
26+
<div className="flex flex-col gap-2">
27+
<h2 className="text-5xl font-bold font-header-title">
28+
Try Degree Audit Plus
29+
</h2>
30+
<p className="text-base font-normal">
31+
Take control of your degree plan with real-time progress, visual
32+
tracking, and flexible planning tools.
33+
</p>
34+
</div>
35+
<button className="flex items-center gap-2 text-black absolute right-4 bottom-4 bg-white rounded-lg px-2 py-1 cursor-pointer border-none outline-none shadow-none transition-all duration-300 ease-in-out transform scale-100 origin-center">
36+
<ArrowTopRightIcon className="w-8 h-8" /> Try it now!
37+
</button>
38+
<button
39+
className=" text-white h-8 w-8 flex items-center justify-center cursor-pointer absolute right-4 top-4"
40+
onClick={handleClose}
41+
>
42+
<XIcon />
43+
</button>
44+
</motion.div>
45+
)}
46+
</AnimatePresence>
47+
);
1248
};
1349

14-
export default Banner;
50+
export default TryDAPBanner;
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import { forwardRef } from "react";
2+
import { cn } from "~/lib/utils";
3+
4+
type DivProps = React.HTMLAttributes<HTMLDivElement> & {
5+
xSpacing?: "left" | "center" | "right" | "baseline" | "stretch";
6+
ySpacing?: "top" | "middle" | "bottom" | "space-between" | "space-around";
7+
gap?: number;
8+
centered?: boolean;
9+
};
10+
11+
export const VStack = forwardRef<HTMLDivElement, DivProps>(
12+
(
13+
{
14+
children,
15+
className,
16+
gap = 4,
17+
centered = false,
18+
xSpacing,
19+
ySpacing,
20+
...props
21+
},
22+
ref
23+
) => {
24+
VStack.displayName = "VStack";
25+
const _xSpacing = centered ? "center" : xSpacing ?? "left";
26+
const _ySpacing = centered ? "middle" : ySpacing ?? "top";
27+
return (
28+
<div
29+
ref={ref}
30+
className={cn("flex flex-col", className, {
31+
"items-center": _xSpacing === "center",
32+
"items-left": _xSpacing === "left",
33+
"items-right": _xSpacing === "right",
34+
"justify-center": _ySpacing === "middle",
35+
"justify-start": _ySpacing === "top",
36+
"justify-end": _ySpacing === "bottom",
37+
"justify-between": _ySpacing === "space-between",
38+
"justify-around": _ySpacing === "space-around",
39+
})}
40+
style={{ gap: `${gap / 4}rem` }}
41+
{...props}
42+
>
43+
{children}
44+
</div>
45+
);
46+
}
47+
);
48+
49+
export const HStack = forwardRef<HTMLDivElement, DivProps>(
50+
(
51+
{
52+
children,
53+
className,
54+
gap = 4,
55+
centered = false,
56+
xSpacing,
57+
ySpacing,
58+
...props
59+
},
60+
ref
61+
) => {
62+
HStack.displayName = "HStack";
63+
const _xSpacing = centered ? "center" : xSpacing ?? "left";
64+
const _ySpacing = centered ? "middle" : ySpacing ?? "top";
65+
return (
66+
<div
67+
ref={ref}
68+
className={cn("flex flex-row", className, {
69+
"items-center": _xSpacing === "center",
70+
"items-left": _xSpacing === "left",
71+
"items-right": _xSpacing === "right",
72+
"justify-start": _ySpacing === "top",
73+
"justify-center": _ySpacing === "middle",
74+
"justify-end": _ySpacing === "bottom",
75+
"justify-between": _ySpacing === "space-between",
76+
"justify-around": _ySpacing === "space-around",
77+
})}
78+
style={{ gap: `${gap / 4}rem` }}
79+
{...props}
80+
>
81+
{children}
82+
</div>
83+
);
84+
}
85+
);
86+
87+
export const Wrap = forwardRef<HTMLDivElement, DivProps & { maxCols?: number }>(
88+
(
89+
{
90+
children,
91+
className,
92+
gap = 4,
93+
centered = false,
94+
xSpacing,
95+
ySpacing,
96+
maxCols,
97+
...props
98+
},
99+
ref
100+
) => {
101+
Wrap.displayName = "Wrap";
102+
const _xSpacing = centered ? "center" : xSpacing ?? "left";
103+
const _ySpacing = centered ? "middle" : ySpacing ?? "top";
104+
return (
105+
<div
106+
ref={ref}
107+
className={cn("flex flex-row flex-wrap", className, {
108+
"flex-wrap": maxCols !== -1,
109+
"items-center": _xSpacing === "center",
110+
"items-left": _xSpacing === "left",
111+
"items-right": _xSpacing === "right",
112+
"justify-center": _ySpacing === "middle",
113+
"justify-start": _ySpacing === "top",
114+
"justify-end": _ySpacing === "bottom",
115+
"justify-between": _ySpacing === "space-between",
116+
"justify-around": _ySpacing === "space-around",
117+
})}
118+
style={{ gap: `${gap / 4}rem` }}
119+
{...props}
120+
>
121+
{children}
122+
</div>
123+
);
124+
}
125+
);
126+
127+
type GridProps = React.HTMLAttributes<HTMLDivElement> & {
128+
maxCols?: number;
129+
xGap?: number;
130+
yGap?: number;
131+
direction?: "row" | "column";
132+
xSpacing?:
133+
| "center"
134+
| "left"
135+
| "right"
136+
| "space-between"
137+
| "space-around"
138+
| "space-evenly";
139+
ySpacing?:
140+
| "middle"
141+
| "top"
142+
| "bottom"
143+
| "space-between"
144+
| "space-around"
145+
| "space-evenly";
146+
};
147+
export const Grid = forwardRef<HTMLDivElement, GridProps>(
148+
(
149+
{
150+
children,
151+
className,
152+
maxCols = -1,
153+
xGap = 4,
154+
yGap = 4,
155+
direction = "row",
156+
xSpacing = "left",
157+
ySpacing = "top",
158+
...props
159+
},
160+
ref
161+
) => {
162+
Grid.displayName = "Grid";
163+
return (
164+
<div
165+
ref={ref}
166+
className={cn("grid", className, {
167+
"grid-cols-1": direction === "column",
168+
"grid-cols-2": direction === "row",
169+
"items-center": xSpacing === "center",
170+
"items-left": xSpacing === "left",
171+
"items-right": xSpacing === "right",
172+
"justify-center": ySpacing === "middle",
173+
"justify-start": ySpacing === "top",
174+
"justify-end": ySpacing === "bottom",
175+
"justify-between": ySpacing === "space-between",
176+
"justify-around": ySpacing === "space-around",
177+
})}
178+
style={{
179+
gap: `${yGap / 4}rem ${xGap / 4}rem`,
180+
gridTemplateColumns: `repeat(${maxCols}, 1fr)`,
181+
}}
182+
{...props}
183+
>
184+
{children}
185+
</div>
186+
);
187+
}
188+
);

entrypoints/content.tsx

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,55 @@
11
import { createRoot } from "react-dom/client";
2-
import Banner from "./components/banner";
3-
import "./styles/content.css";
2+
import TryDAPBanner from "./components/banner";
43

54
export default defineContentScript({
6-
matches: ["https://utdirect.utexas.edu/*"],
7-
main() {
8-
console.log("Content script loaded.");
5+
matches: ["https://utdirect.utexas.edu/apps/degree/audits/"],
6+
cssInjectionMode: "ui",
7+
async main(ctx) {
8+
console.log("Content script loaded.");
99

10-
const container = document.createElement("div");
11-
container.id = "dap-banner-root";
12-
document.body.prepend(container);
10+
// Load fonts dynamically
11+
loadFonts();
1312

14-
const root = createRoot(container);
15-
root.render(<Banner />);
16-
},
13+
defineUTDToppageHeight();
14+
15+
const tryDapBanner = await createShadowRootUi(ctx, {
16+
name: "dap-banner-ui",
17+
position: "inline",
18+
append: "before",
19+
anchor: "#service_content",
20+
onMount(container) {
21+
createRoot(container).render(<TryDAPBanner />);
22+
},
23+
});
24+
25+
tryDapBanner.mount();
26+
},
1727
});
28+
29+
function loadFonts() {
30+
const preconnect1 = document.createElement("link");
31+
preconnect1.rel = "preconnect";
32+
preconnect1.href = "https://fonts.googleapis.com";
33+
document.head.appendChild(preconnect1);
34+
35+
const preconnect2 = document.createElement("link");
36+
preconnect2.rel = "preconnect";
37+
preconnect2.href = "https://fonts.gstatic.com";
38+
preconnect2.crossOrigin = "anonymous";
39+
document.head.appendChild(preconnect2);
40+
41+
const fontLink = document.createElement("link");
42+
fontLink.rel = "stylesheet";
43+
fontLink.href =
44+
"https://fonts.googleapis.com/css2?family=Staatliches:wght@400&family=Roboto+Flex:opsz,wght@8..144,100..1000&display=swap";
45+
document.head.appendChild(fontLink);
46+
47+
console.log("Staatliches and Roboto Flex fonts loaded dynamically");
48+
}
49+
50+
function defineUTDToppageHeight() {
51+
const utdToppage = document.querySelector("#utd_toppage");
52+
if (utdToppage) {
53+
(utdToppage as HTMLElement).style.height = "96px";
54+
}
55+
}

entrypoints/popup/index.html

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
<!doctype html>
1+
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8" />
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>Default Popup Title</title>
7-
<meta name="manifest.type" content="browser_action" />
8-
</head>
9-
<body>
10-
<div id="root"></div>
11-
<script type="module" src="./main.tsx"></script>
12-
</body>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Default Popup Title</title>
7+
<meta name="manifest.type" content="browser_action" />
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="./main.tsx"></script>
12+
</body>
1313
</html>

entrypoints/styles/content.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
11
@import "tailwindcss";
2+
3+
/* Load Staatliches font directly */
4+
@import url("https://fonts.googleapis.com/css2?family=Staatliches:wght@400&display=swap");
5+
6+
/* Load Roboto Flex font directly */
7+
@import url("https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght@8..144,100..1000&display=swap");
8+
9+
/* Ensure proper font loading in shadow DOM */
10+
* {
11+
font-family: "Roboto Flex", "Staatliches", "Arial Black", "Helvetica Neue",
12+
sans-serif;
13+
}
14+
15+
.font-header-title {
16+
font-family: "Staatliches", "Arial Black", "Helvetica Neue", sans-serif;
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const ArrowTopRightIcon = ({ className }: { className?: string }) => {
2+
return (
3+
<svg
4+
width="35"
5+
height="35"
6+
viewBox="0 0 35 35"
7+
fill="none"
8+
xmlns="http://www.w3.org/2000/svg"
9+
className={className}
10+
>
11+
<path
12+
d="M26.8308 8.58587V22.538C26.8308 22.8226 26.7178 23.0956 26.5165 23.2969C26.3152 23.4981 26.0422 23.6112 25.7576 23.6112C25.473 23.6112 25.2 23.4981 24.9987 23.2969C24.7974 23.0956 24.6844 22.8226 24.6844 22.538V11.1764L9.34511 26.517C9.14373 26.7184 8.8706 26.8315 8.5858 26.8315C8.301 26.8315 8.02786 26.7184 7.82648 26.517C7.6251 26.3156 7.51196 26.0425 7.51196 25.7577C7.51196 25.4729 7.6251 25.1997 7.82648 24.9984L23.1671 9.65911H11.8055C11.5209 9.65911 11.2479 9.54604 11.0466 9.34476C10.8453 9.14349 10.7323 8.87051 10.7323 8.58587C10.7323 8.30123 10.8453 8.02825 11.0466 7.82698C11.2479 7.62571 11.5209 7.51263 11.8055 7.51263H25.7576C26.0422 7.51263 26.3152 7.62571 26.5165 7.82698C26.7178 8.02825 26.8308 8.30123 26.8308 8.58587Z"
13+
fill="#1A2024"
14+
/>
15+
</svg>
16+
);
17+
};
18+
19+
export default ArrowTopRightIcon;

0 commit comments

Comments
 (0)