correction responsive mobile
This commit is contained in:
@@ -2,6 +2,7 @@ import type { NextConfig } from "next";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
|
allowedDevOrigins: ['10.0.2.2'],
|
||||||
|
|
||||||
// 1. On ignore les erreurs de type et ESLint pour que le build
|
// 1. On ignore les erreurs de type et ESLint pour que le build
|
||||||
// de production ne plante pas à cause des imports Prisma
|
// de production ne plante pas à cause des imports Prisma
|
||||||
|
|||||||
@@ -101,24 +101,24 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className="bg-gray-50 min-h-screen py-12 relative">
|
<article className="bg-white sm:bg-gray-50 min-h-screen py-0 sm:py-12 relative">
|
||||||
{/* Injection du style de force pour le texte */}
|
{/* Injection du style de force pour le texte */}
|
||||||
<style dangerouslySetInnerHTML={{ __html: noBreakStyle }} />
|
<style dangerouslySetInnerHTML={{ __html: noBreakStyle }} />
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 flex gap-4 lg:gap-8 justify-center relative">
|
<div className="max-w-5xl mx-auto px-0 sm:px-6 lg:px-8 flex gap-4 lg:gap-8 justify-center relative">
|
||||||
{/* Conteneur principal de l'article */}
|
{/* Conteneur principal de l'article */}
|
||||||
<div className="w-[calc(100%-3rem)] sm:w-full max-w-3xl relative">
|
<div className="w-full max-w-3xl relative">
|
||||||
|
|
||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<div className="mb-8">
|
<div className="mb-4 sm:mb-8 px-4 sm:px-0 pt-4 sm:pt-0">
|
||||||
<Link href="/actualites" className="inline-flex items-center text-gray-500 hover:text-brand-600 text-sm font-medium transition-colors">
|
<Link href="/actualites" className="inline-flex items-center text-gray-500 hover:text-brand-600 text-sm font-medium transition-colors">
|
||||||
<ArrowLeft className="w-4 h-4 mr-1" /> Retour aux articles
|
<ArrowLeft className="w-4 h-4 mr-1" /> Retour aux articles
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white rounded-xl shadow-sm p-6 md:p-10 border border-gray-100 relative z-10">
|
<div className="bg-white sm:rounded-xl shadow-none sm:shadow-sm sm:p-10 border-none sm:border sm:border-gray-100 relative z-10">
|
||||||
{/* Image d'en-tête */}
|
{/* Image d'en-tête en pleine largeur sur mobile */}
|
||||||
<div className="w-full h-64 md:h-80 relative mb-8 rounded-lg overflow-hidden shadow-md">
|
<div className="w-full h-64 md:h-80 relative mb-6 sm:mb-8 sm:rounded-lg overflow-hidden shadow-none sm:shadow-md">
|
||||||
<LightboxImage
|
<LightboxImage
|
||||||
src={post.imageUrl}
|
src={post.imageUrl}
|
||||||
alt={post.title}
|
alt={post.title}
|
||||||
@@ -128,7 +128,7 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Header de l'article */}
|
{/* Header de l'article */}
|
||||||
<header className="mb-8 border-b border-gray-100 pb-8">
|
<header className="mb-6 sm:mb-8 border-b border-gray-100 pb-6 sm:pb-8 px-4 sm:px-0">
|
||||||
<div className="flex flex-wrap items-center gap-4 text-sm text-gray-500 mb-4">
|
<div className="flex flex-wrap items-center gap-4 text-sm text-gray-500 mb-4">
|
||||||
<span className="flex items-center">
|
<span className="flex items-center">
|
||||||
<User className="w-4 h-4 mr-1 text-brand-500" />
|
<User className="w-4 h-4 mr-1 text-brand-500" />
|
||||||
@@ -156,7 +156,7 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Contenu de l'article */}
|
{/* Contenu de l'article */}
|
||||||
<div className="prose prose-lg prose-orange max-w-none text-gray-600">
|
<div className="prose sm:prose-lg prose-orange max-w-none text-gray-600 px-4 sm:px-0">
|
||||||
{/* Résumé / Lead */}
|
{/* Résumé / Lead */}
|
||||||
<p className="lead text-xl text-gray-500 font-serif italic mb-6 border-b border-gray-100 pb-6">
|
<p className="lead text-xl text-gray-500 font-serif italic mb-6 border-b border-gray-100 pb-6">
|
||||||
{post.excerpt}
|
{post.excerpt}
|
||||||
@@ -172,7 +172,7 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
|
|
||||||
{/* Sources Section */}
|
{/* Sources Section */}
|
||||||
{Array.isArray(post.sources) && post.sources.length > 0 && (
|
{Array.isArray(post.sources) && post.sources.length > 0 && (
|
||||||
<div className="mt-12 p-6 bg-gray-50 rounded-xl border border-gray-100">
|
<div className="mt-8 sm:mt-12 p-4 sm:p-6 bg-gray-50 sm:rounded-xl border-t sm:border border-gray-100 mx-4 sm:mx-0">
|
||||||
<h3 className="text-sm font-bold uppercase tracking-wider text-gray-400 mb-4 flex items-center gap-2">
|
<h3 className="text-sm font-bold uppercase tracking-wider text-gray-400 mb-4 flex items-center gap-2">
|
||||||
<Share2 className="w-4 h-4 text-brand-500" />
|
<Share2 className="w-4 h-4 text-brand-500" />
|
||||||
Sources & Références
|
Sources & Références
|
||||||
@@ -196,8 +196,14 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Partage sur mobile */}
|
||||||
|
<div className="mt-8 pt-6 border-t border-gray-100 block sm:hidden px-4">
|
||||||
|
<p className="text-xs font-bold uppercase tracking-wider text-gray-400 mb-4 text-center">Partager cet article</p>
|
||||||
|
<BlogShareButtons title={post.title} layout="horizontal" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Partage / Footer */}
|
{/* Partage / Footer */}
|
||||||
<div className="mt-12 pt-8 border-t border-gray-100 flex flex-col sm:flex-row justify-between items-center gap-4">
|
<div className="mt-8 sm:mt-12 pt-6 sm:pt-8 border-t border-gray-100 flex flex-col sm:flex-row justify-between items-center gap-4 px-4 sm:px-0">
|
||||||
<p className="text-gray-500 font-medium">Vous avez aimé cet article ?</p>
|
<p className="text-gray-500 font-medium">Vous avez aimé cet article ?</p>
|
||||||
<Link
|
<Link
|
||||||
href="/actualites"
|
href="/actualites"
|
||||||
@@ -211,7 +217,7 @@ export default async function BlogPostPage({ params }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Sidebar flottante verticale à droite (suit l'article et s'arrête à la fin) */}
|
{/* Sidebar flottante verticale à droite (suit l'article et s'arrête à la fin) */}
|
||||||
<div className="w-10 shrink-0 relative">
|
<div className="hidden sm:block w-10 shrink-0 relative">
|
||||||
<div className="sticky top-32 z-50">
|
<div className="sticky top-32 z-50">
|
||||||
<BlogShareButtons title={post.title} />
|
<BlogShareButtons title={post.title} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { sanitizeHTML } from '../../../lib/sanitize';
|
|||||||
import { prisma } from '../../../lib/prisma';
|
import { prisma } from '../../../lib/prisma';
|
||||||
import { InterviewType } from '@prisma/client';
|
import { InterviewType } from '@prisma/client';
|
||||||
import LightboxImage from '@/components/LightboxImage';
|
import LightboxImage from '@/components/LightboxImage';
|
||||||
|
import BlogShareButtons from '../../../components/BlogShareButtons';
|
||||||
|
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
@@ -91,13 +92,15 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white min-h-screen">
|
<div className="bg-white min-h-screen">
|
||||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
<div className="max-w-4xl mx-auto px-0 sm:px-6 lg:px-8 py-0 sm:py-12">
|
||||||
<Link href="/afrolife" className="inline-flex items-center text-gray-500 hover:text-brand-600 mb-8 transition-colors">
|
<div className="pt-4 sm:pt-0 px-4 sm:px-0 mb-6 sm:mb-8">
|
||||||
<ArrowLeft className="w-4 h-4 mr-2" /> Retour à Afro Life
|
<Link href="/afrolife" className="inline-flex items-center text-gray-500 hover:text-brand-600 transition-colors">
|
||||||
</Link>
|
<ArrowLeft className="w-4 h-4 mr-2" /> Retour à Afro Life
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Header Info */}
|
{/* Header Info */}
|
||||||
<div className="text-center mb-10">
|
<div className="text-center mb-8 sm:mb-10 px-4 sm:px-0">
|
||||||
<div className="inline-flex items-center justify-center px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-xs font-bold uppercase tracking-wider mb-4">
|
<div className="inline-flex items-center justify-center px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-xs font-bold uppercase tracking-wider mb-4">
|
||||||
{isEvent ? 'Événement' : (isVideo ? 'Interview Vidéo' : 'Grand Entretien')}
|
{isEvent ? 'Événement' : (isVideo ? 'Interview Vidéo' : 'Grand Entretien')}
|
||||||
</div>
|
</div>
|
||||||
@@ -143,9 +146,9 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main Content Area */}
|
{/* Main Content Area en pleine largeur sur mobile */}
|
||||||
{isVideo ? (
|
{isVideo ? (
|
||||||
<div className="bg-black rounded-xl overflow-hidden shadow-2xl aspect-w-16 aspect-h-9 mb-10">
|
<div className="bg-black rounded-none sm:rounded-xl overflow-hidden shadow-none sm:shadow-2xl aspect-w-16 aspect-h-9 mb-8 sm:mb-10 w-full">
|
||||||
{(interview as any).videoUrl ? (
|
{(interview as any).videoUrl ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={getEmbedUrl((interview as any).videoUrl) || ''}
|
src={getEmbedUrl((interview as any).videoUrl) || ''}
|
||||||
@@ -161,7 +164,7 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative h-64 md:h-96 rounded-xl overflow-hidden shadow-lg mb-10">
|
<div className="relative h-64 md:h-96 rounded-none sm:rounded-xl overflow-hidden shadow-none sm:shadow-lg mb-8 sm:mb-10 w-full">
|
||||||
<LightboxImage
|
<LightboxImage
|
||||||
src={item!.thumbnailUrl}
|
src={item!.thumbnailUrl}
|
||||||
alt={item!.title}
|
alt={item!.title}
|
||||||
@@ -172,7 +175,7 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Description / Article Content / Event Content */}
|
{/* Description / Article Content / Event Content */}
|
||||||
<div className="prose prose-lg prose-orange max-w-none mx-auto text-gray-600">
|
<div className="prose sm:prose-lg prose-orange max-w-none mx-auto text-gray-600 px-4 sm:px-0">
|
||||||
{isEvent ? (
|
{isEvent ? (
|
||||||
<div dangerouslySetInnerHTML={{ __html: sanitizeHTML((event as any).description) }} />
|
<div dangerouslySetInnerHTML={{ __html: sanitizeHTML((event as any).description) }} />
|
||||||
) : (
|
) : (
|
||||||
@@ -188,7 +191,7 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
|||||||
|
|
||||||
{/* Event Link Action */}
|
{/* Event Link Action */}
|
||||||
{isEvent && (event as any).link && (
|
{isEvent && (event as any).link && (
|
||||||
<div className="mt-10 text-center">
|
<div className="mt-10 text-center px-4 sm:px-0">
|
||||||
<Link
|
<Link
|
||||||
href={(event as any).link}
|
href={(event as any).link}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -199,12 +202,12 @@ export default async function AfroLifeDetailPage({ params }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Footer Actions */}
|
{/* Footer Actions / Partage */}
|
||||||
<div className="mt-12 pt-8 border-t border-gray-100 flex justify-center">
|
<div className="mt-10 sm:mt-12 pt-6 sm:pt-8 border-t border-gray-100 px-4 sm:px-0 pb-8 sm:pb-0">
|
||||||
<button className="flex items-center px-6 py-3 rounded-full bg-brand-50 text-brand-700 font-medium hover:bg-brand-100 transition-colors">
|
<p className="text-xs font-bold uppercase tracking-wider text-gray-400 mb-4 text-center">
|
||||||
<Share2 className="w-5 h-5 mr-2" />
|
|
||||||
Partager {isEvent ? "cet événement" : "cette interview"}
|
Partager {isEvent ? "cet événement" : "cette interview"}
|
||||||
</button>
|
</p>
|
||||||
|
<BlogShareButtons title={item!.title} layout="horizontal" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import toast from 'react-hot-toast';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
|
layout?: 'vertical' | 'horizontal';
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BlogShareButtons({ title }: Props) {
|
export default function BlogShareButtons({ title, layout = 'vertical' }: Props) {
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const [url, setUrl] = useState('');
|
const [url, setUrl] = useState('');
|
||||||
|
|
||||||
@@ -32,12 +33,12 @@ export default function BlogShareButtons({ title }: Props) {
|
|||||||
if (!url) return null;
|
if (!url) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-3 z-50">
|
<div className={`flex ${layout === 'horizontal' ? 'flex-row gap-4 justify-center flex-wrap' : 'flex-col gap-3'} z-50`}>
|
||||||
<a
|
<a
|
||||||
href={shareLinks.facebook}
|
href={shareLinks.facebook}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="w-10 h-10 rounded-full bg-white text-[#1877F2] shadow-xl flex items-center justify-center hover:scale-110 transition-transform"
|
className="w-10 h-10 rounded-full bg-white text-[#1877F2] shadow-xl flex items-center justify-center hover:scale-110 transition-transform border border-gray-100"
|
||||||
title="Partager sur Facebook"
|
title="Partager sur Facebook"
|
||||||
>
|
>
|
||||||
<Facebook className="w-5 h-5" />
|
<Facebook className="w-5 h-5" />
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const nextConfig = {
|
|||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
//output: 'standalone',
|
//output: 'standalone',
|
||||||
poweredByHeader: false,
|
poweredByHeader: false,
|
||||||
|
allowedDevOrigins: ['10.0.2.2'],
|
||||||
turbopack: {
|
turbopack: {
|
||||||
root: __dirname,
|
root: __dirname,
|
||||||
},
|
},
|
||||||
@@ -28,7 +29,7 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'Content-Security-Policy',
|
key: 'Content-Security-Policy',
|
||||||
value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' https:; connect-src 'self' wss: https:; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; object-src 'none';",
|
value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https: http:; font-src 'self' data:; media-src 'self' https: http:; connect-src 'self' ws: wss: https: http:; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; object-src 'none';",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'X-Content-Type-Options',
|
key: 'X-Content-Type-Options',
|
||||||
|
|||||||
Reference in New Issue
Block a user