Skip to content

Commit 04ccc0a

Browse files
committed
Implement SPA routing and remove .html extensions from navigation links
1 parent 9008387 commit 04ccc0a

File tree

6 files changed

+102
-64
lines changed

6 files changed

+102
-64
lines changed

.github/workflows/deploy.yml

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -84,52 +84,30 @@ jobs:
8484
# Print confirmation (without showing the content for security)
8585
echo "Created .env file with $(grep -c '' .env) lines"
8686
87-
- name: Install Supabase CLI and setup project
87+
- name: Prepare for deployment
8888
run: |
8989
# Make scripts executable
9090
chmod +x ./bin/supabase-db.sh
91+
chmod +x ./bin/deploy.sh
92+
chmod +x ./bin/deploy-with-migrations.sh
9193
9294
# Debug: Check .env file existence
9395
echo "Checking .env file..."
9496
if [ -f .env ]; then
9597
echo ".env file exists with $(grep -c '' .env) lines"
96-
# Check if required variables are in .env (without showing values)
97-
grep -q "SUPABASE_URL" .env && echo "SUPABASE_URL is set" || echo "SUPABASE_URL is missing"
98-
grep -q "SUPABASE_KEY" .env && echo "SUPABASE_KEY is set" || echo "SUPABASE_KEY is missing"
99-
grep -q "SUPABASE_DB_PASSWORD" .env && echo "SUPABASE_DB_PASSWORD is set" || echo "SUPABASE_DB_PASSWORD is missing"
100-
grep -q "SUPABASE_ACCESS_TOKEN" .env && echo "SUPABASE_ACCESS_TOKEN is set" || echo "SUPABASE_ACCESS_TOKEN is missing"
10198
else
10299
echo ".env file does not exist"
103100
fi
104-
105-
# Setup Supabase project
106-
./bin/supabase-db.sh setup
107-
108-
# Add to PATH
109-
export PATH="$HOME/.local/bin:$PATH"
110-
111-
# Verify installation
112-
supabase --version
113-
env:
114-
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
115-
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
116-
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
117-
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }}
118-
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
119101
120102
- name: Deploy to server with migrations
121103
run: |
122-
# Make deploy scripts executable
123-
chmod +x ./bin/deploy.sh
124-
chmod +x ./bin/deploy-with-migrations.sh
125-
126104
# Print debug info
127105
echo "Current directory: $(pwd)"
128106
echo "Files in bin directory:"
129107
ls -la ./bin
130108
131109
# Run deploy script with migrations
132-
DEPLOY_REMOTE_HOST=104.36.23.197 DEPLOY_REMOTE_PORT=2048 DEPLOY_REMOTE_USER=ubuntu ./bin/deploy-with-migrations.sh
110+
./bin/deploy-with-migrations.sh
133111
134112
# Run test script to verify deployment
135113
echo "Running test script on remote server..."
@@ -139,8 +117,4 @@ jobs:
139117
DEPLOY_REMOTE_PORT: 2048
140118
DEPLOY_REMOTE_USER: ubuntu
141119
DEPLOY_REMOTE_DIR: www/profullstack.com/pdf
142-
INSTALL_SERVICE: true
143-
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
144-
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
145-
SUPABASE_DB_PASSWORD: ${{ secrets.SUPABASE_DB_PASSWORD }}
146-
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
120+
INSTALL_SERVICE: true

bin/deploy-with-migrations.sh

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,45 @@ NC='\033[0m' # No Color
99

1010
echo -e "${YELLOW}Starting deployment with migrations...${NC}"
1111

12+
# Load environment variables from .env file
13+
if [ -f .env ]; then
14+
echo "Loading environment variables from .env file..."
15+
export $(grep -v '^#' .env | xargs)
16+
else
17+
echo "No .env file found. Using default values."
18+
fi
19+
20+
# Define variables with fallbacks
21+
REMOTE_HOST="${DEPLOY_REMOTE_HOST:-104.36.23.197}"
22+
REMOTE_PORT="${DEPLOY_REMOTE_PORT:-2048}"
23+
REMOTE_USER="${DEPLOY_REMOTE_USER:-ubuntu}"
24+
REMOTE_DIR="${DEPLOY_REMOTE_DIR:-www/profullstack.com/pdf}"
25+
26+
# Create SSH options
27+
SSH_OPTS="-p $REMOTE_PORT"
28+
1229
# Deploy the code first
1330
echo -e "${YELLOW}Running deployment script...${NC}"
1431
./bin/deploy.sh
1532

1633
echo -e "${GREEN}Deployment successful!${NC}"
1734

