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 > GitHub to Dockerfile Generator</ title >
7
+ < script src ="https://cdn.tailwindcss.com "> </ script >
8
+ < style >
9
+ .loader {
10
+ border : 8px solid # fff4da ;
11
+ border-top : 8px solid # ffc480 ;
12
+ border-radius : 50% ;
13
+ width : 64px ;
14
+ height : 64px ;
15
+ animation : spin 1s linear infinite;
16
+ }
17
+ @keyframes spin {
18
+ 0% { transform : rotate (0deg ); }
19
+ 100% { transform : rotate (360deg ); }
20
+ }
21
+ </ style >
22
+ </ head >
23
+ < body class ="bg-[#FFFDF8] min-h-screen ">
24
+ <!-- Header -->
25
+ < header class ="border-b-[3px] border-gray-900 ">
26
+ < div class ="max-w-4xl mx-auto px-4 py-4 ">
27
+ < h1 class ="text-3xl font-bold tracking-tight ">
28
+ < span class ="text-gray-900 "> GitHub</ span >
29
+ < span class ="text-[#FE4A60] "> 2</ span >
30
+ < span class ="text-[#5CF1A4] "> Dockerfile</ span >
31
+ </ h1 >
32
+ </ div >
33
+ </ header >
34
+
35
+ <!-- Main Content -->
36
+ < main class ="max-w-4xl mx-auto px-4 py-8 ">
37
+ <!-- Hero Section -->
38
+ < div class ="mb-8 text-center ">
39
+ < h2 class ="text-4xl md:text-6xl font-bold tracking-tighter mb-4 ">
40
+ Generate Dockerfiles
41
+ < br >
42
+ from GitHub repos
43
+ </ h2 >
44
+ < p class ="text-gray-600 text-lg max-w-2xl mx-auto ">
45
+ Paste any GitHub repository URL and get an AI-generated Dockerfile
46
+ tailored to your project's technology stack.
47
+ </ p >
48
+ </ div >
49
+
50
+ <!-- Error Message -->
51
+ {% if error %}
52
+ < div class ="mb-6 p-4 bg-red-50 border-[3px] border-red-500 rounded-lg text-red-700 ">
53
+ {{ error }}
54
+ </ div >
55
+ {% endif %}
56
+
57
+ <!-- Input Form -->
58
+ < div class ="relative mb-8 ">
59
+ < div class ="w-full h-full absolute inset-0 bg-gray-900 rounded-xl translate-y-2 translate-x-2 "> </ div >
60
+ < div class ="rounded-xl relative z-20 p-8 border-[3px] border-gray-900 bg-[#fff4da] ">
61
+ < form method ="post " class ="flex flex-col md:flex-row gap-4 ">
62
+ < div class ="relative flex-1 ">
63
+ < div class ="w-full h-full rounded bg-gray-900 translate-y-1 translate-x-1 absolute inset-0 z-10 "> </ div >
64
+ < input
65
+ type ="url "
66
+ name ="repo_url "
67
+ value ="{{ repo_url }} "
68
+ placeholder ="https://github.com/username/repository "
69
+ required
70
+ class ="border-[3px] w-full relative z-20 border-gray-900 placeholder-gray-600 text-lg font-medium focus:outline-none py-3.5 px-6 rounded "
71
+ >
72
+ </ div >
73
+ < div class ="relative group ">
74
+ < div class ="w-full h-full rounded bg-gray-800 translate-y-1 translate-x-1 absolute inset-0 z-10 "> </ div >
75
+ < button
76
+ type ="submit "
77
+ class ="py-3.5 rounded px-8 group-hover:-translate-y-px group-hover:-translate-x-px ease-out duration-300 z-20 relative w-full md:w-auto border-[3px] border-gray-900 font-medium bg-[#ffc480] tracking-wide text-lg text-gray-900 "
78
+ >
79
+ Generate Dockerfile
80
+ </ button >
81
+ </ div >
82
+ </ form >
83
+ </ div >
84
+ </ div >
85
+
86
+ <!-- Loading State -->
87
+ {% if loading %}
88
+ < div class ="relative ">
89
+ < div class ="w-full h-full absolute inset-0 bg-black rounded-xl translate-y-2 translate-x-2 "> </ div >
90
+ < div class ="bg-[#fafafa] rounded-xl border-[3px] border-gray-900 p-8 relative z-20 flex flex-col items-center space-y-4 ">
91
+ < div class ="loader "> </ div >
92
+ < p class ="text-lg font-bold text-gray-900 "> Analyzing repository and generating Dockerfile...</ p >
93
+ < p class ="text-sm text-gray-600 "> This may take a few moments</ p >
94
+ </ div >
95
+ </ div >
96
+ {% endif %}
97
+
98
+ <!-- Results -->
99
+ {% if result %}
100
+ < div class ="relative ">
101
+ < div class ="w-full h-full absolute inset-0 bg-gray-900 rounded-xl translate-y-2 translate-x-2 "> </ div >
102
+ < div class ="bg-[#fafafa] rounded-xl border-[3px] border-gray-900 p-6 relative z-20 space-y-6 ">
103
+
104
+ <!-- Project Info -->
105
+ < div class ="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6 ">
106
+ < div class ="bg-[#fff4da] border-[3px] border-gray-900 rounded p-4 ">
107
+ < h3 class ="font-bold text-gray-900 "> Project</ h3 >
108
+ < p class ="text-sm "> {{ result.project_name }}</ p >
109
+ </ div >
110
+ < div class ="bg-[#fff4da] border-[3px] border-gray-900 rounded p-4 ">
111
+ < h3 class ="font-bold text-gray-900 "> Technology Stack</ h3 >
112
+ < p class ="text-sm "> {{ result.technology_stack }}</ p >
113
+ </ div >
114
+ < div class ="bg-[#fff4da] border-[3px] border-gray-900 rounded p-4 ">
115
+ < h3 class ="font-bold text-gray-900 "> Repository Size</ h3 >
116
+ < p class ="text-sm "> {{ result.repo_info.file_count }} files ({{ result.repo_info.size_mb }} MB)</ p >
117
+ </ div >
118
+ </ div >
119
+
120
+ <!-- Dockerfile -->
121
+ < div >
122
+ < div class ="flex justify-between items-center mb-4 ">
123
+ < h3 class ="text-xl font-bold text-gray-900 "> Generated Dockerfile</ h3 >
124
+ < div class ="relative group ">
125
+ < div class ="w-full h-full rounded bg-gray-900 translate-y-1 translate-x-1 absolute inset-0 "> </ div >
126
+ < button
127
+ onclick ="copyToClipboard('dockerfile-content') "
128
+ class ="px-4 py-2 bg-[#ffc480] border-[3px] border-gray-900 text-gray-900 rounded group-hover:-translate-y-px group-hover:-translate-x-px transition-transform relative z-10 flex items-center gap-2 "
129
+ >
130
+ < svg class ="w-4 h-4 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 ">
131
+ < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3 " />
132
+ </ svg >
133
+ Copy Dockerfile
134
+ </ button >
135
+ </ div >
136
+ </ div >
137
+ < div class ="relative ">
138
+ < div class ="w-full h-full rounded bg-gray-900 translate-y-1 translate-x-1 absolute inset-0 "> </ div >
139
+ < textarea
140
+ id ="dockerfile-content "
141
+ class ="w-full p-4 bg-[#fff4da] border-[3px] border-gray-900 rounded font-mono text-sm focus:outline-none relative z-10 h-96 "
142
+ readonly
143
+ > {{ result.dockerfile }}</ textarea >
144
+ </ div >
145
+ </ div >
146
+
147
+ <!-- Docker Compose (if available) -->
148
+ {% if result.docker_compose %}
149
+ < div >
150
+ < div class ="flex justify-between items-center mb-4 ">
151
+ < h3 class ="text-xl font-bold text-gray-900 "> Suggested docker-compose.yml</ h3 >
152
+ < div class ="relative group ">
153
+ < div class ="w-full h-full rounded bg-gray-900 translate-y-1 translate-x-1 absolute inset-0 "> </ div >
154
+ < button
155
+ onclick ="copyToClipboard('docker-compose-content') "
156
+ class ="px-4 py-2 bg-[#ffc480] border-[3px] border-gray-900 text-gray-900 rounded group-hover:-translate-y-px group-hover:-translate-x-px transition-transform relative z-10 flex items-center gap-2 "
157
+ >
158
+ < svg class ="w-4 h-4 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 ">
159
+ < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3 " />
160
+ </ svg >
161
+ Copy Compose
162
+ </ button >
163
+ </ div >
164
+ </ div >
165
+ < div class ="relative ">
166
+ < div class ="w-full h-full rounded bg-gray-900 translate-y-1 translate-x-1 absolute inset-0 "> </ div >
167
+ < textarea
168
+ id ="docker-compose-content "
169
+ class ="w-full p-4 bg-[#fff4da] border-[3px] border-gray-900 rounded font-mono text-sm focus:outline-none relative z-10 h-48 "
170
+ readonly
171
+ > {{ result.docker_compose }}</ textarea >
172
+ </ div >
173
+ </ div >
174
+ {% endif %}
175
+
176
+ <!-- Reasoning & Notes -->
177
+ {% if result.reasoning or result.additional_notes %}
178
+ < div class ="grid grid-cols-1 md:grid-cols-2 gap-6 ">
179
+ {% if result.reasoning %}
180
+ < div >
181
+ < h3 class ="text-lg font-bold text-gray-900 mb-2 "> Base Image Reasoning</ h3 >
182
+ < div class ="bg-[#fff4da] border-[3px] border-gray-900 rounded p-4 ">
183
+ < p class ="text-sm "> {{ result.reasoning }}</ p >
184
+ </ div >
185
+ </ div >
186
+ {% endif %}
187
+
188
+ {% if result.additional_notes %}
189
+ < div >
190
+ < h3 class ="text-lg font-bold text-gray-900 mb-2 "> Additional Notes</ h3 >
191
+ < div class ="bg-[#fff4da] border-[3px] border-gray-900 rounded p-4 ">
192
+ < p class ="text-sm whitespace-pre-wrap "> {{ result.additional_notes }}</ p >
193
+ </ div >
194
+ </ div >
195
+ {% endif %}
196
+ </ div >
197
+ {% endif %}
198
+
199
+ </ div >
200
+ </ div >
201
+ {% endif %}
202
+ </ main >
203
+
204
+ <!-- Footer -->
205
+ < footer class ="border-t-[3px] border-gray-900 mt-auto ">
206
+ < div class ="max-w-4xl mx-auto px-4 py-4 text-center ">
207
+ < p class ="text-gray-600 text-sm ">
208
+ Generate Dockerfiles from GitHub repositories using AI
209
+ </ p >
210
+ </ div >
211
+ </ footer >
212
+
213
+ < script >
214
+ async function copyToClipboard ( elementId ) {
215
+ const element = document . getElementById ( elementId ) ;
216
+ const text = element . value || element . textContent ;
217
+
218
+ try {
219
+ await navigator . clipboard . writeText ( text ) ;
220
+ // Brief visual feedback
221
+ const button = event . target . closest ( 'button' ) ;
222
+ const originalText = button . innerHTML ;
223
+ button . innerHTML = '✓ Copied!' ;
224
+ setTimeout ( ( ) => {
225
+ button . innerHTML = originalText ;
226
+ } , 2000 ) ;
227
+ } catch ( err ) {
228
+ console . error ( 'Failed to copy: ' , err ) ;
229
+ // Fallback for older browsers
230
+ element . select ( ) ;
231
+ document . execCommand ( 'copy' ) ;
232
+ }
233
+ }
234
+ </ script >
235
+ </ body >
236
+ </ html >
0 commit comments