11<style scoped>
2- .default-soft {
2+ .default-soft {
33 background : rgba (101 , 117 , 133 , 0.16 );
44 border-color : #3c3f44 ;
55}
66
77/* Purple checkboxes */
88input [type = " checkbox" ] {
9- accent-color : #9333ea ; /* purple-600 */
9+ accent-color : #9333ea ;
10+ /* purple-600 */
1011}
1112
1213.dark input [type = " checkbox" ] {
13- accent-color : #8b5cf6 ; /* purple-500 */
14+ accent-color : #8b5cf6 ;
15+ /* purple-500 */
1416}
1517
1618.search {
@@ -33,7 +35,8 @@ input[type="checkbox"] {
3335@media (max-width : 640px ) {
3436 .search {
3537 padding : 10px 12px ;
36- font-size : 16px ; /* Prevents zoom on iOS */
38+ font-size : 16px ;
39+ /* Prevents zoom on iOS */
3740 }
3841}
3942
@@ -83,23 +86,23 @@ input[type="checkbox"] {
8386 flex-direction : row ;
8487 gap : 1rem ;
8588 }
86-
89+
8790 .input-container .search {
8891 max-width : 20rem ;
8992 }
90-
93+
9194 .input-container .button-group {
9295 flex-direction : row ;
9396 }
94-
97+
9598 .input-container .select {
9699 width : 12rem ;
97100 }
98-
101+
99102 .input-container .add-service-btn {
100103 width : auto ;
101104 }
102-
105+
103106 .dropdown-content {
104107 left : 0 ;
105108 width : 12rem ;
@@ -112,7 +115,7 @@ input[type="checkbox"] {
112115 font-size : 14px ;
113116 padding : 8px ;
114117 }
115-
118+
116119 .dropdown-content label {
117120 padding : 10px 8px ;
118121 }
@@ -123,7 +126,7 @@ input[type="checkbox"] {
123126 font-size : 16px ;
124127 padding : 12px ;
125128 }
126-
129+
127130 .dropdown-content label {
128131 padding : 12px 10px ;
129132 }
@@ -1945,12 +1948,12 @@ const toggleCategory = (category: string) => {
19451948 selectedCategories .value = [' All' ]
19461949 return
19471950 }
1948-
1951+
19491952 // Remove 'All' if it's currently selected and we're selecting a specific category
19501953 if (selectedCategories .value .includes (' All' )) {
19511954 selectedCategories .value = selectedCategories .value .filter (c => c !== ' All' )
19521955 }
1953-
1956+
19541957 const index = selectedCategories .value .indexOf (category )
19551958 if (index === - 1 ) {
19561959 // Category not found, add it
@@ -1965,14 +1968,6 @@ const toggleCategory = (category: string) => {
19651968 }
19661969}
19671970
1968- const navigateTo = (path : string , external : boolean = false ) => {
1969- if (external ) {
1970- window .location .href = path
1971- } else {
1972- window .location .href = ` /docs/${path } `
1973- }
1974- }
1975-
19761971// Enhanced image fallback composable with preloading
19771972const useImageFallback = () => {
19781973 const imageStates = ref (new Map <string , ' loading' | ' loaded' | ' error' >())
@@ -2058,72 +2053,82 @@ const { preloadServices, handleImageError, hasImageError, isImageLoading, getFal
20582053 <div class =" flex flex-col" >
20592054 <div class =" input-container w-full flex flex-col justify-between gap-2" >
20602055 <input v-model =" search" type =" text" placeholder =" Search"
2061- class =" search w-full border-2 border-gray-300 dark:border-gray-600 rounded-lg py-3 sm:py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:border-purple-500 dark:focus:border-purple-400 focus:outline-none focus:ring-2 focus:ring-purple-200 dark:focus:ring-purple-800" style =" background-color : rgba (101 , 117 , 133 , 0.16 );" />
2056+ class =" search w-full border-2 border-gray-300 dark:border-gray-600 rounded-lg py-3 sm:py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:border-purple-500 dark:focus:border-purple-400 focus:outline-none focus:ring-2 focus:ring-purple-200 dark:focus:ring-purple-800"
2057+ style =" background-color : rgba (101 , 117 , 133 , 0.16 );" />
20622058 <div class =" button-group relative flex flex-col gap-2" ref =" dropdownRef" >
2063- <button @click.stop =" isOpen = !isOpen"
2064- class =" select flex items-center justify-between w-full border-2 border-gray-300 dark:border-gray-600 rounded-lg px-4 py-3 sm:px-3 sm:py-2 bg-purple-700 dark:bg-purple-600 text-gray-900 dark:text-white focus:border-purple-500 dark:focus:border-purple-400 focus:outline-none focus:ring-2 focus:ring-purple-200 dark:focus:ring-purple-800" style =" background-color : rgba (101 , 117 , 133 , 0.16 );" >
2065- <span class =" text-sm sm:text-base" >{{ selectedCategories.length === 1 ? selectedCategories[0] : `${selectedCategories.length} categories` }}</span >
2059+ <button @click.stop =" isOpen = !isOpen"
2060+ class =" select flex items-center justify-between w-full border-2 border-gray-300 dark:border-gray-600 rounded-lg px-4 py-3 sm:px-3 sm:py-2 bg-purple-700 dark:bg-purple-600 text-gray-900 dark:text-white focus:border-purple-500 dark:focus:border-purple-400 focus:outline-none focus:ring-2 focus:ring-purple-200 dark:focus:ring-purple-800"
2061+ style =" background-color : rgba (101 , 117 , 133 , 0.16 );" >
2062+ <span class =" text-sm sm:text-base" >{{ selectedCategories.length === 1 ? selectedCategories[0] :
2063+ `${selectedCategories.length} categories` }}</span >
20662064 <svg class =" w-4 h-4 ml-2 flex-shrink-0" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" >
20672065 <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M19 9l-7 7-7-7" />
20682066 </svg >
20692067 </button >
2070- <div v-if =" isOpen"
2068+ <div v-if =" isOpen"
20712069 class =" dropdown-content absolute z-10 top-full left-0 right-0 rounded-lg shadow-lg bg-white dark:!bg-[#23272f] border border-gray-200 dark:border-gray-700 max-h-60 overflow-y-auto" >
20722070 <div class =" p-2" >
2073- <label class = " flex items-center space-x-2 p-2 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700 rounded cursor-pointer " >
2074- < input type = " checkbox "
2075- :checked =" selectedCategories.includes('All')"
2071+ <label
2072+ class = " flex items-center space-x-2 p-2 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700 rounded cursor-pointer " >
2073+ < input type = " checkbox " :checked =" selectedCategories.includes('All')"
20762074 @change =" toggleCategory('All')"
20772075 class =" rounded border-gray-300 dark:border-gray-600 text-purple-600 dark:text-purple-500 focus:ring-purple-600 dark:focus:ring-purple-500 bg-white dark:bg-gray-800" >
20782076 <span class =" text-gray-900 dark:text-white" >All Categories</span >
20792077 </label >
20802078 <div v-for =" category in categories" :key =" category" class =" mt-1" >
2081- <label class = " flex items-center space-x-2 p-2 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700 rounded cursor-pointer " >
2082- < input type = " checkbox "
2083- :checked =" selectedCategories.includes(category)"
2079+ <label
2080+ class = " flex items-center space-x-2 p-2 text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700 rounded cursor-pointer " >
2081+ < input type = " checkbox " :checked =" selectedCategories.includes(category)"
20842082 @change =" toggleCategory(category)"
20852083 class =" rounded border-gray-300 dark:border-gray-600 text-purple-600 dark:text-purple-500 focus:ring-purple-600 dark:focus:ring-purple-500 bg-white dark:bg-gray-800" >
20862084 <span class =" text-gray-900 dark:text-white" >{{ category }}</span >
20872085 </label >
20882086 </div >
20892087 </div >
20902088 </div >
2091- <button @click =" navigateTo('https://github.com/coollabsio/coolify/blob/v4.x/CONTRIBUTING.md', true)" class =" add-service-btn text-gray-900 dark:text-white px-6 py-3 sm:px-4 sm:py-2 rounded-lg transition-colors text-sm sm:text-base w-full" style =" background-color : rgba (101 , 117 , 133 , 0.16 );" onmouseover =" this.style.backgroundColor='rgba(75, 85, 99, 0.25)'" onmouseout =" this.style.backgroundColor='rgba(101, 117, 133, 0.16)'" >
2089+ <a href =' https://github.com/coollabsio/coolify/blob/v4.x/CONTRIBUTING.md'
2090+ class =" add-service-btn text-gray-900 dark:text-white px-6 py-3 sm:px-4 sm:py-2 rounded-lg transition-colors text-sm sm:text-base w-full"
2091+ style =" background-color : rgba (101 , 117 , 133 , 0.16 );"
2092+ onmouseover =" this.style.backgroundColor='rgba(75, 85, 99, 0.25)'"
2093+ onmouseout =" this.style.backgroundColor='rgba(101, 117, 133, 0.16)'" >
20922094 Add Service
2093- </button >
2095+ </a >
20942096 </div >
20952097 </div >
20962098 <div class =" grid-container" >
20972099 <template v-if =" selectedCategories .includes (' All' )" >
20982100 <div v-if =" filteredCategories.length === 0" >
20992101 <h2 class =" text-2xl font-bold mb-6 text-gray-900 dark:text-gray-100" >No results found</h2 >
21002102 <div class =" services-grid not-found-grid grid grid-cols-1 gap-6" >
2101- <div class =" dark:default-soft rounded-lg shadow border border-gray-300 hover:border-purple-500 dark:hover:border-purple-400 transition-colors hover:cursor-pointer flex flex-col" >
2103+ <div
2104+ class =" dark:default-soft rounded-lg shadow border border-gray-300 hover:border-purple-500 dark:hover:border-purple-400 transition-colors hover:cursor-pointer flex flex-col" >
21022105 <div class =" w-full flex flex-col dark:default-soft rounded-b-xl p-3" >
2103- <div class =" font-bold text-md mb-1 text-gray-900 dark:text-gray-100" >Service not found</div >
2104- <div class =" text-gray-500 dark:text-gray-400 text-xs" >Try adjusting your search or category filter.</div >
2106+ <div class =" font-bold text-md mb-1 text-gray-900 dark:text-gray-100" >Service not found
2107+ </div >
2108+ <div class =" text-gray-500 dark:text-gray-400 text-xs" >Try adjusting your search or
2109+ category filter.</div >
21052110 </div >
21062111 </div >
21072112 </div >
21082113 </div >
21092114 <div v-else v-for =" category in filteredCategories" :key =" category" >
21102115 <h2 class =" text-2xl font-bold mb-6 text-gray-900 dark:text-gray-100" >{{ category }}</h2 >
21112116 <div class =" services-grid grid grid-cols-1 gap-6 rounded-lg" >
2112- <a v-for =" service in filteredServicesByCategory(category)" :key =" service.name" :href =" `/services/${service.slug}`"
2117+ <a v-for =" service in filteredServicesByCategory(category)" :key =" service.name"
2118+ :href =" `/docs/services/${service.slug}`"
21132119 class =" dark:default-soft rounded-lg shadow border border-gray-300 hover:border-purple-500 dark:hover:border-purple-400 transition-colors hover:cursor-pointer flex flex-col no-underline" >
21142120 <div class =" w-full h-full flex flex-col dark:default-soft rounded-t-xl p-3" >
2115- <div class =" font-bold text-md text-gray-900 mb-1 dark:text-gray-100" >{{ service.name }}</div >
2121+ <div class =" font-bold text-md text-gray-900 mb-1 dark:text-gray-100" >{{ service.name }}
2122+ </div >
21162123 <div class =" text-gray-500 dark:text-gray-400 text-xs" >{{ service.description }}</div >
21172124 </div >
21182125 <div class =" p-4" >
2119- <div class =" bg-white dark:default-soft w-full h-full min-h-[100px] rounded-lg flex items-center justify-center" style =" background-color : rgba (101 , 117 , 133 , 0.16 );" >
2120- <img
2121- :src =" isImageLoading(service.icon) ? getLoadingSpinner() : (hasImageError(service.icon) ? getFallbackImage() : service.icon)"
2122- :alt =" service.name"
2123- @error =" handleImageError(service.name, service.icon)"
2126+ <div class =" bg-white dark:default-soft w-full h-full min-h-[100px] rounded-lg flex items-center justify-center"
2127+ style =" background-color : rgba (101 , 117 , 133 , 0.16 );" >
2128+ <img :src =" isImageLoading(service.icon) ? getLoadingSpinner() : (hasImageError(service.icon) ? getFallbackImage() : service.icon)"
2129+ :alt =" service.name" @error =" handleImageError(service.name, service.icon)"
21242130 class =" w-auto h-8 px-2 rounded-lg transition-opacity duration-200"
2125- :class =" { 'opacity-50': isImageLoading(service.icon) }"
2126- />
2131+ :class =" { 'opacity-50': isImageLoading(service.icon) }" />
21272132 </div >
21282133 </div >
21292134 </a >
@@ -2136,29 +2141,34 @@ const { preloadServices, handleImageError, hasImageError, isImageLoading, getFal
21362141 <h2 class =" text-2xl font-bold mb-6 text-gray-900 dark:text-gray-100" >{{ category }}</h2 >
21372142 <div class =" services-grid not-found-grid grid grid-cols-1 gap-6 mb-8" >
21382143 <template v-if =" filteredServicesByCategory (category ).length === 0 " >
2139- <div class =" dark:default-soft h-auto rounded-lg shadow border border-gray-300 hover:border-purple-500 dark:hover:border-purple-400 transition-colors hover:cursor-pointer flex flex-col" >
2144+ <div
2145+ class =" dark:default-soft h-auto rounded-lg shadow border border-gray-300 hover:border-purple-500 dark:hover:border-purple-400 transition-colors hover:cursor-pointer flex flex-col" >
21402146 <div class =" w-full flex flex-col dark:default-soft rounded-b-xl p-3" >
2141- <div class =" font-bold text-md mb-1 text-gray-900 dark:text-gray-100" >No services found</div >
2142- <div class =" text-gray-500 dark:text-gray-400 text-sm" >Try adjusting your search or category filter.</div >
2147+ <div class =" font-bold text-md mb-1 text-gray-900 dark:text-gray-100" >No services
2148+ found</div >
2149+ <div class =" text-gray-500 dark:text-gray-400 text-sm" >Try adjusting your search
2150+ or category filter.</div >
21432151 </div >
21442152 </div >
21452153 </template >
21462154 <template v-else >
2147- <a v-for =" service in filteredServicesByCategory(category)" :key =" service.name" :href =" `/services/${service.slug}`"
2155+ <a v-for =" service in filteredServicesByCategory(category)" :key =" service.name"
2156+ :href =" `/docs/services/${service.slug}`"
21482157 class =" dark:default-soft rounded-lg shadow border border-gray-300 hover:border-purple-500 dark:hover:border-purple-400 transition-colors hover:cursor-pointer flex flex-col no-underline" >
21492158 <div class =" w-full h-full flex flex-col dark:default-soft rounded-b-xl p-3" >
2150- <div class =" font-bold text-md text-gray-900 mb-1 dark:text-gray-100" >{{ service.name }}</div >
2151- <div class =" text-gray-500 dark:text-gray-400 text-xs" >{{ service.description }}</div >
2159+ <div class =" font-bold text-md text-gray-900 mb-1 dark:text-gray-100" >{{
2160+ service.name }}</div >
2161+ <div class =" text-gray-500 dark:text-gray-400 text-xs" >{{ service.description }}
2162+ </div >
21522163 </div >
21532164 <div class =" p-4" >
2154- <div class =" bg-white dark:default-soft w-full h-full min-h-[100px] rounded-lg flex items-center justify-center" style = " background-color : rgba ( 101 , 117 , 133 , 0.16 ); " >
2155- < img
2156- :src =" isImageLoading(service.icon) ? getLoadingSpinner() : (hasImageError(service.icon) ? getFallbackImage() : service.icon)"
2165+ <div class =" bg-white dark:default-soft w-full h-full min-h-[100px] rounded-lg flex items-center justify-center"
2166+ style = " background-color : rgba ( 101 , 117 , 133 , 0.16 ); " >
2167+ < img :src =" isImageLoading(service.icon) ? getLoadingSpinner() : (hasImageError(service.icon) ? getFallbackImage() : service.icon)"
21572168 :alt =" service.name"
21582169 @error =" handleImageError(service.name, service.icon)"
21592170 class =" w-auto h-8 px-2 rounded-lg transition-opacity duration-200"
2160- :class =" { 'opacity-50': isImageLoading(service.icon) }"
2161- />
2171+ :class =" { 'opacity-50': isImageLoading(service.icon) }" />
21622172 </div >
21632173 </div >
21642174 </a >
0 commit comments