18-
# Debug: Print environment variables (masked for security)
19-
echo -e "${YELLOW}Checking environment variables...${NC}"
20-
echo "SUPABASE_URL is ${SUPABASE_URL:+set}${SUPABASE_URL:-not set}"
21-
echo "SUPABASE_KEY is ${SUPABASE_KEY:+set}${SUPABASE_KEY:-not set}"
22-
echo "SUPABASE_DB_PASSWORD is ${SUPABASE_DB_PASSWORD:+set}${SUPABASE_DB_PASSWORD:-not set}"
23-
echo "SUPABASE_ACCESS_TOKEN is ${SUPABASE_ACCESS_TOKEN:+set}${SUPABASE_ACCESS_TOKEN:-not set}"
35+
# Run migrations on the remote server
36+
echo -e "${YELLOW}Running database migrations on remote server...${NC}"
37+
ssh $SSH_OPTS $REMOTE_USER@$REMOTE_HOST "cd $REMOTE_DIR && ./bin/supabase-db.sh migrate"
2438

25-
# Run migrations using Supabase CLI
26-
echo -e "${YELLOW}Running database migrations with Supabase CLI...${NC}"
27-
28-
# Check if required environment variables are set
29-
if [ -z "$SUPABASE_URL" ] || [ -z "$SUPABASE_KEY" ] || [ -z "$SUPABASE_DB_PASSWORD" ] || [ -z "$SUPABASE_ACCESS_TOKEN" ]; then
30-
echo -e "${RED}Error: Required Supabase environment variables are not set.${NC}"
31-
echo -e "${YELLOW}Make sure SUPABASE_URL, SUPABASE_KEY, SUPABASE_DB_PASSWORD, and SUPABASE_ACCESS_TOKEN are set.${NC}"
39+
if [ $? -eq 0 ]; then
40+
echo -e "${GREEN}Migrations successful!${NC}"
41+
else
42+
echo -e "${RED}Migrations failed. Please check the error messages above.${NC}"
43+
echo -e "${YELLOW}You can try running migrations manually by connecting to the remote server and running:${NC}"
44+
echo -e " ssh $SSH_OPTS $REMOTE_USER@$REMOTE_HOST \"cd $REMOTE_DIR && ./bin/supabase-db.sh migrate\""
3245
exit 1
3346
fi
3447

35-
# Run migrations directly
36-
echo -e "${YELLOW}Running migrations...${NC}"
37-
./bin/supabase-db.sh migrate
38-
39-
echo -e "${GREEN}Migrations successful!${NC}"
40-
4148
# Restart the service
4249
echo -e "${YELLOW}Restarting service...${NC}"
43-
ssh -p 2048 [email protected] "sudo systemctl restart profullstack-pdf.service"
50+
ssh $SSH_OPTS $REMOTE_USER@$REMOTE_HOST "sudo systemctl restart profullstack-pdf.service"
4451

4552
echo -e "${GREEN}Service restarted successfully!${NC}"
4653
echo -e "${GREEN}Deployment with migrations completed successfully!${NC}"

index.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import puppeteer from 'puppeteer';
55
import path from 'path';
66
import { fileURLToPath } from 'url';
77
import dotenvFlow from 'dotenv-flow';
8+
import fs from 'fs/promises';
89
import { marked } from 'marked';
910
import * as XLSX from 'xlsx';
1011
import { JSDOM } from 'jsdom';
@@ -17,9 +18,65 @@ dotenvFlow.config();
1718
const __dirname = path.dirname(fileURLToPath(import.meta.url));
1819
const app = new Hono();
1920

21+
// SPA routing middleware
22+
app.use('*', async (c, next) => {
23+
const url = new URL(c.req.url);
24+
const pathname = url.pathname;
25+
26+
// Skip API routes
27+
if (pathname.startsWith('/api/')) {
28+
return next();
29+
}
30+
31+
// If the path has no extension, it might be an SPA route
32+
if (pathname !== '/' && !pathname.includes('.')) {
33+
// Try to serve the HTML file with the same name
34+
const htmlPath = path.join(__dirname, 'public', `${pathname}.html`);
35+
const viewsPath = path.join(__dirname, 'public', 'views', `${pathname}.html`);
36+
37+
try {
38+
// Check if the HTML file exists in public directory
39+
await fs.access(htmlPath);
40+
// If it exists, rewrite the URL to the HTML file
41+
c.req.url = new URL(`${pathname}.html`, c.req.url).toString();
42+
return next();
43+
} catch (e) {
44+
try {
45+
// Check if the HTML file exists in views directory
46+
await fs.access(viewsPath);
47+
// If it exists, rewrite the URL to the views HTML file
48+
c.req.url = new URL(`/views${pathname}.html`, c.req.url).toString();
49+
return next();
50+
} catch (e) {
51+
// If neither exists, let it fall through to the SPA handler
52+
}
53+
}
54+
}
55+
56+
return next();
57+
});
58+
2059
// Serve static files from the public directory
2160
app.use('/*', serveStatic({ root: './public' }));
2261

