UNPKG

juq-llm-kit

Version:

Customizable UI components for React Native (Expo) chat applications

337 lines (329 loc) 12.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importStar(require("react")); const react_native_1 = require("react-native"); const lucide_react_1 = require("lucide-react"); const vector_icons_1 = require("@expo/vector-icons"); // Default projects const defaultProjects = [ { name: "Frontend Development" }, { name: "Backend Architecture" } ]; // Default history items const defaultHistoryItems = [ { name: "Task creation and processing", date: new Date(2024, 2, 15) }, { name: "API Integration", date: new Date(2024, 2, 14) }, { name: "Database Schema Design", date: new Date(2024, 2, 14) }, { name: "User Authentication Flow", date: new Date(2024, 2, 13) }, { name: "Performance Optimization", date: new Date(2024, 2, 13) } ]; // Custom hook for web-specific styles const useWebScrollbarStyle = (theme) => { (0, react_1.useEffect)(() => { if (react_native_1.Platform.OS === 'web' && typeof window !== 'undefined') { const thumbColor = theme === 'light' ? '#6b7280' : '#FFFFFF'; const style = document.createElement('style'); style.textContent = ` .custom-scrollbar::-webkit-scrollbar { width: 6px; background-color: transparent; } .custom-scrollbar::-webkit-scrollbar-track { background-color: transparent; } .custom-scrollbar::-webkit-scrollbar-thumb { background-color: ${thumbColor}; border-radius: 3px; } .custom-scrollbar::-webkit-scrollbar-thumb:hover { background-color: ${thumbColor}; } /* For Firefox */ .custom-scrollbar { scrollbar-width: thin; scrollbar-color: ${thumbColor} transparent; } `; document.head.appendChild(style); return () => { document.head.removeChild(style); }; } }, [theme]); }; // Add fixed positioning CSS for web platform const useFixedPositioningForCollapsed = (isCollapsed) => { (0, react_1.useEffect)(() => { if (react_native_1.Platform.OS === 'web' && typeof window !== 'undefined') { const style = document.createElement('style'); if (isCollapsed) { style.textContent = ` .collapsed-sidebar { position: fixed !important; top: 0 !important; left: 0 !important; z-index: 9999 !important; margin: 0 !important; padding: 0 !important; } `; document.head.appendChild(style); } return () => { if (document.head.contains(style)) { document.head.removeChild(style); } }; } }, [isCollapsed]); }; const Sidebar = ({ onCollapsedChange, initialCollapsed = false, projects = defaultProjects, historyItems = defaultHistoryItems, subscriptionTitle = "View plans", subscriptionText = "Unlimited access, team features,...", containerStyle, theme = 'dark' }) => { const [isCollapsed, setIsCollapsed] = (0, react_1.useState)(initialCollapsed); const animatedWidth = new react_native_1.Animated.Value(initialCollapsed ? 40 : 256); const colors = getThemeColors(theme); useWebScrollbarStyle(theme); useFixedPositioningForCollapsed(isCollapsed); const toggleCollapse = () => { const newCollapsedState = !isCollapsed; setIsCollapsed(newCollapsedState); if (onCollapsedChange) { onCollapsedChange(newCollapsedState); } react_native_1.Animated.timing(animatedWidth, { toValue: newCollapsedState ? 40 : 256, duration: 300, useNativeDriver: false, }).start(); }; return (<react_native_1.Animated.View style={[ styles.container, { width: animatedWidth, backgroundColor: colors.containerBg, }, isCollapsed && styles.collapsedContainer, containerStyle ]}> {/* Top icons */} <react_native_1.View style={[ styles.topBar, { borderBottomColor: colors.borderColor }, isCollapsed && [styles.collapsedTopBar, { backgroundColor: colors.containerBg }] ]}> <react_native_1.Pressable style={styles.iconButton} onPress={toggleCollapse}> <react_native_1.View style={[styles.checkboxIcon, { borderColor: colors.iconColor }]}></react_native_1.View> </react_native_1.Pressable> {!isCollapsed ? (<react_native_1.View style={styles.iconGroup}> <react_native_1.Pressable style={styles.iconButton}> <lucide_react_1.Search size={20} color={colors.iconColor}/> </react_native_1.Pressable> <react_native_1.Pressable style={styles.iconButton}> <lucide_react_1.Plus size={20} color={colors.iconColor}/> </react_native_1.Pressable> </react_native_1.View>) : (<react_native_1.Pressable style={[styles.iconButton, styles.collapsedPlusButton]}> <lucide_react_1.Plus size={20} color={colors.iconColor}/> </react_native_1.Pressable>)} </react_native_1.View> {/* Main content - only show when not collapsed */} {!isCollapsed && (<> <react_native_1.ScrollView style={styles.scrollContainer} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false}> {/* Projects section */} <react_native_1.View style={styles.section}> <react_native_1.Text style={[styles.sectionTitle, { color: colors.secondaryText }]}>Projects</react_native_1.Text> {projects.map((project, index) => (<ProjectItem key={`project-${index}`} name={project.name} onSelect={project.onSelect} colors={colors}/>))} </react_native_1.View> {/* History section */} <react_native_1.View style={styles.sectionWithMargin}> <react_native_1.Text style={[styles.sectionTitle, { color: colors.secondaryText }]}>History</react_native_1.Text> {historyItems.map((item, index) => (<HistoryItem key={`history-${index}`} name={item.name} date={item.date} onSelect={item.onSelect} colors={colors}/>))} </react_native_1.View> </react_native_1.ScrollView> {/* Bottom subscription link */} <react_native_1.View style={[styles.bottomBar, { borderTopColor: colors.borderColor }]}> <react_native_1.View style={[styles.subscriptionCard, { backgroundColor: colors.cardBg }]}> <react_native_1.View style={styles.subscriptionContent}> <react_native_1.View> <react_native_1.Text style={[styles.subscriptionTitle, { color: colors.textColor }]}>{subscriptionTitle}</react_native_1.Text> <react_native_1.Text style={[styles.subscriptionText, { color: colors.secondaryText }]}>{subscriptionText}</react_native_1.Text> </react_native_1.View> <lucide_react_1.Settings size={18} color={colors.secondaryText}/> </react_native_1.View> </react_native_1.View> </react_native_1.View> </>)} </react_native_1.Animated.View>); }; // Project item component with folder icon const ProjectItem = ({ name, onSelect, colors }) => { return (<react_native_1.Pressable style={styles.listItem} onPress={onSelect}> <vector_icons_1.Ionicons name="folder-outline" size={20} color={colors.folderIconColor}/> <react_native_1.Text style={[styles.listItemText, { color: colors.textColor }]}>{name}</react_native_1.Text> </react_native_1.Pressable>); }; // History item component with date const HistoryItem = ({ name, date, onSelect, colors }) => { const formattedDate = date.toLocaleDateString('en-US', { month: 'numeric', day: 'numeric', year: '2-digit' }); return (<react_native_1.Pressable style={styles.listItem} onPress={onSelect}> <react_native_1.Text style={[styles.dateText, { color: colors.secondaryText }]}>{formattedDate}</react_native_1.Text> <react_native_1.Text style={[styles.listItemText, { color: colors.textColor }]}>{name}</react_native_1.Text> </react_native_1.Pressable>); }; // Theme helper function function getThemeColors(theme) { if (theme === 'light') { return { containerBg: '#f9fafb', cardBg: '#e5e7eb', textColor: '#111827', secondaryText: '#6b7280', borderColor: '#e5e7eb', iconColor: '#6b7280', folderIconColor: '#6b7280' }; } return { containerBg: '#111827', cardBg: '#1f2937', textColor: '#f9fafb', secondaryText: '#9ca3af', borderColor: '#1f2937', iconColor: '#d1d5db', folderIconColor: '#4b5563' }; } const styles = react_native_1.StyleSheet.create({ container: { height: '100%', flexDirection: 'column', }, collapsedContainer: Object.assign({ position: 'absolute', top: 0, left: 0, height: 'auto', zIndex: 10000, backgroundColor: 'transparent', padding: 0, margin: 0 }, (react_native_1.Platform.OS === 'web' ? { position: 'fixed', } : {})), topBar: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', padding: 12, borderBottomWidth: 1, }, collapsedTopBar: { flexDirection: 'column', alignItems: 'flex-start', justifyContent: 'flex-start', borderBottomWidth: 0, borderRadius: 4, padding: 0, margin: 0, }, iconButton: { width: 32, height: 32, alignItems: 'center', justifyContent: 'center', borderRadius: 4, }, collapsedPlusButton: { marginTop: 8, }, checkboxIcon: { width: 20, height: 20, borderWidth: 2, borderRadius: 4, }, iconGroup: { flexDirection: 'row', gap: 12, }, scrollContainer: { flex: 1, }, section: { paddingVertical: 8, }, sectionWithMargin: { marginTop: 16, }, sectionTitle: { paddingHorizontal: 12, paddingVertical: 8, fontSize: 12, fontWeight: '500', }, dateText: { fontSize: 11, width: 45, marginRight: 8, }, listItem: { paddingHorizontal: 12, paddingVertical: 8, flexDirection: 'row', alignItems: 'center', }, listItemText: { marginLeft: 12, fontSize: 14, }, bottomBar: { padding: 12, borderTopWidth: 1, }, subscriptionCard: { borderRadius: 8, padding: 12, }, subscriptionContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, subscriptionTitle: { fontSize: 14, fontWeight: '500', }, subscriptionText: { fontSize: 12, }, collapsedIconGroup: { gap: 0, }, }); exports.default = Sidebar;