mirror of
https://github.com/R0m1k3/FlowReader.git
synced 2026-10-21 14:18:06 +02:00
fix(focus): prevent card rebound on swipe release by freezing exit position
This commit is contained in:
1 parent
9d41a74b36
commit
b04dc992d9
2 files changed
+113
-70
No files matched your search
@@ -1,81 +1,124 @@
|
|||||||
# FlowReader
|
# 🌿 FlowReader
|
||||||
|
|
||||||
A minimalist, self-hosted RSS/Atom reader focused on simplicity and resource efficiency.
|
> **Le calme dans le chaos de l'information.**
|
||||||
|
> Un agrégateur RSS minimaliste, intelligent et économe, conçu pour ceux qui veulent reprendre le contrôle de leur veille.
|
||||||
|
|
||||||
## Quick Start
|

|
||||||
|
|
||||||
|
[](https://golang.org/)
|
||||||
|
[](https://react.dev/)
|
||||||
|
[](https://www.docker.com/)
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
|
## ✨ Pourquoi FlowReader ?
|
||||||
|
|
||||||
|
FlowReader n'est pas juste un autre lecteur RSS. C'est une expérience de lecture repensée pour l'efficacité et le plaisir. Fini le scroll infini anxiogène, place à la concentration.
|
||||||
|
|
||||||
|
### 🧘 Mode Focus
|
||||||
|
|
||||||
|
Une interface immersive inspirée des applications de rencontre pour trier vos flux à la vitesse de la pensée.
|
||||||
|
|
||||||
|
- **Swipe à droite :** Article lu / archivé.
|
||||||
|
- **Swipe à gauche :** Article gardé pour plus tard.
|
||||||
|
- **Double-clic :** Lecture immédiate.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 🧠 Smart Digest (IA)
|
||||||
|
|
||||||
|
Ne perdez plus de temps sur les articles "clickbait".
|
||||||
|
|
||||||
|
- FlowReader utilise l'IA (via OpenRouter) pour lire le contenu complet à votre place.
|
||||||
|
- Il génère un **résumé concis** directement accessible depuis votre liste de lecture.
|
||||||
|
- Identifiez en un coup d'œil si un article mérite votre temps.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### ⚡ Performance & Sobriété
|
||||||
|
|
||||||
|
Conçu pour l'auto-hébergement respectueux des ressources.
|
||||||
|
|
||||||
|
- **Backend en Go :** Ultra-rapide et compilé.
|
||||||
|
- **Frontend React 19 :** Fluide et moderne.
|
||||||
|
- **< 150MB RAM :** Tourne parfaitement sur un Raspberry Pi ou un NAS modeste.
|
||||||
|
|
||||||
|
## 🚀 Fonctionnalités Clés
|
||||||
|
|
||||||
|
- **PWA & Offline :** Installez-le sur mobile comme une app native. Supporte la lecture hors-ligne.
|
||||||
|
- **Recherche Full-Text :** Retrouvez n'importe quel article instantanément grâce à l'indexation PostgreSQL.
|
||||||
|
- **Design Organique :** Thèmes "Organic Warmth" et "Deep Forest" (Mode Sombre) pour le confort des yeux.
|
||||||
|
- **Lecture Confortable :** Mode lecteur distration-free intégré.
|
||||||
|
- **Agents IA (BMad) :** Architecture conçue pour être maintenue et étendue par des agents IA.
|
||||||
|
|
||||||
|
## 📦 Installation
|
||||||
|
|
||||||
|
### Option 1 : Docker Compose (Recommandé)
|
||||||
|
|
||||||
|
Le moyen le plus simple de démarrer.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start with Docker Compose
|
# 1. Cloner le dépôt
|
||||||
docker-compose up --build
|
git clone https://github.com/R0m1k3/FlowReader.git
|
||||||
|
cd FlowReader
|
||||||
|
|
||||||
# Or use Make
|
# 2. Lancer la stack
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Accédez à `http://localhost:8080`.
|
||||||
|
|
||||||
|
### Option 2 : Unraid
|
||||||
|
|
||||||
|
Un template dédié est fourni pour les utilisateurs d'Unraid.
|
||||||
|
|
||||||
|
1. Copiez le fichier `docker-compose.unraid.yaml` sur votre serveur.
|
||||||
|
2. Lancez le conteneur :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose -f docker-compose.unraid.yaml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
*Note : Les données sont persistées dans `/mnt/user/appdata/flowreader`.*
|
||||||
|
|
||||||
|
### Configuration (Variables d'Environnement)
|
||||||
|
|
||||||
|
| Variable | Description | Défaut |
|
||||||
|
|----------|-------------|--------|
|
||||||
|
| `PORT` | Port du serveur | `8080` |
|
||||||
|
| `DATABASE_URL` | Connexion PostgreSQL | `postgres://...` |
|
||||||
|
| `OPENROUTER_API_KEY` | Clé pour les résumés IA | *(Optionnel)* |
|
||||||
|
|
||||||
|
## 🛠️ Développement
|
||||||
|
|
||||||
|
Envie de mettre les mains dans le code ?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Pré-requis : Go 1.22+, Node 20+, Docker
|
||||||
|
|
||||||
|
# 1. Lancer les services (DB)
|
||||||
make docker-up
|
make docker-up
|
||||||
|
|
||||||
|
# 2. Lancer le backend (avec reload)
|
||||||
|
make dev-backend
|
||||||
|
|
||||||
|
# 3. Lancer le frontend
|
||||||
|
make dev-frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
Access the API: `http://localhost:8080`
|
## 🏗️ Architecture
|
||||||
|
|
||||||
## Deployment
|
```mermaid
|
||||||
|
graph TD
|
||||||
### Unraid
|
Client[React Frontend] -->|API REST| Server[Go Backend]
|
||||||
|
Server -->|SQL| DB[(PostgreSQL)]
|
||||||
A dedicated configuration file `docker-compose.unraid.yaml` is provided for Unraid servers. It pulls the pre-built image from GitHub Container Registry.
|
Server -->|Fetch| RSS[Flux RSS Externes]
|
||||||
|
Server -->|Analyze| AI[OpenRouter API]
|
||||||
1. Copy **only** `docker-compose.unraid.yaml` to your Unraid server (e.g. into `/mnt/user/appdata/flowreader`).
|
|
||||||
2. Run with Docker Compose:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose -f docker-compose.unraid.yaml up -d
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: The configuration uses `/mnt/user/appdata/flowreader/postgres_data` for database persistence.
|
## 🤝 Contribuer
|
||||||
|
|
||||||
|
Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une Issue ou une Pull Request.
|
||||||
|
|
||||||
## Development
|
## 📄 Licence
|
||||||
|
|
||||||
```bash
|
Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
||||||
# Run locally (requires Go 1.22+)
|
|
||||||
make dev
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
make test
|
|
||||||
|
|
||||||
# Lint code
|
|
||||||
make lint
|
|
||||||
```
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
flowreader/
|
|
||||||
├── cmd/
|
|
||||||
│ └── server/ # Application entry point
|
|
||||||
├── internal/
|
|
||||||
│ ├── domain/ # Business logic (entities, services)
|
|
||||||
│ ├── handler/ # HTTP handlers
|
|
||||||
│ └── repository/ # Database access
|
|
||||||
├── pkg/ # Shared utilities
|
|
||||||
└── migrations/ # SQL migrations
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
|
|
||||||
- **Backend**: Go 1.24+ (Chi, pgx, gofeed)
|
|
||||||
- **Database**: PostgreSQL 16
|
|
||||||
- **Frontend**: React 19 + Vite + Tailwind 4 ("Organic Warmth" Theme)
|
|
||||||
- **Auth**: Session-based (HTTP-only cookies)
|
|
||||||
- **Feeds**: RSS/Atom with Favicon extraction
|
|
||||||
|
|
||||||
## Current Status (MVP)
|
|
||||||
|
|
||||||
- [x] User Management (Register/Login)
|
|
||||||
- [x] Feed Management (Add/Import/Refresh)
|
|
||||||
- [x] Reader Experience (Grid/List View, infinite scroll)
|
|
||||||
- [x] Theme: Organic Warmth (Carbon/Gold/Paper)
|
|
||||||
|
|
||||||
## Memory Target
|
|
||||||
|
|
||||||
Total container footprint: **< 150MB RAM**
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
@@ -24,7 +24,7 @@ interface FocusCardStackProps {
|
|||||||
export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite, onEmpty }: FocusCardStackProps) {
|
export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite, onEmpty }: FocusCardStackProps) {
|
||||||
const [currentIndex, setCurrentIndex] = useState(0);
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
const [readingArticle, setReadingArticle] = useState<Article | null>(null);
|
const [readingArticle, setReadingArticle] = useState<Article | null>(null);
|
||||||
// const [exitX, setExitX] = useState(0); // Removed per simplification
|
const [exitX, setExitX] = useState(0);
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
@@ -84,7 +84,7 @@ export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite,
|
|||||||
if (!active && trigger) {
|
if (!active && trigger) {
|
||||||
// Swipe Validé
|
// Swipe Validé
|
||||||
const isRight = mx > 0;
|
const isRight = mx > 0;
|
||||||
// setExitX(isRight ? 500 : -500); // Trigger exit animation - Removed lateral movement per user request
|
setExitX(x.get()); // Capture current position to freeze exit animation
|
||||||
|
|
||||||
// Trigger action via handler
|
// Trigger action via handler
|
||||||
handleAction(isRight ? 'read' : 'keep');
|
handleAction(isRight ? 'read' : 'keep');
|
||||||
@@ -208,7 +208,7 @@ export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite,
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
animate={{ scale: 1 - i * 0.05, y: i * 20 }}
|
animate={{ scale: 1 - i * 0.05, y: i * 20 }}
|
||||||
exit={{ opacity: 0, scale: 0.9, transition: { duration: 0.2 } }}
|
exit={{ x: exitX, opacity: 0, scale: 0.9, transition: { duration: 0.2 } }}
|
||||||
>
|
>
|
||||||
<FocusCard article={article} isTop={isTop} />
|
<FocusCard article={article} isTop={isTop} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
Reference in new issue
Block a user