62+
// SPA fallback for routes that don't match any static files
63+
app.get('*', async (c, next) => {
64+
const url = new URL(c.req.url);
65+
const pathname = url.pathname;
66+
67+
// Skip API routes and files with extensions
68+
if (pathname.startsWith('/api/') || pathname.includes('.')) {
69+
return next();
70+
}
71+
72+
// If we got here, it's a client-side route, serve the index.html
73+
// This allows the client-side router to handle the route
74+
console.log(`Serving index.html for SPA route: ${pathname}`);
75+
const indexPath = path.join(__dirname, 'public', 'index.html');
76+
const indexContent = await fs.readFile(indexPath, 'utf-8');
77+
return c.html(indexContent);
78+
});
79+
2380
// Health check endpoint
2481
app.get('/', (c) => {
2582
// If the request accepts HTML, the static file middleware will handle it

public/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ <h2>Generate Documents from HTML with Ease</h2>
9797
<p>Convert HTML content to PDF, Word, Excel, PowerPoint, and EPUB formats with a simple API call. Perfect for reports, invoices, presentations, and more.</p>
9898

9999
<div class="cta-buttons">
100-
<a href="/register.html" class="cta-primary">Get Started</a>
101-
<a href="/login.html" class="cta-secondary">Login</a>
100+
<a href="/register" class="cta-primary">Get Started</a>
101+
<a href="/login" class="cta-secondary">Login</a>
102102
</div>
103103
</div>
104104
</div>

public/js/components/pf-footer.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,15 @@ class PfFooter extends HTMLElement {
8686
<h3>Document Generation API</h3>
8787
<ul class="footer-links">
8888
<li><a href="/">Home</a></li>
89-
<li><a href="/api-docs.html">API Documentation</a></li>
90-
<li><a href="/subscription.html">Pricing</a></li>
89+
<li><a href="/api-docs">API Documentation</a></li>
90+
<li><a href="/subscription">Pricing</a></li>
9191
</ul>
9292
</div>
9393
9494
<div class="footer-section">
9595
<h3>Resources</h3>
9696
<ul class="footer-links">
97-
<li><a href="/api-keys.html">API Keys</a></li>
97+
<li><a href="/api-keys">API Keys</a></li>
9898
<li><a href="https://github.com/profullstack/pdf" target="_blank">GitHub</a></li>
9999
<li><a href="mailto:[email protected]">Support</a></li>
100100
</ul>
@@ -103,8 +103,8 @@ class PfFooter extends HTMLElement {
103103
<div class="footer-section">
104104
<h3>Legal</h3>
105105
<ul class="footer-links">
106-
<li><a href="/terms.html">Terms of Service</a></li>
107-
<li><a href="/privacy.html">Privacy Policy</a></li>
106+
<li><a href="/terms">Terms of Service</a></li>
107+
<li><a href="/privacy">Privacy Policy</a></li>
108108
</ul>
109109
</div>
110110
</div>

public/js/components/pf-header.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,10 @@ class PfHeader extends HTMLElement {
137137
138138
<div class="nav-links">
139139
<a href="/" class="nav-link">Home</a>
140-
<a href="/api-docs.html" class="nav-link">API Docs</a>
141-
<a href="/api-keys.html" class="nav-link">API Keys</a>
142-
<a href="/login.html" class="nav-link login-link">Login</a>
143-
<a href="/register.html" class="subscription-link register-link">Register</a>
140+
<a href="/api-docs" class="nav-link">API Docs</a>
141+
<a href="/api-keys" class="nav-link">API Keys</a>
142+
<a href="/login" class="nav-link login-link">Login</a>
143+
<a href="/register" class="subscription-link register-link">Register</a>
144144
</div>
145145
</div>
146146
`;
@@ -189,7 +189,7 @@ class PfHeader extends HTMLElement {
189189
</svg>
190190
</button>
191191
<div class="dropdown-menu">
192-
<a href="/settings.html" class="dropdown-item">Settings</a>
192+
<a href="/settings" class="dropdown-item">Settings</a>
193193
<a href="#" class="dropdown-item logout-button">Logout</a>
194194
</div>
195195
</div>
@@ -241,7 +241,7 @@ class PfHeader extends HTMLElement {
241241

242242
// Redirect to home page if on a protected page
243243
const currentPath = window.location.pathname;
244-
const protectedPages = ['/api-keys.html', '/settings.html'];
244+
const protectedPages = ['/api-keys', '/settings'];
245245

246246
if (protectedPages.includes(currentPath)) {
247247
window.location.href = '/';

0 commit comments

Comments
 (0)