8 Commits
0.0.6 ... 0.0.8

Author SHA1 Message Date
69a9e8000c changed http to https
All checks were successful
continuous-integration/drone/tag Build is passing
2025-10-11 22:34:32 +05:30
6afbc899e1 always restart docker container 2025-10-11 22:29:25 +05:30
fde6be3b18 only run drone on pushing tag 2025-10-11 22:25:01 +05:30
d27b793cd4 scroll in ServiceList 2025-10-11 22:19:18 +05:30
2cdee4a028 fixed maxHeight for ServiceList parent Card as 50vh 2025-10-11 22:17:49 +05:30
081e3bf2b7 removed stray code 2025-10-11 22:15:25 +05:30
e4f40811b6 ident fixes and config 2025-10-11 15:23:51 +05:30
69081b846a enabled pointer events for clicks on servives
Some checks failed
continuous-integration/drone/tag Build is failing
continuous-integration/drone/push Build is passing
2025-10-11 01:11:42 +05:30
5 changed files with 160 additions and 127 deletions

View File

@@ -80,11 +80,10 @@ steps:
--name homepage \ --name homepage \
-p 3001:3000 \ -p 3001:3000 \
-e NODE_ENV=production \ -e NODE_ENV=production \
--restart always \
apps/homepage:$IMAGE_TAG apps/homepage:$IMAGE_TAG
# Trigger rules # Trigger rules
trigger: trigger:
event: event:
- push
- tag - tag
- custom

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@@ -1,41 +1,49 @@
import React from 'react'; import React from 'react';
import Box from '@mui/material/Box';
import {Grid, Paper, Link, Typography} from '@mui/material'; import {Grid, Paper, Link, Typography} from '@mui/material';
interface ServiceList { interface ServiceList {
name: string; name: string;
url: string; url: string;
desc: string; desc: string;
external?: boolean; external?: boolean;
} }
interface ServiceListProps { interface ServiceListProps {
serviceList: ServiceList[]; serviceList: ServiceList[];
} }
const ServiceList: React.FC<ServiceListProps> = ({serviceList}) => { const ServiceList: React.FC<ServiceListProps> = ({serviceList}) => {
return ( return (
<Grid container spacing={3} justifyContent="center"> <Box
{serviceList.map((s) => ( sx={{
<Paper flex: 1,
elevation={3} overflowY: 'auto', // ✅ Scroll only inside this
sx={{p: 2, textAlign: "center", bgcolor: "#2d2d2d", borderRadius: 2}} }}
> >
<Link <Grid container spacing={3} justifyContent="center">
href={s.url} {serviceList.map((s) => (
target={s.external ? "_blank" : undefined} <Paper
rel="noopener" elevation={3}
underline="none" sx={{p: 2, textAlign: "center", bgcolor: "#2d2d2d", borderRadius: 2}}
sx={{fontSize: 18, fontWeight: "bold", color: "success.main"}} >
> <Link
{s.name} href={s.url}
</Link> target={s.external ? "_blank" : undefined}
<Typography variant="body2" sx={{mt: 1, color: "#ccc"}}> rel="noopener"
{s.desc} underline="none"
</Typography> sx={{fontSize: 18, fontWeight: "bold", color: "success.main"}}
</Paper> >
))} {s.name}
</Grid> </Link>
); <Typography variant="body2" sx={{mt: 1, color: "#ccc"}}>
{s.desc}
</Typography>
</Paper>
))}
</Grid>
</Box>
);
}; };
export default ServiceList; export default ServiceList;

View File

