Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/components/content/YoutubePreviewPlayer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,21 @@ describe("YoutubePreviewPlayer", () => {
act(() => window.dispatchEvent(new Event("scroll")));
expect(pause).toHaveBeenCalled();
});

it("cropEdges가 설정되면 영상의 가장자리 픽셀을 확대해 잘라낸다", () => {
const { container } = render(
<YoutubePreviewPlayer
autoplayOnView
cropEdges
framed
thumbnailAlt="AIP thumbnail"
thumbnailSrc="/aip-cover.png"
title="Cropped AIP video"
videoSrc="/aip.mp4"
/>,
);

expect(screen.getByLabelText("Cropped AIP video")).toHaveClass("scale-[1.01]");
expect(container.firstElementChild).toHaveClass("feature-gif-frame");
});
});
11 changes: 8 additions & 3 deletions src/components/content/YoutubePreviewPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import MediaPlayButton from "@/components/ui/MediaPlayButton";

type YoutubePreviewPlayerProps = {
autoplayOnView?: boolean;
cropEdges?: boolean;
embedSrc?: string;
framed?: boolean;
thumbnailAlt: string;
thumbnailSrc: string;
title: string;
Expand All @@ -25,14 +27,17 @@ function withPlaybackParams(src: string) {

export default function YoutubePreviewPlayer({
autoplayOnView = false,
cropEdges = false,
embedSrc,
framed = false,
thumbnailAlt,
thumbnailSrc,
title,
videoSrc,
}: YoutubePreviewPlayerProps) {
const [isPlaying, setIsPlaying] = useState(false);
const videoRef = useRef<HTMLVideoElement>(null);
const videoClassName = `block h-full w-full bg-black object-cover ${cropEdges ? "scale-[1.01]" : ""}`;

useEffect(() => {
if (!autoplayOnView || !videoSrc) return;
Expand Down Expand Up @@ -81,11 +86,11 @@ export default function YoutubePreviewPlayer({
}, [autoplayOnView, videoSrc]);

return (
<div className="aspect-video w-full max-w-[1080px] overflow-hidden rounded-box bg-bg-content">
<div className={`aspect-video w-full max-w-[1080px] overflow-hidden rounded-box bg-bg-content ${framed ? "feature-gif-frame" : ""}`}>
{autoplayOnView && videoSrc ? (
<video
aria-label={title}
className="block h-full w-full bg-black object-cover"
className={videoClassName}
controls
loop
muted
Expand All @@ -98,7 +103,7 @@ export default function YoutubePreviewPlayer({
) : isPlaying && videoSrc ? (
<video
autoPlay
className="block h-full w-full bg-black object-cover"
className={videoClassName}
controls
playsInline
poster={thumbnailSrc}
Expand Down
4 changes: 2 additions & 2 deletions src/components/forms/ContactFormParts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ export function ContactPrivacyNotice({
return (
<p className="m-0 type-body-md leading-5 text-fg">
{privacyText}{" "}
<a className="text-brand transition-colors hover:text-fg" href={privacyTermsHref}>
<a className="text-link transition-colors hover:text-link-hover" href={privacyTermsHref}>
{privacyTermsLabel}
</a>{" "}
&{" "}
<a className="text-brand transition-colors hover:text-fg" href={privacyPolicyHref}>
<a className="text-link transition-colors hover:text-link-hover" href={privacyPolicyHref}>
{privacyPolicyLabel}
</a>
.
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export default function Footer({
</a>
))}
</div>
<ThemeSwitch className="md:min-w-[132px]" locale={locale as Locale} />
<ThemeSwitch locale={locale as Locale} />
</div>

{/* 법적 링크 */}
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/admin/AdminShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export default function AdminShell({ children }: AdminShellProps) {
</div>
))}
<div className="mt-auto border-t border-border pt-5">
<ThemeSwitch className="w-full px-1" locale="ko" />
<ThemeSwitch className="w-full justify-center" locale="ko" />
</div>
</nav>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/admin/AdminSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export default function AdminSidebar({

<div className={cx("relative z-20 mt-5 pt-5 md:mt-auto", isCollapsed ? "flex justify-center" : "flex flex-col gap-2")}>
<ThemeSwitch
className={cx(isCollapsed ? "h-11 w-9" : "w-full px-3")}
className={cx(isCollapsed ? "w-9" : "w-full justify-center")}
compact={isCollapsed}
locale="ko"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function CommunityLicenseApplyPage(copy: CommunityLicenseApplyPag
<p key={item.label} className="m-0">
<span className="text-fg">{item.label}:</span>{" "}
<a
className="text-brand transition-colors hover:text-fg"
className="text-link transition-colors hover:text-link-hover"
href={item.href}
>
{item.value}
Expand All @@ -51,7 +51,7 @@ export default function CommunityLicenseApplyPage(copy: CommunityLicenseApplyPag
<div className="flex flex-col gap-2">
<p className="m-0 type-body-md text-mute">{supportLink.title}</p>
<a
className="inline-flex items-center gap-1.5 type-body-md text-brand transition-colors hover:text-fg"
className="inline-flex items-center gap-1.5 type-body-md text-link transition-colors hover:text-link-hover"
href={supportLink.href}
rel="noreferrer noopener"
target="_blank"
Expand Down
4 changes: 2 additions & 2 deletions src/components/pages/contact/ContactUsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function ContactUsPage(props: ContactUsPageProps) {
<p key={item.label} className="m-0">
<span className="text-fg">{item.label}:</span>{" "}
<a
className="text-brand transition-colors hover:text-fg"
className="text-link transition-colors hover:text-link-hover"
href={item.href}
>
{item.value}
Expand All @@ -55,7 +55,7 @@ export default function ContactUsPage(props: ContactUsPageProps) {
<div className="flex flex-col gap-2">
<p className="m-0 type-body-md text-mute">{supportLink.title}</p>
<a
className="inline-flex self-start items-center gap-1.5 type-body-md text-brand transition-colors hover:text-fg"
className="inline-flex self-start items-center gap-1.5 type-body-md text-link transition-colors hover:text-link-hover"
href={supportLink.href}
rel="noreferrer noopener"
target="_blank"
Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/home/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export default function HomePage({
</div>

<div><Clients caption={clientCaption} /></div>
<div><FeatureMediaList items={featureItems} /></div>
<div><FeatureMediaList className="home-feature-media-list" items={featureItems} /></div>
<div>
<Mcps
action={mcpAction}
Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/legal/LegalContentBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function LegalContentBody({
"[&_h3]:m-0 [&_h3]:mt-7 [&_h3:first-of-type]:mt-0 [&_h3]:type-h3 [&_h3]:text-fg",
"[&_p]:m-0 [&_p]:mt-4 [&_p:first-child]:mt-0 [&_p]:type-body-lg [&_p]:leading-8 [&_p]:whitespace-pre-wrap [&_p]:text-fg",
"[&_strong]:font-semibold [&_strong]:text-fg",
"[&_a]:text-brand [&_a]:transition-colors hover:[&_a]:text-fg",
"[&_a]:text-link [&_a]:transition-colors [&_a:hover]:text-link-hover",
"[&_ul]:m-0 [&_ul]:mt-4 [&_ul]:flex [&_ul]:list-disc [&_ul]:flex-col [&_ul]:gap-2 [&_ul]:pl-6",
"[&_ol]:m-0 [&_ol]:mt-4 [&_ol]:flex [&_ol]:list-decimal [&_ol]:flex-col [&_ol]:gap-2 [&_ol]:pl-6",
"[&_li]:type-body-lg [&_li]:leading-8 [&_li]:text-fg",
Expand Down
2 changes: 2 additions & 0 deletions src/components/pages/solutions/aip/content.en.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export default function AipENSolutionContent({ locale }: Props) {
<section className="flex w-full justify-center">
<YoutubePreviewPlayer
autoplayOnView
cropEdges
framed
thumbnailAlt="QueryPie AI Platform video thumbnail"
thumbnailSrc="/assets/products/aip/aip-cover.png"
title="QueryPie AI Platform video"
Expand Down
2 changes: 2 additions & 0 deletions src/components/pages/solutions/aip/content.ja.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ export default function AipJASolutionContent({ locale }: Props) {
<section className="flex w-full justify-center">
<YoutubePreviewPlayer
autoplayOnView
cropEdges
framed
thumbnailAlt="QueryPie AI Platform video thumbnail"
thumbnailSrc="/assets/products/aip/aip-cover.png"
title="QueryPie AI Platform video"
Expand Down
2 changes: 2 additions & 0 deletions src/components/pages/solutions/aip/content.ko.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export default function AipKOSolutionContent({ locale }: Props) {
<section className="flex w-full justify-center">
<YoutubePreviewPlayer
autoplayOnView
cropEdges
framed
thumbnailAlt="QueryPie AI Platform video thumbnail"
thumbnailSrc="/assets/products/aip/aip-cover.png"
title="QueryPie AI Platform video"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default function AiCrewWhitepaperSection({
</div>
<h2 className="mb-3 mt-5 max-w-[760px] break-keep text-pretty type-h2 text-fg">{title}</h2>
<p className="m-0 max-w-[760px] type-body-md text-mute">{description}</p>
<span className="mt-6 inline-flex items-center justify-center gap-1.5 type-body-md text-brand transition-colors group-hover:text-fg">
<span className="mt-6 inline-flex items-center justify-center gap-1.5 type-body-md text-link transition-colors group-hover:text-link-hover">
<span>{action}</span>
<svg aria-hidden="true" className="h-4 w-4 text-mute group-hover:animate-[button-arrow-nudge_220ms_ease-out_forwards]" fill="none" viewBox="0 0 24 24">
<path d="M15.5 6.5L21.5 12.5M21.5 12.5L15.5 18.5M21.5 12.5H3.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5" />
Expand Down
3 changes: 2 additions & 1 deletion src/components/sections/FeatureMediaList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ function FeatureMedia({
<div
className={cx(
"overflow-hidden rounded-box",
videoSrc && "feature-video-frame",
videoSrc ? "w-full shrink-0 lg:w-[790px] lg:max-w-[65%]" : "aspect-[2/1] w-full shrink-0 lg:w-[790px] lg:max-w-[65%]",
isGif && "feature-gif-frame",
className,
Expand Down Expand Up @@ -301,7 +302,7 @@ export default function FeatureMediaList({
<div
key={`${item.videoSrc ?? item.imageSrc}-${index}`}
className={cx(
"flex min-w-0 flex-col items-start gap-5 lg:flex-row lg:gap-[60px]",
"flex min-w-0 flex-col items-start gap-5 lg:flex-row lg:gap-[40px]",
shouldReverse && "lg:flex-row-reverse",
)}
data-reveal
Expand Down
4 changes: 2 additions & 2 deletions src/components/site/CookieConsentBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default function CookieConsentBanner({ locale }: CookieConsentBannerProps
<p className="m-0 type-body-md text-mute">
{copy.sentenceBeforePrivacy}{" "}
<a
className="text-brand transition-colors hover:text-fg"
className="text-link transition-colors hover:text-link-hover"
href={getLocalePath(locale, "/privacy-policy")}
>
{copy.privacyPolicyLinkLabel}
Expand All @@ -100,7 +100,7 @@ export default function CookieConsentBanner({ locale }: CookieConsentBannerProps
<br />
{copy.sentenceBeforeCookiePreference}{" "}
<a
className="text-brand transition-colors hover:text-fg"
className="text-link transition-colors hover:text-link-hover"
href={getLocalePath(locale, "/cookie-preference")}
>
{copy.cookiePreferenceLinkLabel}
Expand Down
24 changes: 13 additions & 11 deletions src/components/site/ThemeSwitch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,26 @@ describe("ThemeSwitch", () => {
it("시스템, 라이트, 다크 옵션을 표시하고 선택한 테마를 저장한다", async () => {
render(<ThemeSwitch locale="ko" />);

const themeSelect = screen.getByRole("combobox", { name: "컬러 테마 선택" });
expect(themeSelect).toHaveValue("system");
expect(screen.getByRole("option", { name: "시스템 모드" })).toBeInTheDocument();
expect(screen.getByRole("option", { name: "라이트 모드" })).toBeInTheDocument();
expect(screen.getByRole("option", { name: "다크 모드" })).toBeInTheDocument();
const systemTheme = screen.getByRole("radio", { name: "시스템 모드" });
const lightTheme = screen.getByRole("radio", { name: "라이트 모드" });
const darkTheme = screen.getByRole("radio", { name: "다크 모드" });
expect(screen.getByRole("radiogroup", { name: "컬러 테마 선택" })).toBeInTheDocument();
expect(systemTheme).toBeChecked();
expect(lightTheme).not.toBeChecked();
expect(darkTheme).not.toBeChecked();

fireEvent.change(themeSelect, { target: { value: "dark" } });
fireEvent.click(darkTheme);

await waitFor(() => {
expect(themeSelect).toHaveValue("dark");
expect(darkTheme).toBeChecked();
});
expect(document.documentElement.dataset.theme).toBe("dark");
expect(localStorage.getItem(THEME_STORAGE_KEY)).toBe("dark");

fireEvent.change(themeSelect, { target: { value: "system" } });
fireEvent.click(systemTheme);

await waitFor(() => {
expect(themeSelect).toHaveValue("system");
expect(systemTheme).toBeChecked();
});
expect(document.documentElement.dataset.theme).toBe("light");
expect(localStorage.getItem(THEME_STORAGE_KEY)).toBeNull();
Expand All @@ -60,7 +62,7 @@ describe("ThemeSwitch", () => {
render(<ThemeSwitch locale="en" />);

await waitFor(() => {
expect(screen.getByRole("combobox", { name: "Select color theme" })).toHaveValue("system");
expect(screen.getByRole("radio", { name: "System mode" })).toBeChecked();
});
expect(document.documentElement.dataset.theme).toBe("dark");
});
Expand All @@ -71,7 +73,7 @@ describe("ThemeSwitch", () => {
render(<ThemeSwitch locale="en" />);

await waitFor(() => {
expect(screen.getByRole("combobox", { name: "Select color theme" })).toHaveValue("system");
expect(screen.getByRole("radio", { name: "System mode" })).toBeChecked();
});

const changeHandler = addEventListener.mock.calls.find(([eventName]) => eventName === "change")?.[1];
Expand Down
Loading