Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53bb02063a | ||
|
|
10bb283a44 | ||
|
|
eda39d07ba | ||
|
|
845d7ecdcb | ||
|
|
027a7875d8 |
No files matched your search
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 662 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000"><metadata><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><rdf:Description><dc:creator>RealFaviconGenerator</dc:creator><dc:source>https://realfavicongenerator.net</dc:source></rdf:Description></rdf:RDF></metadata><g clip-path="url(#SvgjsClipPath1046)"><rect width="1000" height="1000" fill="#ffffff"></rect><g transform="matrix(3.3333333333333335,0,0,3.3333333333333335,0,0)"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300" viewBox="0 0 300 300"><image width="300" height="300" xlink:href="data:image/png;base64,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 truncated
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Hyperling.com",
|
||||
"short_name": "Hyperling",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/web-app-manifest-192x192.png?v=20261102",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/web-app-manifest-512x512.png?v=20261102",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 39 KiB |
@@ -26,6 +26,10 @@ let pages = [];
|
||||
const pages_dir = "./pages/";
|
||||
const file_types = ["php", "sh"];
|
||||
|
||||
let assets = [];
|
||||
const asset_dir = "./assets/";
|
||||
const asset_types = ['png', 'svg', 'ico', 'webmanifest', 'jpg'];
|
||||
|
||||
let ports = [];
|
||||
// Check parameters for numeric port numbers.
|
||||
process.argv.forEach(function (val, index, array) {
|
||||
@@ -46,6 +50,8 @@ const stringsToRemove = [
|
||||
|
||||
//// Functions ////
|
||||
|
||||
// Compact HTML and remove unnecessary content like comments and whitespace.
|
||||
// May help with performance for slower connections. Also more professional.
|
||||
async function mini(html) {
|
||||
//console.log(`html=${html}`);
|
||||
const minified = await minify(html, {
|
||||
@@ -58,6 +64,38 @@ async function mini(html) {
|
||||
return minified.toString();
|
||||
}
|
||||
|
||||
// Check extension and guess a MIME type.
|
||||
function getMIME(extension) {
|
||||
let mime;
|
||||
switch (extension) {
|
||||
case "apk":
|
||||
mime = "application/vnd.android.package-archive";
|
||||
break;
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
mime = "image/jpeg";
|
||||
break;
|
||||
case "png":
|
||||
mime = "image/png";
|
||||
break;
|
||||
case "html":
|
||||
mime = "text/html";
|
||||
break;
|
||||
case "zip":
|
||||
mime = "application/zip";
|
||||
break;
|
||||
case "md":
|
||||
case "txt":
|
||||
case "csv":
|
||||
mime = "text/*";
|
||||
break;
|
||||
default:
|
||||
mime = "application/" + extension;
|
||||
break;
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
|
||||
/* Code exists inside a main function so that we may use async/await.
|
||||
*/
|
||||
async function main() {
|
||||
@@ -73,7 +111,7 @@ async function main() {
|
||||
next();
|
||||
});
|
||||
|
||||
/* Loop through all file in the pages subdirectory and add the allowed
|
||||
/* Loop through all files in the pages subdirectory and add the allowed
|
||||
// file types into the pages array for automatic router creation.
|
||||
*/
|
||||
console.log("...Starting Main...");
|
||||
@@ -94,6 +132,26 @@ async function main() {
|
||||
console.log(" * Pages loaded: ", pages);
|
||||
//return; // Stop execution FORTESTING
|
||||
|
||||
/* Loop through the assets folder and grab favicons, manifests, etc. and
|
||||
// allow them to be accessed via the root of the website, such as a favicon
|
||||
// at 'https://hyperling.com/favicon.ico'. May help with SEO!
|
||||
*/
|
||||
let ls_assets = await fs.promises.readdir(asset_dir);
|
||||
if (DEBUG) console.log("DEBUG: Results of ls_assets, ", ls_assets);
|
||||
for (let file of ls_assets) {
|
||||
let file_test = file.split(".");
|
||||
//let file_name = file_test[0]; // not needed (yet)
|
||||
let file_type = file_test[file_test.length - 1];
|
||||
if (asset_types.includes(file_type)) {
|
||||
if (DEBUG) console.log("DEBUG: Hooray!", file, "is being added.");
|
||||
assets[file] = asset_dir + file;
|
||||
console.log(" * Added asset", file);
|
||||
} else {
|
||||
if (DEBUG) console.log("DEBUG: ", file, "is not an approved type, skipping.");
|
||||
}
|
||||
}
|
||||
console.log(" * Assets loaded: ", assets);
|
||||
|
||||
/* Create both an XML and HTML sitemap based on these entries. XML is used for
|
||||
// bots like SEO scrapers. HTML will be for human users looking for a list of
|
||||
// all pages. Some are not in the menu. Generated an example XML sitemap at
|
||||
@@ -202,6 +260,30 @@ async function main() {
|
||||
</ul></body></html>
|
||||
`;
|
||||
|
||||
console.log(" * Creating routers for assets");
|
||||
for (let key in assets) {
|
||||
console.log(" * * Adding /" + key);
|
||||
router.get('/' + key, function (req, res) {
|
||||
console.log("asset response to", req.socket.remoteAddress, "asking for", req.url)
|
||||
|
||||
// Build variables.
|
||||
const file = "./assets/" + req.path;
|
||||
const extensions = req.path.split(".");
|
||||
const extension = extensions[extensions.length-1];
|
||||
let mime = getMIME(extension);
|
||||
|
||||
// Return the file
|
||||
res.contentType(mime);
|
||||
let f = fs.createReadStream(file)
|
||||
.on("error", function(e) {
|
||||
res.contentType("text/plain");
|
||||
res.send(404, "Asset Not Found");
|
||||
})
|
||||
.pipe(res)
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
// Provide sitemap.xml file for "SEO".
|
||||
// TBD/TODO would be great to log this as "DATE: ADDRESS hit ROUTER requesting RESOURCE"
|
||||
console.log(" * Creating router for sitemap.xml");
|
||||
@@ -237,35 +319,7 @@ async function main() {
|
||||
const file = "." + req.path;
|
||||
const extensions = req.path.split(".");
|
||||
const extension = extensions[extensions.length-1];
|
||||
|
||||
// Check extension and guess a MIME type.
|
||||
let mime;
|
||||
switch (extension) {
|
||||
case "apk":
|
||||
mime = "application/vnd.android.package-archive";
|
||||
break;
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
mime = "image/jpeg";
|
||||
break;
|
||||
case "png":
|
||||
mime = "image/png";
|
||||
break;
|
||||
case "html":
|
||||
mime = "text/html";
|
||||
break;
|
||||
case "zip":
|
||||
mime = "application/zip";
|
||||
break;
|
||||
case "md":
|
||||
case "txt":
|
||||
case "csv":
|
||||
mime = "text/*";
|
||||
break;
|
||||
default:
|
||||
mime = "application/" + extension;
|
||||
break;
|
||||
}
|
||||
let mime = getMIME(extension);
|
||||
|
||||
// Return the file
|
||||
res.contentType(mime);
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
height: 237px; /* 69*3[banner stripes] + 15*2[padding top+bot] */
|
||||
}
|
||||
.banner-image01 {
|
||||
background-image: url("/files/media/icons/home.jpg");
|
||||
background-image: url("/banner-image01.jpg");
|
||||
}
|
||||
.banner-image02 {
|
||||
background-image: url("/files/media/icons/contact.jpg");
|
||||
background-image: url("/banner-image02.jpg");
|
||||
}
|
||||
|
||||
.banner-anchor {
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
|
||||
<link rel="icon" sizes="32x32"
|
||||
href="/files/media/icons/favicon.ico"
|
||||
href="/favicon.ico"
|
||||
>
|
||||
<link rel="icon" sizes="192x192"
|
||||
href="/files/media/icons/favicon.ico"
|
||||
href="/favicon.ico"
|
||||
>
|
||||
|
||||
<!-- https://favicon.io -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
|
||||
<!-- https://realfavicongenerator.net -->
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png?v=20261102" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg?v=20261102" />
|
||||
<link rel="shortcut icon" href="/favicon.ico?v=20261102" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=20261102" />
|
||||
<meta name="apple-mobile-web-app-title" content="Hyperling" />
|
||||
<link rel="manifest" href="/site.webmanifest?v=20261102" />
|
||||