Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
87
index.html
87
index.html
@@ -32,7 +32,11 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.app { width: 100%; max-width: 680px; padding: 2rem 0; }
|
||||
.app { display: none; width: 100%; max-width: 680px; padding: 2rem 0; }
|
||||
|
||||
#login-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: var(--color-background-secondary); display: flex; align-items: center; justify-content: center; z-index: 1000; }
|
||||
.login-card { background: var(--color-background-primary); padding: 2rem; border: 0.5px solid var(--color-border-secondary); border-radius: var(--border-radius-lg); width: 100%; max-width: 320px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
|
||||
.login-card h2 { font-family: 'Lora', serif; font-size: 24px; margin-bottom: 1.25rem; text-align: center; }
|
||||
|
||||
.header { margin-bottom: 2rem; border-bottom: 0.5px solid var(--color-border-tertiary); padding-bottom: 1.25rem; }
|
||||
.header h1 { font-family: 'Lora', serif; font-size: 26px; font-weight: 600; letter-spacing: -0.5px; margin-bottom: 4px; }
|
||||
@@ -111,7 +115,23 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<div id="login-overlay">
|
||||
<div class="login-card">
|
||||
<h2 style="font-family: 'Lora', serif; font-size: 26px; font-weight: 600; letter-spacing: -0.5px; margin-bottom: 20px;">Welcome</h2>
|
||||
<div class="form-field" style="margin-bottom: 12px;">
|
||||
<label>Username</label>
|
||||
<input type="text" id="login-username" />
|
||||
</div>
|
||||
<div class="form-field" style="margin-bottom: 12px;">
|
||||
<label>Password</label>
|
||||
<input type="password" id="login-password" />
|
||||
</div>
|
||||
<button class="generate-btn" id="login-btn" style="margin-top: 12px;">Sign in</button>
|
||||
<div id="login-error" style="color: var(--color-text-danger); font-size: 13px; margin-top: 10px; text-align: center; display: none;">Invalid credentials</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app" id="app-content">
|
||||
<div class="header">
|
||||
<h1>Recipe Generator</h1>
|
||||
<p>Tell the AI what you have and what you want — it handles the rest.</p>
|
||||
@@ -187,6 +207,45 @@
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
let sessionUser = '';
|
||||
let sessionPass = '';
|
||||
|
||||
const loginBtn = document.getElementById('login-btn');
|
||||
const loginOverlay = document.getElementById('login-overlay');
|
||||
const appContent = document.getElementById('app-content');
|
||||
|
||||
loginBtn.addEventListener('click', async () => {
|
||||
const user = document.getElementById('login-username').value;
|
||||
const pass = document.getElementById('login-password').value;
|
||||
const btn = document.getElementById('login-btn');
|
||||
|
||||
btn.disabled = true;
|
||||
btn.innerText = 'Verifying...';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username: user, password: pass })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
sessionUser = user;
|
||||
sessionPass = pass;
|
||||
loginOverlay.style.display = 'none';
|
||||
appContent.style.display = 'block';
|
||||
} else {
|
||||
document.getElementById('login-error').style.display = 'block';
|
||||
}
|
||||
} catch (err) {
|
||||
document.getElementById('login-error').innerText = 'Network error. Please try again.';
|
||||
document.getElementById('login-error').style.display = 'block';
|
||||
}
|
||||
|
||||
btn.disabled = false;
|
||||
btn.innerText = 'Sign in';
|
||||
});
|
||||
|
||||
const ingredients = [];
|
||||
const ingWrapper = document.getElementById('ing-wrapper');
|
||||
const ingInput = document.getElementById('ing-input');
|
||||
@@ -277,31 +336,21 @@ Respond with ONLY a valid JSON object. Use this exact structure:
|
||||
Rules: use provided ingredients as the base, add pantry staples as needed, 5–10 steps, each instruction 1–3 richly detailed sentences, respect all dietary restrictions strictly.`;
|
||||
|
||||
try {
|
||||
// Vite will inject this automatically from the .env file
|
||||
const API_KEY = import.meta.env.VITE_GEMINI_API_KEY;
|
||||
|
||||
const resp = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${API_KEY}`, {
|
||||
const resp = await fetch('/api/generate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
systemInstruction: {
|
||||
parts: [{ text: systemPrompt }]
|
||||
},
|
||||
contents: [{
|
||||
parts: [{ text: userPrompt }]
|
||||
}],
|
||||
generationConfig: {
|
||||
responseMimeType: "application/json"
|
||||
}
|
||||
username: sessionUser,
|
||||
password: sessionPass,
|
||||
systemPrompt: systemPrompt,
|
||||
userPrompt: userPrompt
|
||||
})
|
||||
});
|
||||
|
||||
const data = await resp.json();
|
||||
|
||||
if (!resp.ok) {
|
||||
throw new Error(data.error?.message || `API error ${resp.status}`);
|
||||
throw new Error(data.error || `Server error ${resp.status}`);
|
||||
}
|
||||
|
||||
const raw = data.candidates[0].content.parts[0].text;
|
||||
|
||||
Reference in New Issue
Block a user