Skip to content
Draft
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
41 changes: 35 additions & 6 deletions src/components/Core/Select/UnifiedSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,18 @@
return selectedOption ? selectedOption.label : "";
});

const selectedSingleOption = useComputed$(() => {
const val = currentValue.value;

if (!val || Array.isArray(val)) {
return undefined;
}

return options.find((opt) => opt.value === val);
});

// Check if mobile device and handle orientation changes
useVisibleTask$(() => {

Check warning on line 235 in src/components/Core/Select/UnifiedSelect.tsx

View workflow job for this annotation

GitHub Actions / ESLint and Prettier

useVisibleTask$() runs eagerly and blocks the main thread, preventing user interaction until the task is finished. Consider using useTask$(), useOn(), useOnDocument(), or useOnWindow() instead. If you have to use a useVisibleTask$(), you can disable the warning with a '// eslint-disable-next-line qwik/no-use-visible-task' comment
const checkMobile = () => {
isMobile.value = window.innerWidth < 768;
// Recalculate position on orientation change for mobile
Expand Down Expand Up @@ -351,7 +361,7 @@
});

// Update dropdown position when opened or window resizes
useVisibleTask$(({ track }) => {

Check warning on line 364 in src/components/Core/Select/UnifiedSelect.tsx

View workflow job for this annotation

GitHub Actions / ESLint and Prettier

useVisibleTask$() runs eagerly and blocks the main thread, preventing user interaction until the task is finished. Consider using useTask$(), useOn(), useOnDocument(), or useOnWindow() instead. If you have to use a useVisibleTask$(), you can disable the warning with a '// eslint-disable-next-line qwik/no-use-visible-task' comment
track(() => isOpen.value);
track(() => filteredOptions.value.length);

Expand All @@ -366,7 +376,7 @@
useOnWindow("scroll", calculateDropdownPosition);

// Close dropdown when clicking outside
useVisibleTask$(({ track }) => {

Check warning on line 379 in src/components/Core/Select/UnifiedSelect.tsx

View workflow job for this annotation

GitHub Actions / ESLint and Prettier

useVisibleTask$() runs eagerly and blocks the main thread, preventing user interaction until the task is finished. Consider using useTask$(), useOn(), useOnDocument(), or useOnWindow() instead. If you have to use a useVisibleTask$(), you can disable the warning with a '// eslint-disable-next-line qwik/no-use-visible-task' comment
track(() => containerRef.value);
if (!containerRef.value) return;

Expand Down Expand Up @@ -510,10 +520,17 @@

// Helper function to render option content
const renderOption = (option: SelectOption, isOptionSelected: boolean) => {
// We'll simplify to use only the default rendering for now
// Custom renderers can be implemented with proper Qwik patterns later
return (
<span class={isOptionSelected ? "font-medium" : ""}>{option.label}</span>
<span class="flex items-center gap-2">
{option.icon && (
<span class="flex h-4 w-4 flex-shrink-0 items-center justify-center text-current">
{option.icon}
</span>
)}
<span class={isOptionSelected ? "font-medium" : ""}>
{option.label}
</span>
</span>
);
};

Expand Down Expand Up @@ -744,8 +761,17 @@
: undefined
}
>
<span class={!displayValue.value ? styles.placeholder : ""}>
{loading ? loadingText : displayValue.value || placeholder}
<span
class={`flex min-w-0 items-center gap-2 ${!displayValue.value ? styles.placeholder : ""}`}
>
{!loading && selectedSingleOption.value?.icon && (
<span class="flex h-4 w-4 flex-shrink-0 items-center justify-center text-current">
{selectedSingleOption.value.icon}
</span>
)}
<span class="truncate">
{loading ? loadingText : displayValue.value || placeholder}
</span>
</span>

{/* Loading indicator for button */}
Expand Down Expand Up @@ -1137,7 +1163,10 @@
</div>
)}

<span>{option.label}</span>
{renderOption(
option,
isSelected(option.value),
)}
</div>
),
);
Expand Down
7 changes: 6 additions & 1 deletion src/components/Core/Select/UnifiedSelect.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Type definitions for the unified Select component
*/

import { type QRL } from "@builder.io/qwik";
import { type JSXNode, type JSXOutput, type QRL } from "@builder.io/qwik";

