google-oauth-cli-generator
Version:
CLI tool to quickly set up Google OAuth authentication for hackathons and projects
342 lines (303 loc) • 9.39 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateVanillaTemplate = generateVanillaTemplate;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
async function generateVanillaTemplate(data) {
const { projectPath } = data;
const frontendPath = path_1.default.join(projectPath, 'frontend');
// Create vanilla JS directory structure
await fs_extra_1.default.ensureDir(path_1.default.join(frontendPath, 'src'));
await fs_extra_1.default.ensureDir(path_1.default.join(frontendPath, 'public'));
// Generate package.json
const packageJson = {
name: `${data.config.projectName}-frontend`,
version: '1.0.0',
private: true,
scripts: {
dev: 'vite',
build: 'vite build',
preview: 'vite preview'
},
devDependencies: {
vite: '^4.4.9'
}
};
await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'package.json'), JSON.stringify(packageJson, null, 2));
// Generate vite.config.js
const viteConfig = `import { defineConfig } from 'vite'
export default defineConfig({
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
}
})`;
await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'vite.config.js'), viteConfig);
// Generate index.html
const indexHtml = `<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>${data.config.projectName}</title>
<link rel="stylesheet" href="/src/style.css" />
</head>
<body>
<div id="app">
<header class="app-header">
<h1>🚀 ${data.config.projectName}</h1>
<p>Google OAuth Authentication Demo</p>
</header>
<main class="app-main">
<div id="loading" class="loading">Loading...</div>
<div id="login-container" class="login-container" style="display: none;">
<h2>Welcome! Please sign in</h2>
<button id="login-btn" class="google-login-btn">
<svg class="google-icon" viewBox="0 0 24 24">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
</svg>
Sign in with Google
</button>
</div>
<div id="profile-container" class="profile-container" style="display: none;">
<div class="profile-card">
<img id="profile-picture" class="profile-picture" alt="Profile" />
<h2 id="profile-name">Welcome!</h2>
<p id="profile-email" class="profile-email"></p>
<button id="logout-btn" class="logout-btn">Sign Out</button>
</div>
</div>
</main>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>`;
await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'index.html'), indexHtml);
// Generate main.js
const mainJs = `class AuthApp {
constructor() {
this.user = null;
this.loadingEl = document.getElementById('loading');
this.loginContainer = document.getElementById('login-container');
this.profileContainer = document.getElementById('profile-container');
this.loginBtn = document.getElementById('login-btn');
this.logoutBtn = document.getElementById('logout-btn');
this.init();
}
async init() {
this.bindEvents();
await this.checkAuthStatus();
}
bindEvents() {
this.loginBtn.addEventListener('click', this.handleLogin.bind(this));
this.logoutBtn.addEventListener('click', this.handleLogout.bind(this));
}
async checkAuthStatus() {
try {
const response = await fetch('/api/auth/user', {
credentials: 'include'
});
if (response.ok) {
this.user = await response.json();
this.showProfile();
} else {
this.showLogin();
}
} catch (error) {
console.error('Auth check failed:', error);
this.showLogin();
} finally {
this.hideLoading();
}
}
handleLogin() {
window.location.href = '/api/auth/google';
}
async handleLogout() {
try {
await fetch('/api/auth/logout', {
method: 'POST',
credentials: 'include'
});
this.user = null;
this.showLogin();
} catch (error) {
console.error('Logout failed:', error);
}
}
hideLoading() {
this.loadingEl.style.display = 'none';
}
showLogin() {
this.loginContainer.style.display = 'block';
this.profileContainer.style.display = 'none';
}
showProfile() {
if (!this.user) return;
document.getElementById('profile-picture').src = this.user.picture;
document.getElementById('profile-picture').alt = this.user.name;
document.getElementById('profile-name').textContent = \`Welcome, \${this.user.name}!\`;
document.getElementById('profile-email').textContent = this.user.email;
this.profileContainer.style.display = 'block';
this.loginContainer.style.display = 'none';
}
}
// Initialize the app when the DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new AuthApp();
});`;
await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'main.js'), mainJs);
// Generate style.css
const styleCss = `* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#app {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 2rem;
}
.app-header h1 {
font-size: 3rem;
margin-bottom: 0.5rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
text-align: center;
}
.app-header p {
font-size: 1.2rem;
opacity: 0.9;
margin-bottom: 2rem;
text-align: center;
}
.loading {
font-size: 1.5rem;
animation: pulse 1.5s ease-in-out infinite alternate;
}
pulse {
from { opacity: 0.6; }
to { opacity: 1; }
}
.login-container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 3rem;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
text-align: center;
}
.login-container h2 {
margin-bottom: 2rem;
font-size: 1.8rem;
}
.google-login-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
background: white;
color: #333;
border: none;
border-radius: 12px;
padding: 16px 32px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.google-login-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.2);
}
.google-icon {
width: 20px;
height: 20px;
}
.profile-container {
display: flex;
justify-content: center;
align-items: center;
}
.profile-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 3rem;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
text-align: center;
}
.profile-picture {
width: 120px;
height: 120px;
border-radius: 50%;
margin-bottom: 1.5rem;
border: 4px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.profile-card h2 {
margin-bottom: 0.5rem;
font-size: 2rem;
}
.profile-email {
opacity: 0.8;
margin-bottom: 2rem;
font-size: 1.1rem;
}
.logout-btn {
background: rgba(255, 255, 255, 0.2);
color: white;
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
padding: 12px 24px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
.logout-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
(max-width: 768px) {
.app-header h1 {
font-size: 2rem;
}
.login-container,
.profile-card {
padding: 2rem;
margin: 0 1rem;
}
.profile-picture {
width: 100px;
height: 100px;
}
}`;
await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'style.css'), styleCss);
}
//# sourceMappingURL=vanilla-template.js.map