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
13 changes: 9 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LaTeX Forge</title>
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Y6B556JJNX"></script>
<!-- Google Analytics (loaded only if user has consented) -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Y6B556JJNX');
if (localStorage.getItem('cookie-consent') !== 'declined') {
var s = document.createElement('script');
s.async = true;
s.src = 'https://www.googletagmanager.com/gtag/js?id=G-Y6B556JJNX';
document.head.appendChild(s);
gtag('js', new Date());
gtag('config', 'G-Y6B556JJNX');
}
</script>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📝</text></svg>" />
</head>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "latexforge",
"private": true,
"version": "1.0.0",
"license": "GPL-3.0-only",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
7 changes: 7 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import ProjectEditor from './pages/ProjectEditor.jsx';
import AcceptInvite from './pages/AcceptInvite.jsx';
import InviteColleagues from './pages/InviteColleagues.jsx';
import AccessDenied from './pages/AccessDenied.jsx';
import Legal from './pages/Legal.jsx';
import CookieConsent from './components/CookieConsent.jsx';

function ProtectedRoute({ children }) {
const { user, loading } = useAuth();
Expand Down Expand Up @@ -70,6 +72,10 @@ export default function App() {
path="/access-denied"
element={<AccessDenied />}
/>
<Route
path="/legal"
element={<Legal />}
/>
<Route
path="/register"
element={<Navigate to="/login" replace />}
Expand All @@ -95,6 +101,7 @@ export default function App() {
}
/>
</Routes>
<CookieConsent />
</BrowserRouter>
);
}
48 changes: 48 additions & 0 deletions src/components/CookieConsent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useState, useEffect } from 'react';

export default function CookieConsent() {
const [visible, setVisible] = useState(false);

useEffect(() => {
const consent = localStorage.getItem('cookie-consent');
if (!consent) setVisible(true);
}, []);

function handleAccept() {
localStorage.setItem('cookie-consent', 'accepted');
setVisible(false);
// Enable GA if it wasn't loaded on page load
if (!window.gtag) {
const s = document.createElement('script');
s.async = true;
s.src = 'https://www.googletagmanager.com/gtag/js?id=G-Y6B556JJNX';
document.head.appendChild(s);
window.dataLayer = window.dataLayer || [];
window.gtag = function () { window.dataLayer.push(arguments); };
window.gtag('js', new Date());
window.gtag('config', 'G-Y6B556JJNX');
}
}

function handleDecline() {
localStorage.setItem('cookie-consent', 'declined');
setVisible(false);
// Disable GA
window['ga-disable-G-Y6B556JJNX'] = true;
}

if (!visible) return null;

return (
<div className="cookie-banner">
<p className="cookie-banner-text">
This site uses cookies for authentication and analytics.{' '}
<a href="/legal#cookies">Learn more</a>
</p>
<div className="cookie-banner-actions">
<button onClick={handleAccept} className="btn cookie-btn-accept">Accept</button>
<button onClick={handleDecline} className="btn cookie-btn-decline">Decline Analytics</button>
</div>
</div>
);
}
168 changes: 168 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,157 @@ body {
color: var(--text-muted);
}

/* ===== Legal Page ===== */
.legal-page {
min-height: 100vh;
background: #1e1e2e;
color: #e0e0e0;
padding: 40px 24px;
}
.legal-container {
max-width: 720px;
margin: 0 auto;
}
.legal-back {
color: #888;
text-decoration: none;
font-size: 14px;
}
.legal-back:hover {
color: #4caf50;
}
.legal-page h1 {
font-size: 28px;
font-weight: 700;
color: #fff;
margin: 20px 0 4px;
}
.legal-updated {
color: #888;
font-size: 13px;
margin-bottom: 24px;
}
.legal-nav {
display: flex;
gap: 16px;
margin-bottom: 40px;
padding-bottom: 16px;
border-bottom: 1px solid #3a3a50;
}
.legal-nav a {
color: #4caf50;
text-decoration: none;
font-size: 14px;
font-weight: 500;
}
.legal-nav a:hover {
text-decoration: underline;
}
.legal-page section {
margin-bottom: 48px;
}
.legal-page h2 {
font-size: 22px;
font-weight: 600;
color: #fff;
margin-bottom: 20px;
padding-top: 16px;
border-top: 1px solid #3a3a50;
}
.legal-page h3 {
font-size: 16px;
font-weight: 600;
color: #ddd;
margin: 20px 0 8px;
}
.legal-page p {
font-size: 14px;
line-height: 1.7;
color: #bbb;
margin-bottom: 12px;
}
.legal-page ul {
margin: 0 0 12px 20px;
padding: 0;
}
.legal-page li {
font-size: 14px;
line-height: 1.7;
color: #bbb;
margin-bottom: 4px;
}
.legal-page a {
color: #4caf50;
text-decoration: none;
}
.legal-page a:hover {
text-decoration: underline;
}
.legal-footer {
margin-top: 40px;
padding-top: 20px;
border-top: 1px solid #3a3a50;
text-align: center;
}

/* ===== Cookie Consent Banner ===== */
.cookie-banner {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
padding: 14px 24px;
background: #1a1a1a;
border-top: 1px solid #333;
flex-wrap: wrap;
}
.cookie-banner-text {
font-size: 14px;
color: #ccc;
}
.cookie-banner-text a {
color: #4caf50;
text-decoration: none;
}
.cookie-banner-text a:hover {
text-decoration: underline;
}
.cookie-banner-actions {
display: flex;
gap: 8px;
}
.cookie-btn-accept {
background: #4caf50;
color: #fff;
border: none;
padding: 8px 20px;
border-radius: 4px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
.cookie-btn-accept:hover {
background: #43a047;
}
.cookie-btn-decline {
background: transparent;
color: #999;
border: 1px solid #555;
padding: 8px 20px;
border-radius: 4px;
font-size: 13px;
cursor: pointer;
}
.cookie-btn-decline:hover {
border-color: #888;
color: #ccc;
}

/* ===== Access Denied Page ===== */
.access-denied-page {
display: flex;
Expand Down Expand Up @@ -483,6 +634,23 @@ body {
font-size: 13px;
color: #666;
}
.landing-footer-links {
margin-top: 8px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.landing-footer-links a {
color: #888;
text-decoration: none;
}
.landing-footer-links a:hover {
color: #4caf50;
}
.landing-footer-links span {
color: #555;
}

/* Responsive */
@media (max-width: 768px) {
Expand Down
Loading
Loading