/**
* Option item for the Select component
Expand All @@ -18,6 +18,11 @@ export interface SelectOption {
*/
label: string;

/**
* Optional icon rendered before the label in custom mode
*/
icon?: JSXNode | JSXOutput;

/**
* Whether the option is disabled
*/
Expand Down
38 changes: 38 additions & 0 deletions src/components/Core/common/AdvancedSummaryBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { component$ } from "@builder.io/qwik";

export interface AdvancedSummaryBannerProps {
title: string;
description?: string;
class?: string;
}

export const AdvancedSummaryBanner = component$<AdvancedSummaryBannerProps>(
({ title, description, class: className }) => {
const classes = [
"relative overflow-hidden rounded-xl bg-gradient-to-br from-primary-600 to-primary-800 px-6 py-5 text-white md:px-7 md:py-6",
className,
]
.filter(Boolean)
.join(" ");

return (
<div class={classes}>
<div class="relative z-10 max-w-3xl">
<h2 class="text-2xl font-bold tracking-tight md:text-[2rem]">
{title}
</h2>
{description && (
<p class="mt-1 text-sm text-primary-100 md:text-base">
{description}
</p>
)}
</div>

<div class="absolute inset-0 opacity-5">
<div class="absolute -right-8 -top-8 h-28 w-28 rounded-full bg-white"></div>
<div class="absolute -bottom-8 -left-8 h-40 w-40 rounded-full bg-white"></div>
</div>
</div>
);
},
);
46 changes: 46 additions & 0 deletions src/components/Core/common/SummaryItemCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { component$, Slot } from "@builder.io/qwik";

export interface SummaryItemCardProps {
statusColorClass: string;
class?: string;
contentClass?: string;
trailingClass?: string;
}

export const SummaryItemCard = component$<SummaryItemCardProps>(
({ statusColorClass, class: className, contentClass, trailingClass }) => {
const wrapperClasses = [
"rounded-lg border bg-gradient-to-r from-white to-gray-50 p-4 dark:from-gray-800 dark:to-gray-900",
statusColorClass,
className,
]
.filter(Boolean)
.join(" ");

const detailsClasses = ["min-w-0", contentClass].filter(Boolean).join(" ");
const statusClasses = [
"flex shrink-0 flex-col items-end gap-1.5 pt-0.5",
trailingClass,
]
.filter(Boolean)
.join(" ");

return (
<div class={wrapperClasses}>
<div class="flex items-start justify-between gap-4">
<div class="flex min-w-0 items-start gap-3">
<Slot name="badge" />
<Slot name="icon" />
<div class={detailsClasses}>
<Slot />
</div>
</div>

<div class={statusClasses}>
<Slot name="trailing" />
</div>
</div>
</div>
);
},
);
2 changes: 2 additions & 0 deletions src/components/Core/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export * from "./types";
export * from "./utils";

// Components
export * from "./AdvancedSummaryBanner";
export * from "./SummaryItemCard";
export * from "./VisuallyHidden";

// ====================
Expand Down
13 changes: 13 additions & 0 deletions src/components/Core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export { CoreUtils };
import { VisuallyHidden } from "./common/VisuallyHidden";
export { VisuallyHidden };

import { AdvancedSummaryBanner } from "./common/AdvancedSummaryBanner";
import { SummaryItemCard } from "./common/SummaryItemCard";

//-------------------------------
// Typography Components
//-------------------------------
Expand Down Expand Up @@ -428,4 +431,14 @@ export {
* />
*/
Newsletter,

/**
* Compact summary banner for advanced review steps.
*/
AdvancedSummaryBanner,

/**
* Shared compact summary item shell for review cards.
*/
SummaryItemCard,
};
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ export const VPNClientAdvanced = component$<VPNClientAdvancedProps>(
type: "L2TP" as const,
enabled: true,
priority: 1, // Give it highest priority
weight: 50,
config: {
Name: "NasNetConnect",
Server: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ export const useVPNClientAdvanced = (): UseVPNClientAdvancedReturn => {
type,
enabled: true,
priority: state.vpnConfigs.length + 1,
weight: 50,
assignedLink: undefined as string | undefined,
};

Expand Down
Loading
Loading