fix(focus): prevent card rebound on swipe release by freezing exit position

This commit is contained in:
Michael committed 2026-02-13 08:41:56 +01:00
1 parent 9d41a74b36
commit b04dc992d9
2 files changed
+113 -70

No files matched your search

+110 -67
View File
@@ -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
![FlowReader Dashboard](docs/dashboard.png)
[![Go Version](https://img.shields.io/badge/Go-1.24-00ADD8?style=flat-square&logo=go)](https://golang.org/)
[![React Version](https://img.shields.io/badge/React-19-61DAFB?style=flat-square&logo=react)](https://react.dev/)
[![Docker](https://img.shields.io/badge/Docker-Ready-2496ED?style=flat-square&logo=docker)](https://www.docker.com/)
[![License](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](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.
![Mode Focus](docs/focus.png)
### 🧠 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.
![Smart Digest](docs/digest.png)
### ⚡ 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
# Start with Docker Compose
docker-compose up --build
# 1. Cloner le dépôt
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
# 2. Lancer le backend (avec reload)
make dev-backend
# 3. Lancer le frontend
make dev-frontend
```
Access the API: `http://localhost:8080`
## 🏗️ Architecture
## Deployment
### Unraid
A dedicated configuration file `docker-compose.unraid.yaml` is provided for Unraid servers. It pulls the pre-built image from GitHub Container Registry.
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
```mermaid
graph TD
Client[React Frontend] -->|API REST| Server[Go Backend]
Server -->|SQL| DB[(PostgreSQL)]
Server -->|Fetch| RSS[Flux RSS Externes]
Server -->|Analyze| AI[OpenRouter API]
```
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
# 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
Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.
+3 -3
View File
@@ -24,7 +24,7 @@ interface FocusCardStackProps {
export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite, onEmpty }: FocusCardStackProps) {
const [currentIndex, setCurrentIndex] = useState(0);
const [readingArticle, setReadingArticle] = useState<Article | null>(null);
// const [exitX, setExitX] = useState(0); // Removed per simplification
const [exitX, setExitX] = useState(0);
const isMobile = useIsMobile();
const [isProcessing, setIsProcessing] = useState(false);
@@ -84,7 +84,7 @@ export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite,
if (!active && trigger) {
// Swipe Validé
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
handleAction(isRight ? 'read' : 'keep');
@@ -208,7 +208,7 @@ export function FocusCardStack({ articles, onMarkRead, onKeep, onToggleFavorite,
}
}}
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} />
</motion.div>