@@ -5,7 +5,7 @@ import Card from '@mui/material/Card';
import MuiChip from '@mui/material/Chip'; import MuiChip from '@mui/material/Chip';
import Container from '@mui/material/Container'; import Container from '@mui/material/Container';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { styled } from '@mui/material/styles'; import {styled} from '@mui/material/styles';
import PermMediaIcon from '@mui/icons-material/PermMedia'; import PermMediaIcon from '@mui/icons-material/PermMedia';
import CodeIcon from '@mui/icons-material/Code'; import CodeIcon from '@mui/icons-material/Code';
@@ -15,33 +15,73 @@ import ServiceList from "~/components/ServiceList";
const items = [ const items = [
{ {
icon: <PermMediaIcon />, icon: <PermMediaIcon/>,
title: 'The Vox Sanctum', title: 'The Vox Sanctum',
serviceList: [ serviceList: [
{ name: "Jellyseerr", url: "http://jellyseerr.aetoskia.com", desc: "Summon films and series from the digital void.", external: true }, {
{ name: "Sonarr", url: "http://sonarr.aetoskia.com", desc: "Keep the endless chronicles of TV under iron control.", external: true }, name: "Jellyseerr",
{ name: "Radarr", url: "http://radarr.aetoskia.com", desc: "Command the legions of cinema, enforce cinematic order.", external: true }, url: "https://jellyseerr.aetoskia.com",
desc: "Summon films and series from the digital void.",
external: true
},
{
name: "Sonarr",
url: "https://sonarr.aetoskia.com",
desc: "Keep the endless chronicles of TV under iron control.",
external: true
},
{
name: "Radarr",
url: "https://radarr.aetoskia.com",
desc: "Command the legions of cinema, enforce cinematic order.",
external: true
},
], ],
description: description:
"Behold the archive of visual legends, where the eternal campaigns of film and series march forth in eternal crusade against chaos and forgetfulness.", "Behold the archive of visual legends, where the eternal campaigns of film and series march forth in eternal crusade against chaos and forgetfulness.",
}, },
{ {
icon: <CodeIcon />, icon: <CodeIcon/>,
title: 'The Forge Conclave', title: 'The Forge Conclave',
serviceList: [ serviceList: [
{ name: "Gitea", url: "http://gitea.aetoskia.com", desc: "Forge and safeguard code like a sacred relic.", external: true }, {
{ name: "Registry", url: "http://registry.aetoskia.com", desc: "Monitor core constructs of the digital empire.", external: true }, name: "Gitea",
{ name: "Drone", url: "http://drone.aetoskia.com", desc: "Automaton architect, building pipelines of perfection.", external: true }, url: "https://gitea.aetoskia.com",
desc: "Forge and safeguard code like a sacred relic.",
external: true
},
{
name: "Registry",
url: "https://registry.aetoskia.com",
desc: "Monitor core constructs of the digital empire.",
external: true
},
{
name: "Drone",
url: "https://drone.aetoskia.com",
desc: "Automaton architect, building pipelines of perfection.",
external: true
},
], ],
description: description:
"The bastion of creation — where code is forged in the fires of discipline, guarded like relics, and deployed with unyielding precision to uphold the empire's might.", "The bastion of creation — where code is forged in the fires of discipline, guarded like relics, and deployed with unyielding precision to uphold the empire's might.",
}, },
{ {
icon: <MonitorHeartIcon />, icon: <MonitorHeartIcon/>,
title: 'The Vigilant Watch', title: 'The Vigilant Watch',
serviceList: [ serviceList: [
{ name: "Portainer", url: "http://portainer.aetoskia.com", desc: "Oversee the fleet of containers with unyielding vigilance.", external: true }, {
{ name: "Traefik", url: "http://traefik.aetoskia.com", desc: "Marshal your gateways and protect the flow between realms.", external: true }, name: "Portainer",
url: "https://portainer.aetoskia.com",
desc: "Oversee the fleet of containers with unyielding vigilance.",
external: true
},
{
name: "Traefik",
url: "https://traefik.aetoskia.com",
desc: "Marshal your gateways and protect the flow between realms.",
external: true
},
], ],
description: description:
"Eyes ever watchful, guarding the realms sanctity — these sentinels oversee the flow of life and command the paths between digital dominions.", "Eyes ever watchful, guarding the realms sanctity — these sentinels oversee the flow of life and command the paths between digital dominions.",
@@ -52,10 +92,10 @@ interface ChipProps {
selected?: boolean; selected?: boolean;
} }
const Chip = styled(MuiChip)<ChipProps>(({ theme }) => ({ const Chip = styled(MuiChip)<ChipProps>(({theme}) => ({
variants: [ variants: [
{ {
props: ({ selected }) => !!selected, props: ({selected}) => !!selected,
style: { style: {
background: background:
'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))', 'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))',
@@ -79,10 +119,10 @@ interface MobileLayoutProps {
} }
export function MobileLayout({ export function MobileLayout({
selectedItemIndex, selectedItemIndex,
handleItemClick, handleItemClick,
selectedFeature, selectedFeature,
}: MobileLayoutProps) { }: MobileLayoutProps) {
if (!items[selectedItemIndex]) { if (!items[selectedItemIndex]) {
return null; return null;
} }
@@ -90,13 +130,13 @@ export function MobileLayout({
return ( return (
<Box <Box
sx={{ sx={{
display: { xs: 'flex', sm: 'none' }, display: {xs: 'flex', sm: 'none'},
flexDirection: 'column', flexDirection: 'column',
gap: 2, gap: 2,
}} }}
> >
<Box sx={{ display: 'flex', gap: 2, overflow: 'auto' }}> <Box sx={{display: 'flex', gap: 2, overflow: 'auto'}}>
{items.map(({ title }, index) => ( {items.map(({title}, index) => (
<Chip <Chip
size="medium" size="medium"
key={index} key={index}
@@ -107,14 +147,14 @@ export function MobileLayout({
))} ))}
</Box> </Box>
<Card variant="outlined"> <Card variant="outlined">
<Box sx={{ px: 2, pb: 2 }}> <Box sx={{px: 2, pb: 2}}>
<Typography <Typography
gutterBottom gutterBottom
sx={{ color: 'text.primary', fontWeight: 'medium' }} sx={{color: 'text.primary', fontWeight: 'medium'}}
> >
{selectedFeature.title} {selectedFeature.title}
</Typography> </Typography>
<Typography variant="body2" sx={{ color: 'text.secondary', mb: 1.5 }}> <Typography variant="body2" sx={{color: 'text.secondary', mb: 1.5}}>
{selectedFeature.description} {selectedFeature.description}
</Typography> </Typography>
</Box> </Box>
@@ -134,85 +174,83 @@ export default function Services() {
const selectedFeature = items[selectedItemIndex]; const selectedFeature = items[selectedItemIndex];
return ( return (
<Container id="features" sx={{ bgcolor: "#1a1a1a", borderRadius: 3, p: 3, boxShadow: 6 }}> <Container id="features" sx={{bgcolor: "#1a1a1a", borderRadius: 3, p: 3, boxShadow: 6}}>
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
flexDirection: { xs: 'column', md: 'row-reverse' }, flexDirection: {xs: 'column', md: 'row-reverse'},
gap: 2, gap: 2,
}} }}
> >
<div> <Box
<Box sx={{
sx={{ display: {xs: 'none', sm: 'flex'},
display: { xs: 'none', sm: 'flex' }, flexDirection: 'column',
flexDirection: 'column', gap: 2,
gap: 2, height: '100%',
height: '100%', }}
}} >
> {items.map(({icon, title, description}, index) => (
{items.map(({ icon, title, description }, index) => ( <Box
key={index}
component={Button}
onClick={() => handleItemClick(index)}
sx={[
(theme) => ({
p: 2,
height: '100%',
width: '100%',
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.hover,
},
}),
selectedItemIndex === index && {
backgroundColor: 'action.selected',
},
]}
>
<Box <Box
key={index}
component={Button}
onClick={() => handleItemClick(index)}
sx={[ sx={[
(theme) => ({ {
p: 2,
height: '100%',
width: '100%', width: '100%',
'&:hover': { display: 'flex',
backgroundColor: (theme.vars || theme).palette.action.hover, flexDirection: 'column',
}, alignItems: 'left',
}), gap: 1,
textAlign: 'left',
textTransform: 'none',
color: 'text.secondary',
},
selectedItemIndex === index && { selectedItemIndex === index && {
backgroundColor: 'action.selected', color: 'text.primary',
}, },
]} ]}
> >
<Box <Typography variant="h6">{icon} {title}</Typography>
sx={[ <Typography variant="body2">{description}</Typography>
{
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'left',
gap: 1,
textAlign: 'left',
textTransform: 'none',
color: 'text.secondary',
},
selectedItemIndex === index && {
color: 'text.primary',
},
]}
>
<Typography variant="h6">{icon} {title}</Typography>
<Typography variant="body2">{description}</Typography>
</Box>
</Box> </Box>
))} </Box>
</Box> ))}
<MobileLayout </Box>
selectedItemIndex={selectedItemIndex} <MobileLayout
handleItemClick={handleItemClick} selectedItemIndex={selectedItemIndex}
selectedFeature={selectedFeature} handleItemClick={handleItemClick}
/> selectedFeature={selectedFeature}
</div> />
<Box <Box
sx={{ sx={{
display: { xs: 'none', sm: 'flex' }, display: {xs: 'none', sm: 'flex'},
width: { xs: '100%', md: '70%' }, width: {xs: '100%', md: '70%'},
}} }}
> >
<Card <Card
variant="outlined" variant="outlined"
sx={{ sx={{
display: { xs: 'none', sm: 'flex' }, display: {xs: 'none', sm: 'flex'},
pointerEvents: 'none', maxHeight: '50vh',
}} }}
> >
<ServiceList serviceList={selectedFeature.serviceList} /> <ServiceList serviceList={selectedFeature.serviceList} />
</Card> </Card>
</Box> </Box>
</Box> </Box>

View File

@@ -13,23 +13,6 @@ export function meta() {
]; ];
} }
const services = {
media: [
{ name: "Jellyseerr", url: "http://jellyseerr.aetoskia.com", desc: "Summon films and series from the digital void.", external: true },
{ name: "Sonarr", url: "http://sonarr.aetoskia.com", desc: "Keep the endless chronicles of TV under iron control.", external: true },
{ name: "Radarr", url: "http://radarr.aetoskia.com", desc: "Command the legions of cinema, enforce cinematic order.", external: true },
{ name: "qBit", url: "http://qbit.aetoskia.com", desc: "Torrent war engine, fetching data across the nether realms.", external: true },
],
codebase: [
{ name: "Gitea", url: "http://gitea.aetoskia.com", desc: "Forge and safeguard code like a sacred relic.", external: true },
{ name: "Registry", url: "http://registry.aetoskia.com", desc: "Monitor core constructs of the digital empire.", external: true },
{ name: "Drone", url: "http://drone.aetoskia.com", desc: "Automaton architect, building pipelines of perfection.", external: true },
],
monitoring: [
{ name: "Portainer", url: "http://portainer.aetoskia.com", desc: "Oversee the fleet of containers with unyielding vigilance.", external: true },
],
};
export default function Home() { export default function Home() {
return ( return (
<Container <Container