feat: Initialize InstaArchive PWA project

Sets up a new React PWA project with Vite, Tailwind CSS, and basic PWA features. Includes essential files like README, .gitignore, package.json, and initial app structure.
This commit is contained in:
ergosteur
2026-03-06 22:41:48 -05:00
parent a724e5bc87
commit cd7dc5f981
12 changed files with 10810 additions and 8 deletions

9
.env.example Normal file
View File

@@ -0,0 +1,9 @@
# GEMINI_API_KEY: Required for Gemini AI API calls.
# AI Studio automatically injects this at runtime from user secrets.
# Users configure this via the Secrets panel in the AI Studio UI.
GEMINI_API_KEY="MY_GEMINI_API_KEY"
# APP_URL: The URL where this applet is hosted.
# AI Studio automatically injects this at runtime with the Cloud Run service URL.
# Used for self-referential links, OAuth callbacks, and API endpoints.
APP_URL="MY_APP_URL"

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
node_modules/
build/
dist/
coverage/
.DS_Store
*.log
.env*
!.env.example

View File

@@ -1,11 +1,20 @@
<div align="center">
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
<h1>Built with AI Studio</h2>
<p>The fastest path from prompt to production with Gemini.</p>
<a href="https://aistudio.google.com/apps">Start building</a>
</div>
# Run and deploy your AI Studio app
This contains everything you need to run your app locally.
View your app in AI Studio: https://ai.studio/apps/29dc2807-7763-419f-9f2f-ac644e1bf4a1
## Run Locally
**Prerequisites:** Node.js
1. Install dependencies:
`npm install`
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
3. Run the app:
`npm run dev`

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>InstaArchive</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

5
metadata.json Normal file
View File

@@ -0,0 +1,5 @@
{
"name": "InstaArchive",
"description": "A high-performance PWA to browse and explore your archived Instagram data with a native-feeling interface.",
"requestFramePermissions": []
}

9202
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

39
package.json Normal file
View File

@@ -0,0 +1,39 @@
{
"name": "react-example",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --port=3000 --host=0.0.0.0",
"build": "vite build",
"preview": "vite preview",
"clean": "rm -rf dist",
"lint": "tsc --noEmit"
},
"dependencies": {
"@google/genai": "^1.29.0",
"@tailwindcss/vite": "^4.1.14",
"@vitejs/plugin-react": "^5.0.4",
"better-sqlite3": "^12.4.1",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"lucide-react": "^0.546.0",
"motion": "^12.23.24",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^3.5.0",
"vite": "^6.2.0"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^22.14.0",
"autoprefixer": "^10.4.21",
"tailwindcss": "^4.1.14",
"tsx": "^4.21.0",
"typescript": "~5.8.2",
"vite": "^6.2.0",
"vite-plugin-pwa": "^1.2.0"
}
}

1363
src/App.tsx Normal file

File diff suppressed because it is too large Load Diff

43
src/index.css Normal file
View File

@@ -0,0 +1,43 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap');
@import "tailwindcss";
@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-serif: "Playfair Display", ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
}
@layer base {
body {
@apply antialiased;
}
}
/* Custom scrollbar for a cleaner look */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #e5e7eb;
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: #d1d5db;
}
@keyframes dots-blink {
0%, 20% { content: ''; }
40% { content: '.'; }
60% { content: '..'; }
80%, 100% { content: '...'; }
}
.animate-dots::after {
content: '';
animation: dots-blink 1.5s infinite;
}

13
src/main.tsx Normal file
View File

@@ -0,0 +1,13 @@
import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { registerSW } from 'virtual:pwa-register';
registerSW();
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);

27
tsconfig.json Normal file
View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2022",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"module": "ESNext",
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"moduleResolution": "bundler",
"isolatedModules": true,
"moduleDetection": "force",
"allowJs": true,
"jsx": "react-jsx",
"paths": {
"@/*": [
"./*"
]
},
"allowImportingTsExtensions": true,
"noEmit": true,
"types": ["vite-plugin-pwa/client"]
}
}

71
vite.config.ts Normal file
View File

@@ -0,0 +1,71 @@
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import {defineConfig, loadEnv} from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig(({mode}) => {
const env = loadEnv(mode, '.', '');
return {
plugins: [
react(),
tailwindcss(),
VitePWA({
registerType: 'prompt',
manifest: {
name: 'InstaArchive',
short_name: 'InstaArchive',
description: 'Browse your archived Instagram data with a native-feeling interface.',
theme_color: '#ffffff',
background_color: '#ffffff',
display: 'standalone',
icons: [
{
src: 'https://cdn-icons-png.flaticon.com/512/174/174855.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
},
{
src: 'https://cdn-icons-png.flaticon.com/192/174/174855.png',
sizes: '192x192',
type: 'image/png'
}
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff,woff2}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 10,
maxAgeSeconds: 60 * 60 * 24 * 365
},
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}
})
],
define: {
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),
},
resolve: {
alias: {
'@': path.resolve(__dirname, '.'),
},
},
server: {
// HMR is disabled in AI Studio via DISABLE_HMR env var.
// Do not modify—file watching is disabled to prevent flickering during agent edits.
hmr: process.env.DISABLE_HMR !== 'true',
},
};
});