226226 padding : 12px 42px 12px 12px ;
227227 }
228228 }
229+
230+ /* Search Bar styling */
231+ .search-container {
232+ margin-top : 1.5rem ;
233+ margin-bottom : 1.5rem ;
234+ }
235+
236+ .search-input-wrapper {
237+ position : relative;
238+ display : flex;
239+ align-items : center;
240+ }
241+
242+ .search-icon {
243+ position : absolute;
244+ left : 1rem ;
245+ color : var (--muted );
246+ pointer-events : none;
247+ display : flex;
248+ align-items : center;
249+ justify-content : center;
250+ }
251+
252+ .search-input-wrapper input {
253+ width : 100% ;
254+ padding : 12px 16px 12px 44px ;
255+ background : var (--card );
256+ border : 1px solid var (--card-border );
257+ border-radius : 14px ;
258+ color : var (--ink );
259+ font-family : var (--font );
260+ font-size : 0.95rem ;
261+ transition : border-color 0.15s ease, box-shadow 0.15s ease;
262+ box-shadow : var (--shadow );
263+ backdrop-filter : blur (8px );
264+ }
265+
266+ .search-input-wrapper input : focus {
267+ outline : none;
268+ border-color : var (--accent );
269+ box-shadow : 0 0 0 3px rgba (252 , 216 , 70 , 0.25 );
270+ }
271+
272+ /* CLI Command Syntax Highlighting */
273+ .code-keyword { color : # 005cc5 ; font-weight : 600 ; }
274+ .code-subcommand { color : # d73a49 ; }
275+ .code-flag { color : # e36209 ; }
276+ .code-url { color : # 22863a ; text-decoration : underline; text-underline-offset : 3px ; }
277+
278+ @media (prefers-color-scheme : dark) {
279+ .code-keyword { color : # c9d1d9 ; font-weight : 600 ; }
280+ .code-subcommand { color : # ff7b72 ; }
281+ .code-flag { color : # 79c0ff ; }
282+ .code-url { color : # 85e8b4 ; text-decoration : underline; text-underline-offset : 3px ; }
283+ }
229284 </ style >
230285</ head >
231286< body >
@@ -256,14 +311,25 @@ <h2>Add this repository</h2>
256311 < div class ="card ">
257312 {{if .Signing.Enabled}}
258313 < div class ="step ">
259- < span class ="label "> < span class ="n "> 1</ span > Add the signed remote (flatpak ≥ 1.17)</ span >
314+ < span class ="label "> < span class ="n "> 1</ span > Add the signed repository (flatpak ≥ 1.17)</ span >
260315 < div class ="code "> < button class ="copy "> Copy</ button > < code > flatpak remote-add --user \
261- --signature-lookaside={{.PagesURL}}/{{.Signing.Lookaside}} \
262316 {{.RemoteName}} \
263317 {{.PagesURL}}/{{.RemoteName}}.flatpakrepo</ code > </ div >
264- < p class ="note "> The < code > .flatpakrepo</ code > embeds the GPG key and turns on < code > gpg-verify</ code > ; the lookaside flag completes signature verification in the same command .</ p >
318+ < p class ="note "> The < code > .flatpakrepo</ code > embeds the GPG key, signature lookaside, and automatically turns on < code > gpg-verify</ code > .</ p >
265319 </ div >
266320 < div class ="step ">
321+ < details style ="margin-top: 6px; ">
322+ < summary style ="cursor: pointer; color: var(--muted); font-size: 0.85rem; font-weight: 600; "> Older flatpak clients (< 1.17) setup instructions</ summary >
323+ < p class ="note " style ="margin-top: 8px; "> Older Flatpak versions cannot read the signature lookaside from the repository file directly. Run these commands to add the repository and configure verification manually:</ p >
324+ < div class ="code " style ="margin-top: 8px; "> < button class ="copy "> Copy</ button > < code > flatpak remote-add --if-not-exists --user --no-gpg-verify \
325+ {{.RemoteName}} \
326+ oci+{{.PagesURL}}</ code > </ div >
327+ < div class ="code " style ="margin-top: 8px; "> < button class ="copy "> Copy</ button > < code > flatpak remote-modify --user \
328+ --signature-lookaside={{.PagesURL}}/{{.Signing.Lookaside}} \
329+ {{.RemoteName}}</ code > </ div >
330+ </ details >
331+ </ div >
332+ < div class ="step " style ="margin-top: 18px; ">
267333 < span class ="label "> < span class ="n "> 2</ span > Install an app</ span >
268334 < p class ="note "> Pick any app below, or install by ID once the remote is added.</ p >
269335 </ div >
@@ -272,10 +338,6 @@ <h2>Add this repository</h2>
272338 < a class ="btn ghost " href ="index/static " target ="_blank " rel ="noopener "> View OCI index</ a >
273339 < a class ="btn ghost " href ="{{.Signing.PublicKey}} " download > Public key</ a >
274340 </ div >
275- < p class ="note " style ="margin-top:14px; "> Adding the repository through a software center can't carry the signature lookaside. After a GUI add, enable verification once:</ p >
276- < div class ="code "> < button class ="copy "> Copy</ button > < code > flatpak remote-modify --user \
277- --signature-lookaside={{.PagesURL}}/{{.Signing.Lookaside}} \
278- {{.RemoteName}}</ code > </ div >
279341 {{else}}
280342 < div class ="step ">
281343 < span class ="label "> < span class ="n "> 1</ span > Add the remote</ span >
@@ -297,10 +359,22 @@ <h2>Add this repository</h2>
297359 < h2 > Apps</ h2 >
298360 {{if .Apps}}< span class ="hint "> {{len .Apps}} app{{if gt (len .Apps) 1}}s{{end}} · install per release</ span > {{end}}
299361 </ div >
362+
363+ {{if gt (len .Apps) 1}}
364+ < div class ="search-container " id ="search-wrapper ">
365+ < div class ="search-input-wrapper ">
366+ < span class ="search-icon " aria-hidden ="true ">
367+ < svg xmlns ="http://www.w3.org/2000/svg " width ="18 " height ="18 " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 " stroke-linecap ="round " stroke-linejoin ="round "> < circle cx ="11 " cy ="11 " r ="8 "> </ circle > < line x1 ="21 " y1 ="21 " x2 ="16.65 " y2 ="16.65 "> </ line > </ svg >
368+ </ span >
369+ < input type ="text " id ="app-search " placeholder ="Search applications by name, ID, or summary... " aria-label ="Search applications ">
370+ </ div >
371+ </ div >
372+ {{end}}
373+
300374 {{if .Apps}}
301375 < div class ="grid ">
302376 {{range .Apps}}
303- < article class ="card ">
377+ < article class ="card app-card " data-app-id =" {{.ID}} " data-app-name =" {{.Name}} " data-app-summary =" {{.Summary}} ">
304378 < div class ="app-head ">
305379 < span class ="app-icon " role ="img " aria-label ="{{.Name}} icon "> 🍋{{if .Icon}}< i class ="ic " hidden > {{.Icon}}</ i > {{end}}</ span >
306380 < div >
@@ -368,6 +442,7 @@ <h3>No apps published yet</h3>
368442 btn . addEventListener ( 'click' , function ( ) {
369443 var code = btn . parentElement . querySelector ( 'code' ) ;
370444 if ( ! code || ! navigator . clipboard ) return ;
445+ // Copy raw text content without HTML tags or formatting
371446 navigator . clipboard . writeText ( code . textContent ) . then ( function ( ) {
372447 var prev = btn . innerHTML ;
373448 btn . innerHTML = '✓ Copied' ;
@@ -379,6 +454,74 @@ <h3>No apps published yet</h3>
379454 } ) ;
380455 } ) ;
381456 } ) ;
457+
458+ // CLI Command Syntax Highlighting
459+ function esc ( s ) { return String ( s ) . replace ( / [ & < > " ' ] / g, function ( c ) { return { '&' :'&' , '<' :'<' , '>' :'>' , '"' :'"' , "'" :''' } [ c ] ; } ) ; }
460+
461+ function highlightCmd ( cmd ) {
462+ var htmlStr = esc ( cmd ) ;
463+ var urls = [ ] ;
464+ htmlStr = htmlStr . replace ( / ( (?: o c i \+ ) ? h t t p s ? : \/ \/ [ ^ \s \\ ] + | s i g s \/ [ ^ \s \\ ] + ) / g, function ( match ) {
465+ urls . push ( match ) ;
466+ return '__AETHERPAK_URL_PLACEHOLDER_' + ( urls . length - 1 ) + '__' ;
467+ } ) ;
468+ htmlStr = htmlStr . replace ( / ( ^ | \s ) ( - - ? [ a - z A - Z 0 - 9 - ] + ) / g, '$1<span class="code-flag">$2</span>' ) ;
469+ htmlStr = htmlStr . replace ( / ( ^ | \s ) ( f l a t p a k ) \b / g, '$1<span class="code-keyword">$2</span>' ) ;
470+ htmlStr = htmlStr . replace ( / \b ( i n s t a l l | r e m o t e - a d d | r e m o t e - m o d i f y ) \b / g, '<span class="code-subcommand">$1</span>' ) ;
471+ for ( var i = 0 ; i < urls . length ; i ++ ) {
472+ htmlStr = htmlStr . replace ( '__AETHERPAK_URL_PLACEHOLDER_' + i + '__' , '<span class="code-url">' + urls [ i ] + '</span>' ) ;
473+ }
474+ return htmlStr ;
475+ }
476+
477+ document . querySelectorAll ( '.code code' ) . forEach ( function ( el ) {
478+ el . innerHTML = highlightCmd ( el . textContent ) ;
479+ } ) ;
480+
481+ // Search and filter logic
482+ var searchInput = document . getElementById ( 'app-search' ) ;
483+ if ( searchInput ) {
484+ searchInput . addEventListener ( 'input' , function ( e ) {
485+ var query = e . target . value . toLowerCase ( ) . trim ( ) ;
486+ var cards = document . querySelectorAll ( '.grid > .app-card' ) ;
487+ var visibleCount = 0 ;
488+
489+ cards . forEach ( function ( card ) {
490+ var name = card . getAttribute ( 'data-app-name' ) . toLowerCase ( ) ;
491+ var id = card . getAttribute ( 'data-app-id' ) . toLowerCase ( ) ;
492+ var summary = ( card . getAttribute ( 'data-app-summary' ) || '' ) . toLowerCase ( ) ;
493+
494+ if ( name . indexOf ( query ) !== - 1 || id . indexOf ( query ) !== - 1 || summary . indexOf ( query ) !== - 1 ) {
495+ card . style . display = 'block' ;
496+ visibleCount ++ ;
497+ } else {
498+ card . style . display = 'none' ;
499+ }
500+ } ) ;
501+
502+ var emptySearch = document . getElementById ( 'empty-search' ) ;
503+ if ( visibleCount === 0 ) {
504+ if ( ! emptySearch ) {
505+ emptySearch = document . createElement ( 'div' ) ;
506+ emptySearch . id = 'empty-search' ;
507+ emptySearch . className = 'card empty' ;
508+ emptySearch . style . marginTop = '1.5rem' ;
509+ emptySearch . innerHTML = '<span class="mark" aria-hidden="true">🍋</span><h3>No matching applications</h3><p>Try searching for a different keyword or app ID.</p>' ;
510+ document . querySelector ( '.grid' ) . appendChild ( emptySearch ) ;
511+ }
512+ } else {
513+ if ( emptySearch ) emptySearch . remove ( ) ;
514+ }
515+ } ) ;
516+
517+ // Focus search input when "/" is pressed
518+ document . addEventListener ( 'keydown' , function ( e ) {
519+ if ( e . key === '/' && document . activeElement . tagName !== 'INPUT' && document . activeElement . tagName !== 'TEXTAREA' ) {
520+ e . preventDefault ( ) ;
521+ searchInput . focus ( ) ;
522+ }
523+ } ) ;
524+ }
382525 </ script >
383526</ body >
384527</ html >
0 commit comments