diff --git a/components/styles/cards/desktop.tsx b/components/styles/cards/desktop.tsx index 55da40a..326e465 100644 --- a/components/styles/cards/desktop.tsx +++ b/components/styles/cards/desktop.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { CardLink, PageCard, CardStyleWrap, CardContentTitle, CardContentWarning, OnlineStatus } from '../content'; // Card Content Component for Services Page -export const CardContentService = ({ content }: { content: Service }) => { +export const ServiceCardDesktop = ({ content }: { content: Service }) => { let ret; if (content.href) { ret = ( diff --git a/components/styles/cards/mobile.tsx b/components/styles/cards/mobile.tsx index 1cdc874..796c79f 100644 --- a/components/styles/cards/mobile.tsx +++ b/components/styles/cards/mobile.tsx @@ -7,66 +7,30 @@ import { Dispatch, SetStateAction, useState } from 'react'; // needed for Online Status checks interface OnlinePropType { status: string; - active?: number; } -interface ActivePropType { - active?: number; -} -const Card = styled.div` +const Card = styled.div` position: relative; display: flex; flex-direction: column; align-items: center; - width: 10rem; - min-height: 6.5rem; + width: 30rem; + min-height: 10rem; + max-height: 15rem; // themeing border-top: 0.125rem solid; border-radius: 10px; - ${props => { - let ret; - if (props.active) { - ret = css` - backdrop-filter: blur(1rem); - margin-bottom: -6.5rem; - max-height: 12rem; - z-index: 10; - color: ${({ theme }) => theme.colors.secondary}; - border: 0.125rem solid; - border-color: ${({ theme }) => theme.colors.secondary}; - background-color: ${({ theme }) => { - let ret; - - if (theme.invertButtons) { - ret = theme.colors.backgroundAlt ? theme.colors.backgroundAlt : theme.colors.background; - } - else { - ret = theme.colors.background; - } - - return ret; - }}; - ` - } - else { - ret = css` - max-height: 6.5rem; - margin-bottom: 0rem; - color: ${({ theme }) => theme.colors.primary}; - border-color: ${({ theme }) => theme.colors.primary}; - background-color: ${({ theme }) => theme.colors.background}; - ` - } - return ret; - }} + color: ${({ theme }) => theme.colors.primary}; + border-color: ${({ theme }) => theme.colors.primary}; + background-color: ${({ theme }) => theme.colors.background}; transition-property: max-height, margin-bottom; - transition-duration: 2s, 0s; - transition-delay: 2s, 2s; + transition-duration: 0.2s, 0s; + transition-delay: 0.2s, 0.2s; ` // custom objects for CardTitle @@ -74,7 +38,7 @@ const Card = styled.div` const CardTitleWrap = styled.div` display: flex; flex-direction: row; - justify-content: center; + justify-content: space-between; align-items: center; width: 100%; flex-grow: 0.8; @@ -90,34 +54,139 @@ const CardTitleIcon = styled.div` object-fit: contain; margin-right: 0.4rem; aspect-ratio: 1; - height: 1.2rem; + height: 1.5rem; `; const CardTitleIconMirror = styled.div` - height: 1.2rem; + height: 1.5rem; aspect-ratio: 1; ` -// content visible when reduced -const CardTitle = ({ content }: { content: Service }) => { - return ( - - { - content.icon ? ( - - icon - - ) : (<>) - } - {content.name} - { - content.icon ? ( - - ) : (<>) - } - +const CardStatus = styled.p` + font-size: 0.9rem; + padding: 0.1rem; + margin: 0.5rem; + margin-right: 1.5rem; + + border-radius: 5px; + border: 0; + border-bottom: 0.125rem solid; - ) + ${({ theme }) => { + let ret; + + if (theme.backgroundImage) { + ret = css` + background-image: ${() => { + return css` + linear-gradient(${theme.colors.background}, ${theme.colors.background}), + url(${theme.backgroundImage}) + ` + }}; + background-repeat: no-repeat; + background-attachment: fixed; + background-size: cover; + background-position: 60%; + `; + } + else { + ret = css` + background-color: ${({ theme }) => theme.colors.background}; + `; + } + + return ret; + }}; + color: ${props => { + let ret; + switch (props.status) { + case "Online": + ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.online; + break; + case "Loading": + ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.loading; + break; + case "Offline": + ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.offline; + break; + default: + ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.offline; + } + return ret; + }}; +` + +const CardTitleLink = styled(Link)` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + align-self: flex-start; + margin: 0.5rem; + padding-left: 1rem; +` + +const CardTitleLinkPlaceholder = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + align-self: flex-start; + margin: 0.5rem; + padding-left: 1rem; +` + +// content visible when reduced +const CardTitle = ({ content, href }: { content: Service, href: string }) => { + let card; + + if (href) { + card = ( + + + { + content.icon ? ( + + icon + + ) : (<>) + } + {content.name} + { + content.icon ? ( + + ) : (<>) + } + + {content.status} + + + ) + } + else { + card = ( + + + { + content.icon ? ( + + icon + + ) : (<>) + } + {content.name} + { + content.icon ? ( + + ) : (<>) + } + + {content.status} + + + ) + } + return card } // custom objects for CardDescription @@ -171,9 +240,9 @@ const CardDescription = ({ content }: { content: Service }) => { return ret; } -const CardDescriptionCollapsed = styled.p` - max-height: ${props => props.active ? css`2rem` : css`0rem`}; - visibility: ${props => props.active ? css`visible` : css`hidden`}; +const CardDescriptionCollapsed = styled.p` + max-height: 0rem; + visibility: hidden; ${CardDescriptionCommon} text-align: center; @@ -181,139 +250,10 @@ const CardDescriptionCollapsed = styled.p` transition-delay: 2s; ` -// custom objects for CardFooter -//############################## - -const CardFooterStyle = styled.div` - width: 100%; - display: flex; - flex-direction: row; - justify-content: space-around; - align-items: center; - position: absolute; - bottom: -0.5rem; -` - -const CardStatus = styled.p` - font-size: 0.9rem; - padding: 0.1rem; - - border-radius: 5px; - margin: 0; - - ${props => props.active ? css` - border-top: 0; - border: 0.125rem solid; - ` : css` - border: 0; - border-top: 0.125rem solid; - `}; - - ${props => ({ theme }) => { - let ret; - - if (theme.backgroundImage) { - ret = css` - background-image: ${() => { - let image; - let gradient; - - if (props.active) { - if (theme.invertButtons && theme.colors.backgroundAlt) { - gradient = css`linear-gradient(${theme.colors.backgroundAlt}, ${theme.colors.backgroundAlt})`; - } - else { - gradient = css`linear-gradient(${theme.colors.background}, ${theme.colors.background})`; - } - } - else { - gradient = css`linear-gradient(${theme.colors.background}, ${theme.colors.background})`; - } - - image = css` - ${gradient}, - url(${theme.backgroundImage}) - ` - return image; - }}; - background-repeat: no-repeat; - background-attachment: fixed; - background-size: cover; - background-position: 60%; - `; - } - else { - ret = css` - background-color: ${({ theme }) => theme.colors.background}; - `; - } - - return ret; - }}; - color: ${props => { - let ret; - switch (props.status) { - case "Online": - ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.online; - break; - case "Loading": - ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.loading; - break; - case "Offline": - ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.offline; - break; - default: - ret = ({ theme }: { theme: DefaultTheme }) => theme.colors.offline; - } - return ret; - }}; - border-color: ${props => ({ theme }) => props.active ? theme.colors.secondary : theme.colors.primary}; -/* - padding: 0.2rem; - width: min-content; - position: absolute; - top: 100; right: 50; bottom: 0; left: 50; - offset-position: bottom 10px; - transition: color 0.15s ease, border-color 0.15s ease; -*/ -` - -const CardExpandButton = styled.button` - cursor: pointer; - height: 1.5rem; - margin: 0; - -` - -// content visble at the bottom of the card -const CardFooter = ({ expanded, setExpanded, content }: { expanded: boolean, setExpanded: Dispatch>, content: Service }) => { - let ret; - - ret = ( - - {content.status} - setExpanded(expanded => !expanded)}>{expanded ? "shrink" : "expand"} - - ) - - return ret; -} - // exported Card Elements //####################### export const ServiceCardMobile = ({ content }: { content: Service }) => { - const [expanded, setExpanded] = useState(false); - - function handleBlur(event: any) { - if (!event.currentTarget.contains(event.relatedTarget)) { - setExpanded(false); - console.log("triggered") // DEBUG - } - else { - console.log("not triggered") // DEBUG - } - } let card; @@ -321,25 +261,17 @@ export const ServiceCardMobile = ({ content }: { content: Service }) => { if (content.href) { // TODO: adjust sizes card = ( - handleBlur(event)}> - - - {content.desc1 ? content.desc1 : ""} - - - + + + ) } else { card = ( - handleBlur(event)}> -
- - {content.desc1 ? content.desc1 : ""} -
- - + + + ) } diff --git a/interfaces/CardTypes.ts b/interfaces/CardTypes.ts index 21c5ec2..59f0b2b 100644 --- a/interfaces/CardTypes.ts +++ b/interfaces/CardTypes.ts @@ -15,7 +15,6 @@ export interface Service { name: string, icon: string, href: string, - desc1?: string, desc: string, warn?: string, extLink?: string, diff --git a/pages/api/containers.tsx b/pages/api/containers.tsx index 7f6a6d2..9d9fec8 100644 --- a/pages/api/containers.tsx +++ b/pages/api/containers.tsx @@ -1,4 +1,3 @@ -import Docker from 'dockerode' import ApiSecret from '../../private/portainer_api_secret.json' import { DockerInfo } from '../../interfaces/DockerStatus'; import { ServiceLocation } from '../../interfaces/CardTypes'; diff --git a/pages/services.tsx b/pages/services.tsx index de5b066..354cd33 100644 --- a/pages/services.tsx +++ b/pages/services.tsx @@ -1,11 +1,13 @@ import Head from 'next/head' -import { Service, Status, ServiceType, ServiceLocation } from '../interfaces/CardTypes'; -import Dockerode from 'dockerode'; +import { Service, Status, ServiceType } from '../interfaces/CardTypes'; import { ReactElement } from 'react' import useSWR from 'swr'; import ServiceList from '../public/data/pages.json'; import { DockerInfo } from '../interfaces/DockerStatus'; import { CardContentService, PageContentBox, PageDescription, PageTitle } from '../components/styles/content'; +import useWindowSize from '../components/windowsize'; +import { ServiceCardMobile } from '../components/styles/cards/mobile'; +import { ServiceCardDesktop } from '../components/styles/cards/desktop'; const fetcher = (url: string) => fetch(url).then((res) => res.json()) @@ -29,7 +31,7 @@ function Services() { content = {initialData?.map((item: Service) => ( - + ))} } @@ -47,7 +49,7 @@ function Services() { content = {fullData.map((item: Service) => ( - + ))} } diff --git a/public/data/pages.json b/public/data/pages.json index 639019c..e8f6746 100644 --- a/public/data/pages.json +++ b/public/data/pages.json @@ -4,7 +4,6 @@ "name": "Nextcloud", "icon": "/icons/nextcloud-logo.svg", "href": "https://nextcloud.neshweb.net/", - "desc1": "Cloud Storage", "desc": "Self-hosted Cloud Storage Service but longer and hopefully with wrap as well as some extra just to make sure", "warn": "Note: Registration requires approval", "extLink": "https://qwant.com", @@ -27,7 +26,6 @@ "name": "Calibre Web", "icon": "/icons/calibre-logo.ico", "href": "https://calibre.neshweb.net/", - "desc1": "eBooks", "desc": "Self-hosted Ebook Library Service", "warn": "Note: Registration only via Admin", "type": "docker", @@ -38,7 +36,6 @@ "name": "PeerTube", "icon": "/icons/peertube-logo.svg", "href": "https://tube.neshweb.net/", - "desc1": "Video Platform", "desc": "Self-hosted PeerTube Instance", "warn": "Note: Registration only via Admin", "type": "docker", @@ -49,7 +46,6 @@ "name": "Mastodon", "icon": "/icons/mastodon-logo.svg", "href": "https://mastodon.neshweb.net/", - "desc1": "Twitter Alternative", "desc": "Self-hosted Mastodon Instance", "warn": "Note: Registration requires approval", "type": "docker", @@ -70,7 +66,6 @@ { "name": "File Browser", "href": "https://files.neshweb.net/", - "desc1": "Online File Explorer", "desc": "Server File Browser", "warn": "Note: Registration only via Admin", "type": "docker", @@ -81,7 +76,6 @@ "name": "Jellyfin", "icon": "/icons/jellyfin-logo.svg", "href": "https://jellyfin.neshweb.net/", - "desc1": "Movie Platform", "desc": "Open-Source, Self-Hosted Media Platform", "warn": "Note: Registration only via Admin", "type": "docker", @@ -92,7 +86,6 @@ "name": "Navidrome", "icon": "/icons/navidrome-logo.png", "href": "https://navidrome.neshweb.net/", - "desc1": "Music Service", "desc": "Open-Source, Self-Hosted Music Streaming Platform", "warn": "Note: Registration only via Admin", "type": "docker", @@ -102,7 +95,6 @@ { "name": "Picard", "href": "https://picard.neshweb.net/", - "desc1": "MP3 Tagger", "desc": "MP3 Tagger", "warn": "Note: Access only via Admin", "type": "docker", @@ -113,7 +105,6 @@ "name": "Gitlab", "icon": "/icons/gitlab-logo.svg", "href": "https://gitlab.neshweb.net/", - "desc1": "Git Hosting", "desc": "Self-hosted Git Service", "warn": "Note: Registration only via Admin", "type": "docker", @@ -124,7 +115,6 @@ "name": "Portainer", "icon": "/icons/portainer-logo.png", "href": "https://portainer.neshweb.net/", - "desc1": "Docker Management", "desc": "Docker Container Manager", "warn": "Note: Admin Only", "type": "docker", @@ -135,7 +125,6 @@ "name": "Nginx", "icon": "/icons/npm-logo.png", "href": "https://nginx.neshweb.net/", - "desc1": "Proxy Management", "desc": "Web-based Nginx Proxy Manager", "warn": "Note: Admin Only", "type": "docker", @@ -145,7 +134,6 @@ { "name": "Debug1", "href": "https://qwant.com", - "desc1": "DEBUG1", "desc": "Debug Debug Debug", "warn": "Note: Debug", "extLink": "https://qwant.com", @@ -156,7 +144,6 @@ }, { "name": "Debug2", - "desc1": "DEBUG2", "desc": "Debug Debug Debug", "warn": "Note: Debug", "extLink": "https://qwant.com",