diff --git a/.gitignore b/.gitignore index c18a7a7..c811e76 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ yarn-error.log* next-env.d.ts # local notes -.notes.md +# notes.md diff --git a/.notes.md b/.notes.md new file mode 100644 index 0000000..31906e9 --- /dev/null +++ b/.notes.md @@ -0,0 +1,370 @@ +# Code Style & Patterns + +Personal notes on code style for this project. + +--- + +## Comments + +### ✅ Do +```typescript +// Debounce rapid keypresses - nobody needs 60fps navigation +// AUR gets special amber styling because it's ✨special✨ +// Skip if already installed - no point reinstalling +// The vim keybindings that make us feel like hackers +``` + +### ❌ Don't +```typescript +/** + * Debounces rapid keypresses to prevent performance issues + * @param delay - The delay in milliseconds + * @returns void + */ + +// ───────────────────────────────────────────────────────────────── +// Section Header +// ───────────────────────────────────────────────────────────────── +``` + +### Rules +1. Single-line `//` comments, not JSDoc blocks +2. No decorative section dividers +3. Explain "why", not "what" +4. Occasional humor when it fits +5. Short comments - if you need a paragraph, simplify the code + +--- + +## Component Structure + +### Size Limits +- **Functions**: ~30 lines +- **Components**: ~150 lines +- **Files**: ~300 lines + +### Organization +- Logic in hooks, rendering in components +- One component per file +- Barrel files get one-liner comments + +```typescript +// Header area components +export { HowItWorks } from './HowItWorks'; +``` + +### File Naming +- `PascalCase.tsx` for components +- `camelCase.ts` for hooks/utilities +- `kebab-case` for directories + +--- + +## TypeScript + +```typescript +// Let inference work +const [selected, setSelected] = useState>(new Set()); + +// Destructure props +function AppItem({ app, isSelected }: AppItemProps) { ... } + +// Union types over enums +type DistroId = 'ubuntu' | 'debian' | 'arch'; + +// Avoid any +const data: any = fetchData(); // ❌ +``` + +--- + +## React Patterns + +### Memoization +```typescript +// Memo for expensive children with frequent parent re-renders +const AppItem = memo(function AppItem({ ... }) { ... }); + +// useMemo for expensive calculations +const filtered = useMemo(() => apps.filter(...), [apps, query]); + +// useCallback for handlers to memoized children +const handleToggle = useCallback((id) => { ... }, [deps]); +``` + +### State +```typescript +// Derive state, don't store computed values +const count = selected.size; // ✅ derived +const [count, setCount] = ... // ❌ redundant state + +// Keep state minimal and colocated +``` + +### Early Returns +```typescript +if (!apps.length) return null; +if (isLoading) return ; +// Then the happy path +``` + +--- + +## Accessibility + +### Keyboard Navigation +```typescript +// All interactive elements need keyboard support +onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') handleClick(); +}} + +// Focus management after modals/overlays +useEffect(() => { inputRef.current?.focus(); }, [isOpen]); +``` + +### Semantic HTML +```typescript +// Use correct elements + diff --git a/src/components/command/CommandFooter.tsx b/src/components/command/CommandFooter.tsx index 3aa002b..14bab11 100644 --- a/src/components/command/CommandFooter.tsx +++ b/src/components/command/CommandFooter.tsx @@ -203,11 +203,11 @@ export function CommandFooter({ {/* Command Bar */}
- {/* Preview button */} + {/* Preview button (hidden on mobile) */}
- {/* Clear button */} + {/* Clear button (hidden on mobile) */} - {/* Download button */} + {/* Download button (hidden on mobile) */} - {/* Copy button */} + {/* Copy button (hidden on mobile) */} {mounted && typeof document !== 'undefined' && createPortal(dropdown, document.body)} diff --git a/src/components/header/HowItWorks.tsx b/src/components/header/HowItWorks.tsx index 2061a8f..bb0aabc 100644 --- a/src/components/header/HowItWorks.tsx +++ b/src/components/header/HowItWorks.tsx @@ -200,10 +200,12 @@ export function HowItWorks() { {isOpen && mounted && typeof document !== 'undefined' && createPortal(modal, document.body)}