Deminiko commited on
Commit
f14212d
·
0 Parent(s):

Initial commit: Web app with HTML/CSS/JS/PHP + Docker

Browse files
.github/workflows/sync-to-hf.yml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face Space
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ sync:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout repository
13
+ uses: actions/checkout@v3
14
+ with:
15
+ fetch-depth: 0
16
+ lfs: true
17
+
18
+ - name: Push to Hugging Face Space
19
+ env:
20
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
21
+ run: |
22
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
23
+ git config --global user.name "github-actions[bot]"
24
+ git remote add hf https://NLarchive:[email protected]/spaces/NLarchive/my-webapp-hf
.gitignore ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dependencies
2
+ node_modules/
3
+ vendor/
4
+
5
+ # Environment files
6
+ .env
7
+ .env.local
8
+
9
+ # IDE
10
+ .vscode/
11
+ .idea/
12
+ *.swp
13
+ *.swo
14
+
15
+ # OS
16
+ .DS_Store
17
+ Thumbs.db
18
+
19
+ # Logs
20
+ *.log
21
+
22
+ # Docker
23
+ .dockerignore
Dockerfile ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM php:8.2-apache
2
+
3
+ # Enable Apache mod_rewrite for clean URLs
4
+ RUN a2enmod rewrite
5
+
6
+ # Install any additional PHP extensions if needed
7
+ # RUN docker-php-ext-install pdo pdo_mysql
8
+
9
+ # Set working directory
10
+ WORKDIR /var/www/html
11
+
12
+ # Copy all web files to Apache document root
13
+ COPY ./public /var/www/html
14
+
15
+ # Set proper permissions
16
+ RUN chown -R www-data:www-data /var/www/html \
17
+ && chmod -R 755 /var/www/html
18
+
19
+ # Configure Apache to listen on port 7860 (required by Hugging Face Spaces)
20
+ RUN sed -i 's/80/7860/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
21
+
22
+ # Expose port 7860
23
+ EXPOSE 7860
24
+
25
+ # Start Apache in foreground
26
+ CMD ["apache2-foreground"]
README.md ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # My Web App on Hugging Face Spaces
2
+
3
+ A simple web application with HTML, CSS, JavaScript, and PHP running on Hugging Face Spaces via Docker.
4
+
5
+ ## Features
6
+
7
+ - 📄 Static HTML content
8
+ - 🎨 Responsive CSS styling
9
+ - ⚡ Interactive JavaScript
10
+ - 🐘 PHP backend processing
11
+ - 🐳 Dockerized with Apache
12
+ - 🔄 Auto-sync from GitHub to Hugging Face
13
+
14
+ ## Technologies
15
+
16
+ - HTML5
17
+ - CSS3
18
+ - JavaScript (Vanilla)
19
+ - PHP 8.2
20
+ - Apache Web Server
21
+ - Docker
22
+
23
+ ## Local Development
24
+
25
+ ### Run with Docker
26
+
27
+ ```bash
28
+ # Build the image
29
+ docker build -t my-webapp .
30
+
31
+ # Run the container
32
+ docker run -p 7860:7860 my-webapp
33
+ ```
34
+
35
+ Visit http://localhost:7860
36
+
37
+ ### File Structure
38
+
39
+ ```
40
+ .
41
+ ├── Dockerfile
42
+ ├── README.md
43
+ ├── .gitignore
44
+ ├── .dockerignore
45
+ └── public/
46
+ ├── index.html
47
+ ├── styles.css
48
+ ├── script.js
49
+ ├── api.php
50
+ └── process.php
51
+ ```
52
+
53
+ ## Deployment
54
+
55
+ This app is automatically deployed to Hugging Face Spaces from GitHub.
56
+
57
+ Live URL: [Your Space URL will be here]
58
+
59
+ ## License
60
+
61
+ MIT
SETUP.md ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Setup Instructions
2
+
3
+ ## Complete Step-by-Step Guide
4
+
5
+ ### Part 1: Create GitHub Repository
6
+
7
+ 1. **Create a new repository on GitHub:**
8
+ - Go to https://github.com/new
9
+ - Repository name: `my-webapp-hf` (or your choice)
10
+ - Make it **Public** (easier for HF Spaces)
11
+ - ✅ Initialize with README (optional, we have our own)
12
+ - Click **Create repository**
13
+
14
+ 2. **Clone the repository to your local machine:**
15
+ ```bash
16
+ git clone https://github.com/YOUR_USERNAME/my-webapp-hf.git
17
+ cd my-webapp-hf
18
+ ```
19
+
20
+ 3. **Copy all the files from this project** into your local repository folder
21
+
22
+ 4. **Commit and push to GitHub:**
23
+ ```bash
24
+ git add .
25
+ git commit -m "Initial commit: Web app with HTML, CSS, JS, PHP and Docker"
26
+ git push origin main
27
+ ```
28
+
29
+ ---
30
+
31
+ ### Part 2: Create Hugging Face Space
32
+
33
+ 1. **Go to Hugging Face Spaces:**
34
+ - Visit https://huggingface.co/spaces
35
+ - Click **Create new Space**
36
+
37
+ 2. **Configure the Space:**
38
+ - **Owner:** Your HF username
39
+ - **Space name:** `my-webapp-hf` (or match your GitHub repo name)
40
+ - **License:** Choose one (e.g., MIT)
41
+ - **Select SDK:** Choose **Docker**
42
+ - **Space hardware:** CPU basic (free tier)
43
+ - **Visibility:** Public
44
+ - Click **Create Space**
45
+
46
+ 3. **Import from GitHub (Option A - Easier):**
47
+ - On the Space page, look for **Settings**
48
+ - Click **Settings** → **Sync with GitHub**
49
+ - Authorize Hugging Face to access your GitHub
50
+ - Select your repository
51
+ - Click **Import**
52
+ - HF will clone your repo and build automatically
53
+
54
+ ---
55
+
56
+ ### Part 3: Set Up Auto-Sync (GitHub → Hugging Face)
57
+
58
+ 1. **Get your Hugging Face Token:**
59
+ - Go to https://huggingface.co/settings/tokens
60
+ - Click **New token**
61
+ - Name: `GitHub Sync Token`
62
+ - Role: **Write**
63
+ - Click **Generate**
64
+ - **Copy the token** (save it securely)
65
+
66
+ 2. **Add the token to GitHub Secrets:**
67
+ - Go to your GitHub repo settings
68
+ - **Secrets and variables** → **Actions**
69
+ - Click **New repository secret**
70
+ - Name: `HF_TOKEN`
71
+ - Value: paste your HF token
72
+ - Click **Add secret**
73
+
74
+ 3. **Update the GitHub Action workflow:**
75
+ - Edit `.github/workflows/sync-to-hf.yml`
76
+ - Replace `NLarchive` with your GitHub username
77
+ - Replace `YOUR_SPACE_NAME` with your actual space name
78
+ - Commit and push
79
+
80
+ 4. **Verify the Action:**
81
+ - Go to your GitHub repo → **Actions** tab
82
+ - You should see "Sync to Hugging Face Space" workflow
83
+ - On future pushes to `main`, changes will auto-deploy to HF
84
+
85
+ ---
86
+
87
+ ### Part 4: Test Locally
88
+
89
+ ```bash
90
+ # Build the Docker image
91
+ docker build -t my-webapp .
92
+
93
+ # Run the container
94
+ docker run -p 7860:7860 my-webapp
95
+
96
+ # Visit http://localhost:7860 in your browser
97
+ ```
98
+
99
+ ---
100
+
101
+ ### Part 5: Verify on Hugging Face
102
+
103
+ 1. Go to your Space: `https://huggingface.co/spaces/YOUR_USERNAME/my-webapp-hf`
104
+ 2. Check **Logs** or **Build logs** for any errors
105
+ 3. Wait for Docker build to complete (2-5 minutes on first build)
106
+ 4. Once running, click on your Space URL
107
+ 5. Test all features:
108
+ - Click the "Click Me" button (tests JavaScript)
109
+ - Check PHP content loads
110
+ - Submit the form
111
+
112
+ ---
113
+
114
+ ## Project Structure
115
+
116
+ ```
117
+ my-webapp-hf/
118
+ ├── Dockerfile # Docker configuration for Apache + PHP 8.2
119
+ ├── README.md # Project documentation
120
+ ├── .gitignore # Git ignore rules
121
+ ├── .dockerignore # Docker ignore rules
122
+ ├── .github/
123
+ │ └── workflows/
124
+ │ └── sync-to-hf.yml # GitHub Action for auto-sync
125
+ └── public/ # Web root (served by Apache)
126
+ ├── index.html # Main HTML page
127
+ ├── styles.css # Styling
128
+ ├── script.js # JavaScript functionality
129
+ ├── api.php # API endpoint for dynamic content
130
+ └── process.php # Form processing endpoint
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Key Features
136
+
137
+ ✅ **Modular Architecture:** Each file has a single responsibility
138
+ ✅ **Maintainable Code:** Clean, well-organized structure
139
+ ✅ **Plug-and-play:** Easy to add new features or APIs
140
+ ✅ **Production Ready:** Proper headers, error handling, security basics
141
+ ✅ **Responsive Design:** Works on mobile and desktop
142
+ ✅ **Full Stack:** HTML + CSS + JavaScript + PHP
143
+ ✅ **Docker Support:** Single command deployment
144
+ ✅ **Auto-Sync:** Changes to GitHub automatically deploy to HF Spaces
145
+
146
+ ---
147
+
148
+ ## Troubleshooting
149
+
150
+ | Issue | Solution |
151
+ |-------|----------|
152
+ | 502 Bad Gateway | Docker still building, wait 2-5 minutes |
153
+ | Build failed | Check Docker build logs for errors |
154
+ | PHP not working | Verify files are in `public/` folder |
155
+ | Page not loading | Ensure port 7860 is used in Dockerfile |
156
+ | Auto-sync not working | Check GitHub Actions logs, verify HF_TOKEN secret |
157
+
158
+ ---
159
+
160
+ ## Quick Commands
161
+
162
+ ```bash
163
+ # Local Docker testing
164
+ docker build -t my-webapp .
165
+ docker run -p 7860:7860 my-webapp
166
+
167
+ # Push to GitHub
168
+ git add .
169
+ git commit -m "Your message"
170
+ git push origin main
171
+
172
+ # Manual push to HF Spaces
173
+ git remote add hf https://huggingface.co/spaces/YOUR_USERNAME/my-webapp-hf
174
+ git push hf main
175
+ ```
176
+
177
+ ---
178
+
179
+ For detailed instructions, see README.md
public/api.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ header('Content-Type: application/json');
3
+ header('Access-Control-Allow-Origin: *');
4
+
5
+ $response = [
6
+ 'message' => 'PHP is working correctly! ✓',
7
+ 'timestamp' => date('Y-m-d H:i:s'),
8
+ 'random' => rand(1, 1000),
9
+ 'php_version' => phpversion(),
10
+ 'server' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'
11
+ ];
12
+
13
+ echo json_encode($response);
14
+ ?>
public/index.html ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>My Hugging Face Space</title>
7
+ <link rel="stylesheet" href="styles.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <header>
12
+ <h1>Welcome to My Web App</h1>
13
+ <p class="subtitle">Running on Hugging Face Spaces with Docker</p>
14
+ </header>
15
+
16
+ <main>
17
+ <section class="card">
18
+ <h2>Static Content</h2>
19
+ <p>This is a simple HTML page styled with CSS.</p>
20
+ <button id="testButton">Click Me (JS Test)</button>
21
+ <p id="jsOutput"></p>
22
+ </section>
23
+
24
+ <section class="card">
25
+ <h2>PHP Dynamic Content</h2>
26
+ <div id="phpContent">
27
+ <p>Loading PHP content...</p>
28
+ </div>
29
+ <button id="loadPhp">Reload PHP Data</button>
30
+ </section>
31
+
32
+ <section class="card">
33
+ <h2>Form Example</h2>
34
+ <form id="testForm">
35
+ <input type="text" id="nameInput" placeholder="Enter your name" required>
36
+ <button type="submit">Submit to PHP</button>
37
+ </form>
38
+ <div id="formResponse"></div>
39
+ </section>
40
+ </main>
41
+
42
+ <footer>
43
+ <p>Synced from GitHub to Hugging Face Spaces</p>
44
+ </footer>
45
+ </div>
46
+
47
+ <script src="script.js"></script>
48
+ </body>
49
+ </html>
public/process.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ header('Content-Type: application/json');
3
+ header('Access-Control-Allow-Origin: *');
4
+
5
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
6
+ $name = isset($_POST['name']) ? htmlspecialchars($_POST['name']) : 'Guest';
7
+
8
+ $response = [
9
+ 'success' => true,
10
+ 'greeting' => "Hello, {$name}! Your form was processed by PHP.",
11
+ 'timestamp' => date('Y-m-d H:i:s'),
12
+ 'name_length' => strlen($name)
13
+ ];
14
+ } else {
15
+ $response = [
16
+ 'success' => false,
17
+ 'error' => 'Only POST requests are accepted'
18
+ ];
19
+ }
20
+
21
+ echo json_encode($response);
22
+ ?>
public/script.js ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // JavaScript functionality
2
+ document.addEventListener('DOMContentLoaded', function() {
3
+
4
+ // Button click test
5
+ const testButton = document.getElementById('testButton');
6
+ const jsOutput = document.getElementById('jsOutput');
7
+
8
+ testButton.addEventListener('click', function() {
9
+ const now = new Date().toLocaleString();
10
+ jsOutput.textContent = `✓ JavaScript is working! Clicked at: ${now}`;
11
+ jsOutput.style.display = 'block';
12
+ });
13
+
14
+ // Load PHP content
15
+ function loadPhpContent() {
16
+ const phpContent = document.getElementById('phpContent');
17
+
18
+ fetch('api.php')
19
+ .then(response => response.json())
20
+ .then(data => {
21
+ phpContent.innerHTML = `
22
+ <p><strong>Server Message:</strong> ${data.message}</p>
23
+ <p><strong>Server Time:</strong> ${data.timestamp}</p>
24
+ <p><strong>Random Number:</strong> ${data.random}</p>
25
+ `;
26
+ })
27
+ .catch(error => {
28
+ phpContent.innerHTML = `<p style="color: red;">Error loading PHP: ${error.message}</p>`;
29
+ });
30
+ }
31
+
32
+ // Load PHP on page load
33
+ loadPhpContent();
34
+
35
+ // Reload PHP button
36
+ document.getElementById('loadPhp').addEventListener('click', loadPhpContent);
37
+
38
+ // Form submission
39
+ const testForm = document.getElementById('testForm');
40
+ const formResponse = document.getElementById('formResponse');
41
+
42
+ testForm.addEventListener('submit', function(e) {
43
+ e.preventDefault();
44
+
45
+ const nameInput = document.getElementById('nameInput');
46
+ const formData = new FormData();
47
+ formData.append('name', nameInput.value);
48
+
49
+ fetch('process.php', {
50
+ method: 'POST',
51
+ body: formData
52
+ })
53
+ .then(response => response.json())
54
+ .then(data => {
55
+ formResponse.innerHTML = `
56
+ <p><strong>${data.greeting}</strong></p>
57
+ <p>Processed at: ${data.timestamp}</p>
58
+ `;
59
+ formResponse.style.display = 'block';
60
+ nameInput.value = '';
61
+ })
62
+ .catch(error => {
63
+ formResponse.innerHTML = `<p style="color: red;">Error: ${error.message}</p>`;
64
+ });
65
+ });
66
+ });
public/styles.css ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
9
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
+ min-height: 100vh;
11
+ padding: 20px;
12
+ color: #333;
13
+ }
14
+
15
+ .container {
16
+ max-width: 900px;
17
+ margin: 0 auto;
18
+ }
19
+
20
+ header {
21
+ text-align: center;
22
+ color: white;
23
+ padding: 40px 20px;
24
+ margin-bottom: 30px;
25
+ }
26
+
27
+ header h1 {
28
+ font-size: 2.5em;
29
+ margin-bottom: 10px;
30
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
31
+ }
32
+
33
+ .subtitle {
34
+ font-size: 1.2em;
35
+ opacity: 0.9;
36
+ }
37
+
38
+ main {
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: 20px;
42
+ }
43
+
44
+ .card {
45
+ background: white;
46
+ border-radius: 12px;
47
+ padding: 30px;
48
+ box-shadow: 0 10px 30px rgba(0,0,0,0.2);
49
+ transition: transform 0.3s ease;
50
+ }
51
+
52
+ .card:hover {
53
+ transform: translateY(-5px);
54
+ }
55
+
56
+ .card h2 {
57
+ color: #667eea;
58
+ margin-bottom: 15px;
59
+ font-size: 1.8em;
60
+ }
61
+
62
+ .card p {
63
+ line-height: 1.6;
64
+ margin-bottom: 15px;
65
+ }
66
+
67
+ button {
68
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
69
+ color: white;
70
+ border: none;
71
+ padding: 12px 24px;
72
+ border-radius: 6px;
73
+ font-size: 1em;
74
+ cursor: pointer;
75
+ transition: opacity 0.3s ease;
76
+ margin-top: 10px;
77
+ }
78
+
79
+ button:hover {
80
+ opacity: 0.9;
81
+ }
82
+
83
+ button:active {
84
+ transform: scale(0.98);
85
+ }
86
+
87
+ #jsOutput, #formResponse {
88
+ margin-top: 15px;
89
+ padding: 15px;
90
+ background: #f0f0f0;
91
+ border-radius: 6px;
92
+ min-height: 20px;
93
+ font-weight: bold;
94
+ color: #667eea;
95
+ }
96
+
97
+ #phpContent {
98
+ padding: 15px;
99
+ background: #f9f9f9;
100
+ border-radius: 6px;
101
+ border-left: 4px solid #667eea;
102
+ margin-bottom: 10px;
103
+ }
104
+
105
+ form {
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: 10px;
109
+ }
110
+
111
+ input[type="text"] {
112
+ padding: 12px;
113
+ border: 2px solid #ddd;
114
+ border-radius: 6px;
115
+ font-size: 1em;
116
+ transition: border-color 0.3s ease;
117
+ }
118
+
119
+ input[type="text"]:focus {
120
+ outline: none;
121
+ border-color: #667eea;
122
+ }
123
+
124
+ footer {
125
+ text-align: center;
126
+ color: white;
127
+ padding: 30px 20px;
128
+ margin-top: 30px;
129
+ opacity: 0.9;
130
+ }
131
+
132
+ @media (max-width: 600px) {
133
+ header h1 {
134
+ font-size: 2em;
135
+ }
136
+
137
+ .card {
138
+ padding: 20px;
139
+ }
140
+ }