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
4 changes: 3 additions & 1 deletion app/(main)/o/[slug]/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import PlusIcon from "@/public/icons/plus.svg";

import { Banner, BannerLink } from "./banner";
import ConversationHistory from "./conversation-history";
import { LegalAnalysisToggle } from "@/components/legal-analysis/legal-analysis-toggle";

const errorSchema = z.object({
error: z.string(),
Expand Down Expand Up @@ -121,7 +122,7 @@ export default function Header({

return (
<header className="w-full shrink-0 flex justify-between p-4 items-center">
<div className="flex">
<div className="flex items-center gap-2">
<Popover>
<PopoverTrigger asChild>
<Image src={HamburgerIcon} alt="Expand chats" className="mr-2.5 cursor-pointer" onClick={onNavClick} />
Expand All @@ -133,6 +134,7 @@ export default function Header({
<Link href={getTenantPath(tenant.slug)}>
<Image src={NewChatIcon} alt="New chat" />
</Link>
<LegalAnalysisToggle />
</div>
{billingEnabled && (
<>
Expand Down
208 changes: 208 additions & 0 deletions components/legal-analysis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Legal Analysis Panel ("Legal Thoughts")

A collapsible side panel that displays editorial legal analysis content alongside the chat interface.

## Features

- **Practice Area Organization**: Content is organized by 38 legal practice areas
- **Expandable Cards**: Click to expand and read full analysis excerpts
- **Author Information**: Displays author name, title, and firm
- **Read Time**: Shows estimated reading time for each article
- **Featured Content**: Highlights featured analyses
- **Tag Filtering**: Content can be filtered by tags
- **Responsive Design**: Works as slide-over panel on mobile, inline sidebar on desktop

## File Structure

```
components/legal-analysis/
├── index.ts # Public exports
├── legal-analysis-panel.tsx # Main panel component (client)
├── legal-analysis-content.tsx # Server component for data fetching
├── legal-analysis-toggle.tsx # Toggle button and slide-out panel
├── README.md # This file
└── ...

lib/legal-analysis/
├── types.ts # TypeScript types and schemas
├── data.ts # Sample content (replace with CMS)
└── ...
```

## Data Source

Currently uses static JSON data in `lib/legal-analysis/data.ts`. To integrate with a CMS:

### Payload CMS

```typescript
// lib/legal-analysis/payload.ts
import { getPayloadClient } from '@/lib/payload'

export async function getLegalAnalyses(filters) {
const payload = await getPayloadClient()
const results = await payload.find({
collection: 'legal-analyses',
where: {
...(filters.practiceArea && {
practiceArea: { equals: filters.practiceArea }
}),
...(filters.featured && {
featured: { equals: true }
})
}
})
return results.docs
}
```

### Airtable

```typescript
// lib/legal-analysis/airtable.ts
import Airtable from 'airtable'

const base = new Airtable({ apiKey: process.env.AIRTABLE_API_KEY })
.base(process.env.AIRTABLE_BASE_ID)

export async function getLegalAnalyses(filters) {
const records = await base('LegalAnalyses').select({
filterByFormula: buildFilterFormula(filters)
}).all()

return records.map(record => mapToLegalAnalysis(record))
}
```

## Usage

### In Header (Global Toggle)

```tsx
import { LegalAnalysisToggle } from '@/components/legal-analysis'

export function Header() {
return (
<header>
<LegalAnalysisToggle />
</header>
)
}
```

### With Practice Area Filter

```tsx
import { LegalAnalysisToggle } from '@/components/legal-analysis'
import { PracticeArea } from '@/lib/legal-analysis/types'

export function ClassPage({ practiceArea }: { practiceArea: PracticeArea }) {
return (
<aside>
<LegalAnalysisToggle practiceArea={practiceArea} />
</aside>
)
}
```

### Inline Sidebar (Desktop)

```tsx
import { LegalAnalysisSidebar } from '@/components/legal-analysis'

export function ConversationLayout() {
return (
<div className="flex">
<main>...</main>
<LegalAnalysisSidebar />
</div>
)
}
```

## Adding Content

### Via Data File (Quick Start)

Edit `lib/legal-analysis/data.ts`:

```typescript
export const legalAnalyses: LegalAnalysis[] = [
{
id: "la-006",
title: "Your Article Title",
excerpt: "Brief summary...",
content: `Full markdown content...`,
practiceArea: "employment-law",
author: {
name: "Author Name",
title: "Partner",
firm: "Law Firm",
},
publishedAt: "2025-03-20T10:00:00Z",
readTimeMinutes: 8,
featured: true,
tags: ["tag1", "tag2"],
},
// ... more articles
]
```

### Practice Areas

Available practice area keys:

```typescript
"administrative-law"
"alternative-dispute-resolution"
"antitrust"
"appellate-practice"
"bankruptcy"
"business-law"
"civil-rights"
"construction-law"
"consumer-protection"
"corporate-law"
"criminal-law"
"employment-law"
"environmental-law"
"estate-planning"
"family-law"
"healthcare-law"
"immigration-law"
"insurance-law"
"intellectual-property"
"international-law"
"labor-law"
"litigation"
"municipal-law"
"personal-injury"
"product-liability"
"professional-responsibility"
"real-estate"
"securities-law"
"tax-law"
"technology-law"
"trusts-estates"
"workers-compensation"
```

## Styling

Uses existing Base Chat design system:
- Radix UI components
- Tailwind CSS
- Lucide icons

To customize colors or spacing, modify the component classes or update `tailwind.config.ts`.

## Future Enhancements

- [ ] Full article page with slug-based routing
- [ ] Search functionality across all analyses
- [ ] Related content suggestions
- [ ] Bookmark/favorite functionality
- [ ] Print/export to PDF
- [ ] Social sharing
- [ ] Comment/annotation system
- [ ] CLE credit tracking integration
3 changes: 3 additions & 0 deletions components/legal-analysis/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { LegalAnalysisPanel } from "./legal-analysis-panel";
export { LegalAnalysisContent } from "./legal-analysis-content";
export { LegalAnalysisToggle, LegalAnalysisSidebar } from "./legal-analysis-toggle";
18 changes: 18 additions & 0 deletions components/legal-analysis/legal-analysis-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { LegalAnalysisPanel } from "./legal-analysis-panel";
import { getLegalAnalyses } from "@/lib/legal-analysis/data";
import { LegalAnalysisFilters } from "@/lib/legal-analysis/types";

interface LegalAnalysisContentProps {
filters?: LegalAnalysisFilters;
className?: string;
}

/**
* Server component that fetches legal analysis data
* and renders the panel
*/
export async function LegalAnalysisContent({ filters, className }: LegalAnalysisContentProps) {
const analyses = getLegalAnalyses(filters);

return <LegalAnalysisPanel analyses={analyses} className={className} />;
}
Loading