Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

Commit 15f77fd

Browse files
twoGiantsclaude
andcommitted
docs: add GitHub Pages landing page
Add a simple landing page with quick install instructions, a direct link to plugin.yaml, and links to the repository and container registry. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent bad8bec commit 15f77fd

4 files changed

Lines changed: 253 additions & 1 deletion

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,14 @@ jobs:
143143
- name: Setup Helm
144144
uses: azure/setup-helm@v5
145145

146-
- name: Generate deployment YAML
146+
- name: Generate deployment YAML and landing page
147147
run: |
148148
mkdir public
149149
helm template console-functions-plugin charts/openshift-console-plugin \
150150
-n console-functions-plugin \
151151
--set "plugin.image=${{ env.IMAGE }}@${{ needs.publish.outputs.digest }}" \
152152
> public/plugin.yaml
153+
cp pages/index.html public/index.html
153154
154155
- name: Upload Pages artifact
155156
uses: actions/upload-pages-artifact@v5

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ install-state.gz
5050

5151
# Built binaries
5252
/bin
53+
pages/plugin.yaml

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ A Functions-as-a-Service PoC UI for the OpenShift Web Console. Developers create
44

55
Built as an [OpenShift Console dynamic plugin](https://github.com/openshift/console/tree/main/frontend/packages/console-dynamic-plugin-sdk) using React, TypeScript, and PatternFly 6.
66

7+
**[Deploy to your cluster](https://twogiants.github.io/func-console/)**
8+
79
## Deployment on cluster
810

911
### Prerequisites

pages/index.html

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
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">
6+
<title>Serverless Functions Console Plugin</title>
7+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Sora:wght@400;600;700&display=swap" rel="stylesheet">
8+
<link href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/styles/github-dark.min.css" rel="stylesheet" integrity="sha384-wH75j6z1lH97ZOpMOInqhgKzFkAInZPPSPlZpYKYTOqsaizPvhQZmAtLcPKXpLyH" crossorigin="anonymous">
9+
<style>
10+
:root {
11+
--accent: #e86a2a;
12+
--accent-soft: rgba(232, 106, 42, 0.12);
13+
--surface: #161b22;
14+
--border-subtle: rgba(255, 255, 255, 0.06);
15+
}
16+
* { margin: 0; padding: 0; box-sizing: border-box; }
17+
body {
18+
font-family: 'Sora', sans-serif;
19+
background: #0d1117;
20+
color: #c9d1d9;
21+
min-height: 100vh;
22+
}
23+
.container {
24+
max-width: 680px;
25+
margin: 0 auto;
26+
padding: 0 1.5rem;
27+
}
28+
.hero {
29+
padding: 5rem 0 1rem;
30+
text-align: center;
31+
position: relative;
32+
}
33+
.hero::before {
34+
content: '';
35+
position: absolute;
36+
top: 0;
37+
left: 50%;
38+
transform: translateX(-50%);
39+
width: 600px;
40+
height: 400px;
41+
background: radial-gradient(ellipse, var(--accent-soft) 0%, transparent 70%);
42+
pointer-events: none;
43+
}
44+
.hero h1 {
45+
font-weight: 700;
46+
font-size: 2.4rem;
47+
letter-spacing: -0.03em;
48+
line-height: 1.2;
49+
color: #fff;
50+
}
51+
.hero .accent { color: var(--accent); }
52+
.hero p {
53+
color: #8b949e;
54+
font-size: 1.05rem;
55+
max-width: 480px;
56+
margin: 0.75rem auto 0;
57+
}
58+
.badge-version {
59+
display: inline-block;
60+
font-family: 'JetBrains Mono', monospace;
61+
font-size: 0.7rem;
62+
background: var(--accent-soft);
63+
color: var(--accent);
64+
padding: 0.25rem 0.6rem;
65+
border-radius: 20px;
66+
font-weight: 500;
67+
margin-bottom: 0.75rem;
68+
}
69+
.card {
70+
background: var(--surface);
71+
border: 1px solid var(--border-subtle);
72+
border-radius: 12px;
73+
padding: 1.5rem;
74+
margin-bottom: 0.75rem;
75+
transition: border-color 0.2s;
76+
}
77+
.card:hover { border-color: rgba(255, 255, 255, 0.1); }
78+
.card-title {
79+
font-weight: 600;
80+
font-size: 0.85rem;
81+
text-transform: uppercase;
82+
letter-spacing: 0.08em;
83+
color: #8b949e;
84+
margin-bottom: 1rem;
85+
}
86+
pre {
87+
font-family: 'JetBrains Mono', monospace;
88+
font-size: 0.82rem;
89+
line-height: 1.7;
90+
background: #0d1117;
91+
border: 1px solid var(--border-subtle);
92+
border-radius: 8px;
93+
padding: 1.2rem;
94+
margin: 0;
95+
overflow-x: auto;
96+
}
97+
.prompt {
98+
color: var(--accent);
99+
user-select: none;
100+
}
101+
.btn-row {
102+
display: flex;
103+
gap: 0.5rem;
104+
flex-wrap: wrap;
105+
}
106+
.btn {
107+
display: inline-block;
108+
font-family: 'Sora', sans-serif;
109+
font-weight: 600;
110+
font-size: 0.82rem;
111+
letter-spacing: 0.02em;
112+
padding: 0.5rem 1.2rem;
113+
border-radius: 8px;
114+
text-decoration: none;
115+
transition: all 0.2s;
116+
cursor: pointer;
117+
}
118+
.btn-accent {
119+
background: var(--accent);
120+
color: #fff;
121+
border: none;
122+
}
123+
.btn-accent:hover {
124+
background: #d45d22;
125+
transform: translateY(-1px);
126+
}
127+
.btn-ghost {
128+
background: transparent;
129+
color: #8b949e;
130+
border: 1px solid var(--border-subtle);
131+
}
132+
.btn-ghost:hover {
133+
color: #c9d1d9;
134+
border-color: rgba(255, 255, 255, 0.15);
135+
background: #1c2129;
136+
}
137+
.yaml-scroll {
138+
max-height: 420px;
139+
overflow-y: auto;
140+
border-radius: 8px;
141+
}
142+
.yaml-scroll::-webkit-scrollbar { width: 6px; }
143+
.yaml-scroll::-webkit-scrollbar-track { background: transparent; }
144+
.yaml-scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 3px; }
145+
.yaml-scroll::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.2); }
146+
.last-card { margin-bottom: 3rem; }
147+
.code-wrap { position: relative; }
148+
.copy-btn {
149+
position: absolute;
150+
top: 0.6rem;
151+
right: 0.6rem;
152+
background: transparent;
153+
border: none;
154+
color: #484f58;
155+
cursor: pointer;
156+
padding: 0.3rem;
157+
border-radius: 4px;
158+
transition: all 0.2s;
159+
line-height: 1;
160+
}
161+
.copy-btn:hover { color: #8b949e; background: rgba(255, 255, 255, 0.06); }
162+
.copy-btn.copied { color: var(--accent); }
163+
.copy-icon { width: 16px; height: 16px; }
164+
.check-icon { width: 16px; height: 16px; display: none; }
165+
.copy-btn.copied .copy-icon { display: none; }
166+
.copy-btn.copied .check-icon { display: inline; }
167+
.fade-in { animation: fadeIn 0.6s ease both; }
168+
.fade-in-delay-1 { animation-delay: 0.1s; }
169+
.fade-in-delay-2 { animation-delay: 0.2s; }
170+
.fade-in-delay-3 { animation-delay: 0.3s; }
171+
@keyframes fadeIn {
172+
from { opacity: 0; transform: translateY(12px); }
173+
to { opacity: 1; transform: translateY(0); }
174+
}
175+
</style>
176+
</head>
177+
<body>
178+
<div class="container">
179+
<div class="hero fade-in">
180+
<span class="badge-version">OpenShift Console Plugin</span>
181+
<h1>Serverless Functions<br><span class="accent">Console Plugin</span></h1>
182+
<p>Create, edit, and deploy serverless functions from the OpenShift Web Console.</p>
183+
</div>
184+
185+
<div class="card fade-in fade-in-delay-1">
186+
<h5 class="card-title">Install</h5>
187+
<div class="code-wrap">
188+
<button class="copy-btn" data-target="install-cmd" data-strip="$ ">
189+
<svg class="copy-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/></svg>
190+
<svg class="check-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg>
191+
</button>
192+
<pre><code id="install-cmd"><span class="prompt">$</span> oc new-project console-functions-plugin
193+
<span class="prompt">$</span> oc apply -f https://twogiants.github.io/func-console/plugin.yaml</code></pre>
194+
</div>
195+
</div>
196+
197+
<div class="card fade-in fade-in-delay-2">
198+
<h5 class="card-title">Resources</h5>
199+
<div class="btn-row">
200+
<a href="plugin.yaml" class="btn btn-accent">plugin.yaml</a>
201+
<a href="https://github.com/twoGiants/func-console" class="btn btn-ghost">Repository</a>
202+
<a href="https://github.com/twoGiants/func-console/pkgs/container/console-functions-plugin" class="btn btn-ghost">Container Registry</a>
203+
</div>
204+
</div>
205+
206+
<div class="card last-card fade-in fade-in-delay-3">
207+
<h5 class="card-title">plugin.yaml</h5>
208+
<div class="code-wrap">
209+
<button class="copy-btn" data-target="yaml-content">
210+
<svg class="copy-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/></svg>
211+
<svg class="check-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/></svg>
212+
</button>
213+
<div class="yaml-scroll">
214+
<pre><code id="yaml-content">Loading...</code></pre>
215+
</div>
216+
</div>
217+
</div>
218+
</div>
219+
220+
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/highlight.min.js" integrity="sha384-RH2xi4eIQ/gjtbs9fUXM68sLSi99C7ZWBRX1vDrVv6GQXRibxXLbwO2NGZB74MbU" crossorigin="anonymous"></script>
221+
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/languages/yaml.min.js" integrity="sha384-A/iMReLA0Bo3tLydBIoOQXQzYnrwL90jkHYUubrtERUGCbIuU7U0EHge0Xd2s5sr" crossorigin="anonymous"></script>
222+
<script>
223+
document.querySelectorAll('.copy-btn').forEach(btn => {
224+
btn.addEventListener('click', () => {
225+
let text = document.getElementById(btn.dataset.target).textContent;
226+
const strip = btn.dataset.strip;
227+
if (strip) {
228+
text = text.split('\n').map(l => l.startsWith(strip) ? l.slice(strip.length) : l).join('\n');
229+
}
230+
navigator.clipboard.writeText(text).then(() => {
231+
btn.classList.add('copied');
232+
setTimeout(() => { btn.classList.remove('copied'); }, 1500);
233+
});
234+
});
235+
});
236+
237+
fetch('plugin.yaml')
238+
.then(r => r.text())
239+
.then(text => {
240+
const el = document.getElementById('yaml-content');
241+
el.textContent = text;
242+
el.classList.add('language-yaml');
243+
hljs.highlightElement(el);
244+
})
245+
.catch(() => { document.getElementById('yaml-content').textContent = 'Failed to load plugin.yaml'; });
246+
</script>
247+
</body>
248+
</html>

0 commit comments

Comments
 (0)