feat: github fix and ui improvements (#1685)
* feat: Add reusable UI components and fix GitHub repository display * style: Fix linting issues in UI components * fix: Add close icon to GitHub Connection Required dialog * fix: Add CloseButton component to fix white background issue in dialog close icons * Fix close button styling in dialog components to address ghost white issue in dark mode * fix: update icon color to tertiary for consistency The icon color was changed from `text-bolt-elements-icon-info` to `text-bolt-elements-icon-tertiary` * fix: improve repository selection dialog tab styling for dark mode - Update tab menu styling to prevent white background in dark mode - Use explicit color values for better dark/light mode compatibility - Improve hover and active states for better visual hierarchy - Remove unused Tabs imports --------- Co-authored-by: KevIsDev <zennerd404@gmail.com>
This commit is contained in:
101
app/components/ui/Breadcrumbs.tsx
Normal file
101
app/components/ui/Breadcrumbs.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import React from 'react';
|
||||
import { classNames } from '~/utils/classNames';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface BreadcrumbItem {
|
||||
label: string;
|
||||
href?: string;
|
||||
icon?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
interface BreadcrumbsProps {
|
||||
items: BreadcrumbItem[];
|
||||
className?: string;
|
||||
separator?: string;
|
||||
maxItems?: number;
|
||||
renderItem?: (item: BreadcrumbItem, index: number, isLast: boolean) => React.ReactNode;
|
||||
}
|
||||
|
||||
export function Breadcrumbs({
|
||||
items,
|
||||
className,
|
||||
separator = 'i-ph:caret-right',
|
||||
maxItems = 0,
|
||||
renderItem,
|
||||
}: BreadcrumbsProps) {
|
||||
const displayItems =
|
||||
maxItems > 0 && items.length > maxItems
|
||||
? [
|
||||
...items.slice(0, 1),
|
||||
{ label: '...', onClick: undefined, href: undefined },
|
||||
...items.slice(-Math.max(1, maxItems - 2)),
|
||||
]
|
||||
: items;
|
||||
|
||||
const defaultRenderItem = (item: BreadcrumbItem, index: number, isLast: boolean) => {
|
||||
const content = (
|
||||
<div className="flex items-center gap-1.5">
|
||||
{item.icon && <span className={classNames(item.icon, 'w-3.5 h-3.5')} />}
|
||||
<span
|
||||
className={classNames(
|
||||
isLast
|
||||
? 'font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark'
|
||||
: 'text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:text-bolt-elements-textPrimary dark:hover:text-bolt-elements-textPrimary-dark',
|
||||
item.onClick || item.href ? 'cursor-pointer' : '',
|
||||
)}
|
||||
>
|
||||
{item.label}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (item.href && !isLast) {
|
||||
return (
|
||||
<motion.a href={item.href} className="hover:underline" whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
{content}
|
||||
</motion.a>
|
||||
);
|
||||
}
|
||||
|
||||
if (item.onClick && !isLast) {
|
||||
return (
|
||||
<motion.button
|
||||
type="button"
|
||||
onClick={item.onClick}
|
||||
className="hover:underline"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
{content}
|
||||
</motion.button>
|
||||
);
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
return (
|
||||
<nav className={classNames('flex items-center', className)} aria-label="Breadcrumbs">
|
||||
<ol className="flex items-center gap-1.5">
|
||||
{displayItems.map((item, index) => {
|
||||
const isLast = index === displayItems.length - 1;
|
||||
|
||||
return (
|
||||
<li key={index} className="flex items-center">
|
||||
{renderItem ? renderItem(item, index, isLast) : defaultRenderItem(item, index, isLast)}
|
||||
{!isLast && (
|
||||
<span
|
||||
className={classNames(
|
||||
separator,
|
||||
'w-3 h-3 mx-1 text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ol>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user