Skip to content
Merged
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
156 changes: 137 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,154 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# Solid File Manager

A Google Drive-like file manager for Solid Pods, built with Next.js, React, and TypeScript.

## Overview

This application provides a user-friendly interface for managing files and folders in Solid Pods, with features similar to Google Drive:

- **File Management**: Browse, view, and organize files and folders
- **Permission Management**: Share files with others using ACP (Access Control Policies) with a Google Drive-like interface
- **Multiple Drives**: View and manage multiple storage roots/drives
- **Grid and List Views**: Toggle between grid and list views for file browsing
- **Search**: Search functionality for finding files quickly

## Features

### Current UI Features (Phase 1)

- ✅ Google Drive-like interface layout
- ✅ Left sidebar with drives list
- ✅ Main content area with file list
- ✅ Grid and list view toggle
- ✅ Breadcrumb navigation
- ✅ File item display with icons and metadata
- ✅ Permissions/sharing dialog (UI only)
- ✅ Minimal black, white, and light purple color scheme
- ✅ Semantic HTML for accessibility

### Planned Features (Phase 2 - Integration)

- [ ] Solid authentication (OIDC)
- [ ] File operations (create, read, update, delete)
- [ ] Folder navigation
- [ ] ACP permission management integration
- [ ] Storage root discovery from WebID
- [ ] File upload/download
- [ ] Real-time file updates

## Tech Stack

- **Framework**: Next.js 16
- **UI Library**: React 19
- **Styling**: Tailwind CSS 4
- **Language**: TypeScript
- **Solid SDK**: [@inrupt/solid-client-js](https://github.com/inrupt/solid-client-js) (to be integrated)

## Getting Started

First, run the development server:
### Prerequisites

- Node.js 18+
- npm, yarn, pnpm, or bun

### Installation

1. Clone the repository:
```bash
git clone <repository-url>
cd solid-file-manager
```

2. Install dependencies:
```bash
npm install
```

3. Run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
4. Open [http://localhost:3000](http://localhost:3000) in your browser.

## Development Setup

### Local CSS (Community Solid Server)

For development, you'll need to run a local Community Solid Server (CSS). The app is configured to work with a CSS instance running on `http://localhost:3001/`.

### Environment Variables

Create a `.env.local` file in the root directory:

```env
# The URI of the Solid container used by the demo Community Solid Server
# Default for local dev (Community Solid Server started by `npm run start:css`)
NEXT_PUBLIC_BASE_URI="http://localhost:3001/"

# The manifest resource file used by the app (relative to the container root)
NEXT_PUBLIC_MANIFEST_RESOURCE_URI="resource.ttl"

# Admin WebID used for booting the demo (replace with your WebID)
NEXT_PUBLIC_ADMIN_WEBID="https://id.inrupt.com/your-webid"

NEXT_PUBLIC_OIDC_ISSUER="https://login.inrupt.com"
```

## Project Structure

```
solid-file-manager/
├── app/
│ ├── components/ # React components
│ │ ├── Header.tsx # Top header with search and actions
│ │ ├── Sidebar.tsx # Left sidebar with drives list
│ │ ├── Breadcrumb.tsx # Navigation breadcrumb
│ │ ├── FileList.tsx # Main file list component
│ │ ├── FileItem.tsx # Individual file/folder item
│ │ └── PermissionsDialog.tsx # Sharing/permissions dialog
│ ├── page.tsx # Main page component
│ ├── layout.tsx # Root layout
│ └── globals.css # Global styles
├── public/ # Static assets
└── README.md
```

## Solid Protocol Integration

This application will integrate with Solid using:

- **Solid Protocol**: [https://solidproject.org/TR/protocol#resources](https://solidproject.org/TR/protocol#resources)
- **ACP (Access Control Policies)**: [https://solid.github.io/authorization-panel/acp-specification/](https://solid.github.io/authorization-panel/acp-specification/)
- **Storage Root Discovery**: Using `pim:storage` predicate from WebID
- **SDK**: [@inrupt/solid-client-js](https://github.com/inrupt/solid-client-js)

## Design Principles

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
- **Minimal Design**: Black, white, and light purple color scheme with no gradients
- **Accessibility**: Semantic HTML and ARIA labels throughout
- **Code Splitting**: Components are split into reusable, focused modules
- **Type Safety**: Full TypeScript support for type safety

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Contributing

## Learn More
This project is currently in active development. The UI phase is complete, and Solid integration is the next step.

To learn more about Next.js, take a look at the following resources:
## License

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
[Add your license here]

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## References

## Deploy on Vercel
- [Solid Project](https://solidproject.org/)
- [Solid Protocol Specification](https://solidproject.org/TR/protocol)
- [ACP Specification](https://solid.github.io/authorization-panel/acp-specification/)
- [Inrupt Solid Client JS](https://github.com/inrupt/solid-client-js)
- [Community Solid Server](https://github.com/CommunitySolidServer/CommunitySolidServer)

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
## Related Projects

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
- [nextfm](https://github.com/inrupt/nextfm)
- [Penny](https://penny.vincenttunru.com/)
- [PodPro](https://podpro.dev/)
- [solid-filemanager](https://otto-aa.github.io/solid-filemanager/)
87 changes: 87 additions & 0 deletions app/components/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";

interface BreadcrumbItem {
name: string;
path: string;
}

interface BreadcrumbProps {
items: BreadcrumbItem[];
onNavigate: (path: string) => void;
}

export default function Breadcrumb({ items, onNavigate }: BreadcrumbProps) {
// On mobile, show only the last item or truncate
const displayItems = items.length > 2 ? [items[0], ...items.slice(-2)] : items;

return (
<nav className="flex items-center gap-1 overflow-x-auto px-2 py-2 sm:gap-2 sm:px-4" aria-label="Breadcrumb">
<ol className="flex min-w-0 items-center gap-1 sm:gap-2" role="list">
{items.length > 2 && (
<>
<li className="flex items-center gap-1 sm:gap-2">
<button
type="button"
onClick={() => onNavigate(items[0].path)}
className="cursor-pointer truncate text-sm text-gray-600 hover:text-black"
>
{items[0].name}
</button>
<svg
className="h-4 w-4 flex-shrink-0 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</li>
<li className="text-sm text-gray-400">...</li>
</>
)}
{displayItems.slice(items.length > 2 ? 1 : 0).map((item, index) => {
const actualIndex = items.length > 2 ? items.length - 2 + index : index;
return (
<li key={item.path} className="flex items-center gap-1 sm:gap-2">
{actualIndex > 0 && (
<svg
className="h-4 w-4 flex-shrink-0 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
)}
<button
type="button"
onClick={() => onNavigate(item.path)}
className={`cursor-pointer truncate text-sm ${
actualIndex === items.length - 1
? "font-medium text-black"
: "text-gray-600 hover:text-black"
}`}
aria-current={actualIndex === items.length - 1 ? "page" : undefined}
>
{item.name}
</button>
</li>
);
})}
</ol>
</nav>
);
}

Loading