From 3032a8495174f4f583f52c4e9429b6d4d357dc0c Mon Sep 17 00:00:00 2001 From: navewindre Date: Wed, 12 Nov 2025 06:32:24 +0100 Subject: aa --- web/src/blog.tsx | 156 ++++++++++++++++++++++++++++++++++++++++++++-- web/src/home.tsx | 10 +-- web/src/index-page.tsx | 1 + web/src/index.html | 4 +- web/src/jsx.tsx | 29 ++++++++- web/src/pkg.tsx | 140 ++++++++++------------------------------- web/src/sidebar.tsx | 5 +- web/src/util.tsx | 112 +++++++++++++++++++++++++++++++-- web/static/main.css | 164 ++++++++++++++++++++++++++++++++++++++++++------- 9 files changed, 472 insertions(+), 149 deletions(-) diff --git a/web/src/blog.tsx b/web/src/blog.tsx index 9d86657..bfef434 100644 --- a/web/src/blog.tsx +++ b/web/src/blog.tsx @@ -1,10 +1,158 @@ import $ from "jquery"; import * as JSX from "./jsx"; -import { Page } from "./components"; -import { AsciiArt } from "./ascii-art"; +import { Page, Spinner } from "./components"; +import { FtpEntry, ftpGetEntries } from "./util"; + +let entries: FtpEntry[] = []; +let reqErr = 0; + +let hljs = null; +let hljs_imported = 0; +async function importHlJs() { + if( hljs ) return; + if( hljs_imported ) return; + + hljs_imported = 1; + hljs = ( await import( 'highlight.js' ) ).default; + + const elements = $( "code" ); + elements.each( ( _, e ) => { + hljs.highlightElement( e ); + } ); +} + +function urlForHref( href: string, isdir: boolean ) { + const url = new URL( window.location.href ); + let path = url.pathname; + if( isdir ) { + if( path.endsWith( '/' ) ) { + return path + href; + } + return path + "/" + href; + } + + const file = href.slice( 0, href.lastIndexOf( "." ) ); + path = path.slice( path.indexOf( '/blog' ) + 5 ); + if( path.endsWith( '/' ) ) + return "/blog" + path + file; + else + return "/blog" + path + "/" + file; +} + +function BlogEntry( props: any ) { + const entry = props.entry as FtpEntry; + return + + { entry.name == "../" && + JSX.goUpDirectory() } class="package-entry-link"> + ../ + } + { entry.name != "../" && !entry.isdir && + JSX.navigate( urlForHref( entry.name, entry.isdir ) ) } class="package-entry-link"> + {entry.name.replace( /_/g, " " )} + } + { entry.name != "../" && entry.isdir && + JSX.navigate( urlForHref( entry.name, entry.isdir ) ) } class="package-entry-link"> + {entry.name} + } + + {entry.date} {entry.time} + +} + +function getEndpoint() { + const url = new URL( window.location.href ); + let href = url.pathname.split( "/blog" )[1]; + + if( href[0] == '/' ) { + href = href.slice( 1 ); + } + + return "posts/" + href; +} + +function populateEntries() { + if( reqErr ) { + return JSX.navigate( "/404" ); + } + + if( entries.length <= 0 ) + return setTimeout( populateEntries, 100 ); + + const target = $( "#package-entries" ).find( "table" ); + $( "#package-entries" ).find( ".spinner" ).remove(); + + for( const entry of entries ) { + target.append( ); + } +} + +async function populatePost() { + try { + const res = await fetch( "https://networkheaven.net/" + getEndpoint() + ".html" ); + const text = await res.text(); + if( text.startsWith( "" ) || text.startsWith( "" ); + const titlee = text.indexOf( "" ); + + if( titles != -1 && titlee != -1 ) { + let title = text.substring( titles + 7, titlee - 1 ); + title = title.replace( /\n/g, "" ); + $( ".page-title h3" )[0].innerText = title; + $( "title" ).html( title ); + } + + importHlJs(); + + $( "#package-entries" ).find( ".spinner" ).remove(); + $( "#package-entries" ).css( "display", "none" ); + $( "#blog-entry" ).html( text ); + $( "#blog-entry" ).css( "display", "flex" ); + $( "#back-btn" ).css( "display", "block" ); + } catch( e ) { + return populateEntries(); + } +} export default function Blog() { - return - work in progress (: + entries = []; + reqErr = 0; + setTimeout( async () => { + try { + entries = await ftpGetEntries( getEndpoint(), getEndpoint() != 'posts/' ); + } catch( e ) { + reqErr = 1; + } + } ); + + setTimeout( () => { + if( getEndpoint() == 'posts/' ) + return populateEntries(); + + populatePost(); + } ); + + return +
+

BLOG

+
+
+ +
+ + + + +
+ +
+ + } diff --git a/web/src/home.tsx b/web/src/home.tsx index 77404fd..217b7a4 100644 --- a/web/src/home.tsx +++ b/web/src/home.tsx @@ -6,19 +6,19 @@ import { AsciiArt } from "./ascii-art"; export default function Home() { return
-

NETWORKHEAVEN

+

NETWORKHEAVEN


-

- hi, im aura and this is my website. +

+ hi, im aura and this is my website. check out my blog !!!
i will add more stuff when i have time -
+
-

STEAM

+

STEAM

; } diff --git a/web/src/index-page.tsx b/web/src/index-page.tsx index 4b7ce1c..a754ef6 100644 --- a/web/src/index-page.tsx +++ b/web/src/index-page.tsx @@ -5,6 +5,7 @@ import Pkgs from "./pkg"; JSX.addRoute( "/", () => ); JSX.addRoute( "/blog", () => ); +JSX.addRoute( "/blog/*", () => ); JSX.addRoute( "/pkg", () => ); JSX.addRoute( "/pkg/*", () => ); diff --git a/web/src/index.html b/web/src/index.html index 08b8208..b14f5b5 100644 --- a/web/src/index.html +++ b/web/src/index.html @@ -2,8 +2,8 @@ - - + + networkheaven.net diff --git a/web/src/jsx.tsx b/web/src/jsx.tsx index 64a8aad..a92fc11 100644 --- a/web/src/jsx.tsx +++ b/web/src/jsx.tsx @@ -1,6 +1,7 @@ import $ from 'jquery'; const assetAttributeNames = new Set( ['data', 'srcset', 'src', 'href'] ); +let curRoute = null; export interface Route { path: string, component: Function, @@ -82,10 +83,12 @@ export function navigate( route: string ) { if( !cb ) return navigate( err404page ); - window.history.pushState( {}, null, url.href ); + if( curRoute != cb ) + window.history.pushState( {}, null, url.href ); onprenavigate(); const el = $( cb() ); + curRoute = cb; $( `#${rootId}` ).children().remove(); $( `#${rootId}` ).append( el ); @@ -104,10 +107,12 @@ export function navigateParams( route: string, params: any ) { if( !cb ) return navigate( err404page ); - window.history.pushState( {}, null, url.href ); + if( curRoute != cb ) + window.history.pushState( {}, null, url.href ); onprenavigate(); const el = $( cb() ); + curRoute = cb; $( `#${rootId}` ).children().remove(); $( `#${rootId}` ).append( el ); @@ -139,6 +144,7 @@ export function navigateParamsSilent( route: string, params: any ) { onprenavigate(); const el = $( cb() ); + curRoute = cb; $( `#${rootId}` ).children().remove(); $( `#${rootId}` ).append( el ); @@ -157,6 +163,7 @@ export function navigateSilent( route: string ) { onprenavigate(); const el = $( cb() ); + curRoute = cb; $( `#${rootId}` ).children().remove(); $( `#${rootId}` ).append( el ); @@ -174,14 +181,32 @@ export function onPopState() { if( !cb ) return navigateSilent( err404page ); + if( cb == curRoute ) + return; + onprenavigate(); const el = $( cb() ); + curRoute = cb; $( `#${rootId}` ).children().remove(); $( `#${rootId}` ).append( el ); onpostnavigate(); } +/** + * navigates to the parent directory from the current page +**/ +export function goUpDirectory() { + const url = new URL( window.location.href ); + if( url.pathname.endsWith( "/" ) ) + url.pathname = url.pathname.slice( 0, -1 ); + let idx = url.pathname.lastIndexOf( "/" ); + if( idx === -1 ) + return; + url.pathname = url.pathname.slice( 0, url.pathname.lastIndexOf( "/" ) ); + navigate( url.pathname ); +} + export function getRoutes() : Route[] { return routes; } diff --git a/web/src/pkg.tsx b/web/src/pkg.tsx index c3a6985..b1f38c9 100644 --- a/web/src/pkg.tsx +++ b/web/src/pkg.tsx @@ -1,16 +1,9 @@ import $ from "jquery"; import * as JSX from "./jsx"; import { Page, Spinner } from "./components"; -import { sizeHumanReadable } from "./util"; - -function downloadFile( file: string ) { - const a = document.createElement( "a" ); - a.href = "https://networkheaven.net/pkgs/"; - a.download = "string"; - a.click(); - a.remove(); -} +import { FtpEntry, ftpGetEntries, sizeHumanReadable } from "./util"; +let entries: FtpEntry[] = []; function urlForHref( href: string, isdir: boolean ) { const url = new URL( window.location.href ); let path = url.pathname; @@ -23,99 +16,19 @@ function urlForHref( href: string, isdir: boolean ) { path = path.slice( path.indexOf( '/pkgs' ) + 5 ); if( path.endsWith( '/' ) ) - return "https://networkheaven.net/pkgs" + path + "" + href; -} - -interface PkgEntry { - name: string; - date: string; - time: string; - size: string; - isdir: boolean; -} - -function entryFromLine( line: string ): PkgEntry | null { - const isdir = line[line.length - 1] == '-'; - const name = line.slice( 0, line.indexOf( " " ) ); - if( name == ".." ) return null; - if( !name ) - return null; - let date = ''; - let time = ''; - let size = '' - - if( !isdir ) { - let end = line.lastIndexOf( " " ); - size = line.slice( end + 1 ); - date = line.slice( line.indexOf( " " ) + 1, end ); - end = date.indexOf( " " ); - const datetime = date.slice( date.search( /[0-9]/ ) ); - end = datetime.indexOf( ' ' ); - date = datetime.slice( 0, end ); - time = datetime.slice( end + 1 ); - time = time.slice( 0, time.indexOf( " " ) ); - } else { - let start = line.search( /[0-9]/ ) - date = line.slice( start ); - let end = date.indexOf( " " ); - date = date.slice( 0, end ); - time = line.slice( start + end + 1, line.length - 1 ); - time = time.slice( 0, time.indexOf( " " ) ); - } - - return { name, date, time, size, isdir }; -} - -async function getEntries(): Promise { - const url = new URL( window.location.href ); - const href = url.pathname.split( "/pkg" )[1]; - - const packages = await fetch( "https://networkheaven.net/pkgs/" + href ); - const text = await packages.text(); - - const pkgBody = $(
); - pkgBody.html( text ); - pkgBody.html( pkgBody.find( "body" ).html() ); - const pre = pkgBody.find( "pre" )[0].innerText; - - const ret = []; - if( !url.pathname.endsWith( "/pkg/" ) && !url.pathname.endsWith( "/pkg" ) ) { - ret.push({ - name: '../', - date: ' ', - time: ' ', - size: '', - isdir: true - } ); - } - - const lines = pre.split( "\n" ); - for( const line of lines ) { - if( !line.length ) - continue; - - const entry = entryFromLine( line ); - if( entry ) - ret.push( entry ); - } - - return ret; + return "https://networkheaven.net/pkgs" + path + href; + else + return "https://networkheaven.net/pkgs" + path + "/" + href; } -function back() { - const url = new URL( window.location.href ); - if( url.pathname.endsWith( "/" ) ) - url.pathname = url.pathname.slice( 0, -1 ); - url.pathname = url.pathname.slice( 0, url.pathname.lastIndexOf( "/" ) ); - JSX.navigate( url.pathname ); -} function PackageEntry( props: any ) { - const entry = props.entry as PkgEntry; + const entry = props.entry as FtpEntry; + const small = !!( window.innerWidth < 750 ); return
- + } +function getEndpoint() { + const url = new URL( window.location.href ); + let href = url.pathname.split( "/pkg" )[1]; + + if( href[0] == '/' ) { + href = href.slice( 1 ); + } + + return "pkgs/" + href; +} + export default function Pkgs() { + entries = []; setTimeout( async () => { - try { - const entries = await getEntries(); - const target = $( "#package-entries" ).find( "table" ); - $( "#package-entries" ).find( ".spinner" ).remove(); - for( const entry of entries ) { - target.append( ); - } + const url = new URL( window.location.href ); + const showBack = !url.pathname.endsWith( "/pkg/" ) && !url.pathname.endsWith( "/pkg" ); + entries = await ftpGetEntries( getEndpoint(), showBack ); - } catch( e ) { - console.log( e ); - } + const target = $( "#package-entries" ).find( "table" ); + $( "#package-entries" ).find( ".spinner" ).remove(); + target.empty(); + for( const entry of entries ) { + target.append( ); + } } ); return
-

PACKAGE REPOSITORY

+

PACKAGE REPOSITORY


diff --git a/web/src/sidebar.tsx b/web/src/sidebar.tsx index de7b2fd..6ada6f9 100644 --- a/web/src/sidebar.tsx +++ b/web/src/sidebar.tsx @@ -50,12 +50,13 @@ async function updateWeather() { function Weather() { setTimeout( updateWeather ); const weather = getWeatherCache(); + const small = !!( window.innerWidth < 750 ); if( weather && weather.current ) { const temp = weather.current.temperature_2m; const wind = weather.current.wind_speed_10m; const humi = weather.current.relative_humidity_2m; return
- + @@ -63,7 +64,7 @@ function Weather() { } return
- + diff --git a/web/src/util.tsx b/web/src/util.tsx index 1b1ccc0..00dbb57 100644 --- a/web/src/util.tsx +++ b/web/src/util.tsx @@ -1,3 +1,87 @@ +import $ from "jquery"; +import * as JSX from "./jsx"; + +export interface FtpEntry { + name: string; + date: string; + time: string; + size: string; + isdir: boolean; +} + +export function ftpEntryFromLine( line: string ): FtpEntry | null { + const isdir = line[line.length - 1] == '-'; + const name = line.slice( 0, line.indexOf( " " ) ); + if( name == ".." ) return null; + if( !name ) + return null; + let date = ''; + let time = ''; + let size = '' + + if( !isdir ) { + let end = line.lastIndexOf( " " ); + size = line.slice( end + 1 ); + date = line.slice( line.indexOf( " " ) + 1, end ); + end = date.indexOf( " " ); + const datetime = date.slice( date.search( /[0-9]/ ) ); + end = datetime.indexOf( ' ' ); + date = datetime.slice( 0, end ); + time = datetime.slice( end + 1 ); + time = time.slice( 0, time.indexOf( " " ) ); + } else { + let start = line.search( /[0-9]/ ) + date = line.slice( start ); + let end = date.indexOf( " " ); + date = date.slice( 0, end ); + + time = line.slice( start + end + 1, line.length - 1 ); + time = time.slice( 0, time.indexOf( " " ) ); + } + + const day = date.slice( 0, date.indexOf( "-" ) ); + const month = date.slice( date.indexOf( "-" ) + 1, date.indexOf( "-" ) + 4 ); + const year = date.slice( -2 ); + + date = `${year}/${monthToNumber( month )}/${day}`; + + return { name, date, time, size, isdir }; +} + +export async function ftpGetEntries( endpoint: string, showBack: boolean = false ): Promise { + const packages = await fetch( "https://networkheaven.net/" + endpoint ); + const text = await packages.text(); + + const pkgBody = $(
); + pkgBody.html( text ); + pkgBody.html( pkgBody.find( "body" ).html() ); + const pre = pkgBody.find( "pre" )[0].innerText; + + const ret = []; + if( showBack ) { + ret.push({ + name: '../', + date: ' ', + time: ' ', + size: '', + isdir: true + } ); + } + + const lines = pre.split( "\n" ); + for( const line of lines ) { + if( !line.length ) + continue; + + const entry = ftpEntryFromLine( line ); + if( entry ) + ret.push( entry ); + } + + return ret; +} + + export function escapeHtml( html: string ) { const entityMap = { '&': '&', @@ -29,14 +113,32 @@ export function parseJWT( token: string ) : any { return payload; } -export function sizeHumanReadable( size: number ) { +export function sizeHumanReadable( size: number, short: boolean = false ) { if( size < 1024 ) - return size + ' B'; + return size + (short? 'B' : ' B'); else if( size < 1024 * 1024 ) - return ( size / 1024 ).toFixed( 2 ) + ' KB'; + return ( size / 1024 ).toFixed( short? 1: 2 ) + (short? 'K' : ' KB'); else if( size < 1024 * 1024 * 1024 ) - return ( size / 1024 / 1024 ).toFixed( 2 ) + ' MB'; + return ( size / 1024 / 1024 ).toFixed( short? 1 : 2 ) + (short? 'M' : ' MB'); else - return ( size / 1024 / 1024 / 1024 ).toFixed( 2 ) + ' GB'; + return ( size / 1024 / 1024 / 1024 ).toFixed( short? 1 : 2 ) + (short? 'G':' GB'); } +export function monthToNumber( month: string ) { + const months = [ + '', + 'jan', + 'feb', + 'mar', + 'apr', + 'may', + 'jun', + 'jul', + 'aug', + 'sep', + 'oct', + 'nov', + 'dec' + ]; + return months.indexOf( month.toLowerCase() ); +}; diff --git a/web/static/main.css b/web/static/main.css index ba7524c..79f28f4 100644 --- a/web/static/main.css +++ b/web/static/main.css @@ -42,6 +42,7 @@ flex-direction: column; padding: 0; margin: 0; + font-weight: normal; } input[type="radio"] { appearance: none; @@ -95,8 +96,17 @@ input[type="radio"]:checked::before { code { font-family: Code; - font-size: 12px; + font-size: 13px; white-space: pre-wrap; + background: #212325; + padding: 5px 7px !important; + border-top: 1px solid #aaa; + border-left: 1px solid #888; + border-right: 1px solid #666; + border-bottom: 1px solid #000; + display: inline-block; + margin-top: 3px; + margin-bottom: 3px; } html, body { @@ -150,7 +160,7 @@ a:hover { background: var( --gradient ); background-clip: border-box; text-decoration: underline; - -webkit-text-fill-color: transparent; + -webkit-text-fill-color: unset; -webkit-background-clip: text; text-decoration: underline; } @@ -174,6 +184,10 @@ a.nogradient { } a.nogradient:hover { + background: var( --gradient ); + background-clip: border-box; + -webkit-text-fill-color: transparent; + -webkit-background-clip: text; text-decoration: underline; } @@ -233,6 +247,7 @@ body { border-top: 1px solid #fff; border-right: 1px solid #888; border-bottom: 1px solid #222; + position: relative; } @@ -242,6 +257,18 @@ body { .btn_close { background: #ccc; } +#ascii-art { + white-space: pre-wrap; + font-family: Code; + font-size: 12px; + overflow:clip; + padding-top: 5px; +} + +#ascii-art span { + padding: 0; + margin: 0; +} #sidebar { width: 230px; @@ -278,7 +305,6 @@ body { margin-left: 4px; } - .sidebar-row { display: flex; flex-direction: row; @@ -296,13 +322,46 @@ body { .page-title h3 { margin-top: 15px; margin-bottom: 6px; + font-size: 25px; +} + +h5 { + font-family: JPN16; + font-size: 17px; + font-weight: normal; + margin-top: 12px; +} + + +.package-entry-date, +.package-entry-time { + padding: 0 10px; +} + +#blog-entry { + display: flex; + justify-content: center; + padding-top: 8px; + width: 95%; + font-size: 17px; +} + +#blog-entry h4 { + margin-top: 4px; + margin-bottom: 4px; + font-family: JPN19; + font-size: 20px; +} + +#blog-entry ul { + padding-left: 20px; } @media( max-width: 1100px ) { #page-main-content { width: calc( 100% - 20px ) !important; min-width: unset !important; - margin-right: 20px !important; + margin-right: 20px; margin-left: 0 !important; }; @@ -319,6 +378,11 @@ body { height: 35px; } + + h5 { + margin-top: 9px; + } + #sidebar h3 { margin-top: 8px; margin-bottom: 8px; @@ -344,18 +408,24 @@ body { #package-entries table { font-family: JPN12 !important; - font-size: 11px !important; + font-size: 13px !important; text-align: right; } #ascii-art { - font-size: 7px !important; + font-size: 9px; + } + + #blog-entry { + width: 98%; + font-family: JPN12; + font-size: 13px; } } @media( max-width: 740px ) { #sidebar { - width: 200px !important; + width: 200px; } #sidebar h4 { @@ -364,6 +434,23 @@ body { margin-top: 0px; } + .page-title h3 { + font-size: 20px; + margin-top: 6px; + margin-bottom: 0px; + } + + h5 { + font-family: JPN16; + font-size: 10px; + font-weight: normal; + margin-top: 7px; + } + + .page-title { + height: 30px; + } + #sidebar h3 { font-size: 20px !important; } @@ -380,23 +467,60 @@ body { } #ascii-art { - font-size: 6px !important; + font-size: 6px; + } + + .package-entry-date, + .package-entry-time { + padding: 0; } } -#ascii-art { - white-space: pre-wrap; - font-family: Code; - font-size: 12px; - overflow:clip; - padding-top: 5px; + +@media( max-width: 460px ) { + #sidebar { + width: 170px !important; + margin-left: 5px; + margin-right: 5px; + } + + #page-main-content { + margin-right: 5px; + } + + #page-main { + padding-top: 10px; + } + + #ascii-art { + font-size: 4px; + } + + #sidebar h4 { + font-size: 8px !important; + margin-bottom: 0px; + margin-top: 0px; + } + + #sidebar h3 { + font-size: 17px !important; + } + + h5 { + font-family: JPN12; + font-size: 9px; + font-weight: normal; + margin-top: 4px; + } } -#ascii-art span { - padding: 0; - margin: 0; +@media( max-width: 350px ) { + #ascii-art { + font-size: 3px; + } } + .groupbox { border: 1px solid var( --front ); background-color: var( --back ); @@ -605,6 +729,7 @@ body { #package-entries table { text-align: right; + font-size: 17px; } #package-entries table tr td:first-child { @@ -617,8 +742,3 @@ body { justify-content: space-between; } - -.package-entry-date, -.package-entry-time { - padding: 0 10px; -} -- cgit v1.2.3
{ entry.name == "../" && - back() } class="package-entry-link"> + JSX.goUpDirectory() } class="package-entry-link"> ../ } { entry.name != "../" && !entry.isdir && @@ -129,29 +42,42 @@ function PackageEntry( props: any ) { {entry.time}{ !entry.isdir && { sizeHumanReadable( parseInt( entry.size ) ) } }{ !entry.isdir && { sizeHumanReadable( parseInt( entry.size ), small ) } } + { entry.isdir && dir } +