initial commit

This commit is contained in:
2025-09-17 23:05:25 -04:00
commit ee78eef527
17 changed files with 610 additions and 0 deletions

28
startpage/index.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="icon" type="image/png" href="../icons/misc.png">
<title>Startpage</title>
</head>
<body>
<header>
<h1 id="clock" style="margin-bottom:0;"></h1>
<p id="date" style="margin-top:0;"></p>
</header>
<p id="search-results">
<div id="search">
<input
type="text"
id="search-bar"
value="fetch"
placeholder="run man for more info"
autofocus
>
</div>
</p>
</body>
<script type="module" src="./index.js"></script>
</html>

134
startpage/index.js Normal file
View File

@@ -0,0 +1,134 @@
let clock = document.getElementById("clock");
let date = document.getElementById("date");
let input = document.getElementById("search-bar");
let result = document.getElementById("search-results");
/* Allow toggling between military and 12 hr time */
let military_time = false
clock.onclick = function() {
military_time = !military_time;
time();
}
function time(timeout) {
let d = new Date();
let m = d.getMinutes();
let h = d.getHours();
/* if it hasn't been set then set it here */
if (military_time) {
clock.textContent = `${("0" + h).substr(-2)}:${("0" + m).substr(-2)}`;
} else {
let hours = h % 12;
let minutes = ("0" + m).substr(-2);
hours = hours ? hours : 12;
clock.textContent = `${hours}:${minutes} ${(h >= 12 ? "PM" : "AM")}`;
}
/* set the time every second */
timeout && setTimeout(() => time(true), (60 - d.getSeconds()) * 1000);
}
let last_date;
/* Sun 31st, May */
function cal(force) {
const days = [ "Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat" ];
const months = [ "January", "Febuary", "March", "April", "May", "June",
"July", "August", "September", "November", "December", ];
let d = new Date();
let day = days[d.getDay()];
let day_of_month = d.getDate();
let month = months[d.getMonth()];
let day_suffix
/* get a suffix for the day of the month */
if (day_of_month > 3 && day_of_month < 21) {
day_suffix = "th";
} else if ((day_of_month / 1) % 10 == 1) {
day_suffix = "st";
} else if ((day_of_month / 1) % 10 == 2) {
day_suffix = "nd";
} else if ((day_of_month / 1) % 10 == 3) {
day_suffix = "rd";
} else {
day_suffix = "th";
}
/* check if this date has already been set before */
if (!force && last_date == `${d.getDay()}${d.getMonth()}`) {
return;
}
date.textContent = `${day} ${day_of_month}${day_suffix}, ${month}`;
/* store the last date that was set */
last_date = `${d.getDay()}${d.getMonth()}`;
}
/* show the time on the page */
time(true);
/* just incase something dumb happens the time should update when the user
* focus's the page */
window.addEventListener('focus', time);
cal();
setInterval(cal, 1000);
function shell(event) {
var env = {
path: "/startpage/root/bin/",
};
/* convert a directory such as /startpage/root/bin/ to /startpage/root/.bin
* to read static fs data.
*/
function convertPath(path) {
if (path.endsWith('/')) {
path = path.slice(0, -1);
}
const parts = path.split('/');
const hidden = '.' + parts.pop();
return parts.concat(hidden).join('/');
}
async function run(path) {
try {
const response = await fetch(convertPath(env.path));
if (!response.ok) {
throw new Error(`Failed to load file: ${response.status}`);
}
const text = await response.text();
const lines = text.split(/\r?\n/);
const matchedLine = lines.find(line => line.split(".")[0] == path);
if (!matchedLine) {
throw new Error(`${path} cannot be found in path.`);
}
const file = env.path + matchedLine;
const { cmd } = await import(file);
return await cmd(input.value, event.key);
} catch (err) {
throw err;
}
}
if (input.value == "") {
input.style.color = "white";
} else {
run(input.value.substring(0, input.value.indexOf(" ")) || input.value)
.then(res => {
result.innerHTML = res;
input.style.color = "var(--blue)";
})
.catch(err => {
input.style.color = "white";
});
}
}
input.addEventListener('keyup', shell);
shell({ key: "" });

4
startpage/root/.bin Normal file
View File

@@ -0,0 +1,4 @@
clear.js
fetch.js
gpt.js
man.js

View File

@@ -0,0 +1,12 @@
export async function cmd() {
return ``;
}
export let man = `
<pre>
CLEAR(1)
NAME
\tclear - clear the screen
</pre>
`

View File

@@ -0,0 +1,29 @@
export async function cmd(_) {
return `
<pre>
_____\t\t\tOS: ${navigator.platform}
.-"" ""-.\t\tLang: ${navigator.language}
/(/ _ }\`;\`.\t\tTimezone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}
|\`---'/ \` \`;\\\t\tAgent: ${navigator.userAgent}
.' (\`._ ; \`:
: \--' '|\`;,;
| .---' ; | |
: ' \`.__.-. / ; ;
: .----' .' / :
\`. \`----' .' /
\`.\`--. __ .- .'
\`-._ _.-' fsc
\`""""
</pre>
`;
}
export let man = `
<pre>
FETCH(1)
NAME
\tfetch Get information about the browser. This is specific to firefox because
\tthis addon is specific to firefox.
</pre>
`

26
startpage/root/bin/gpt.js Normal file
View File

@@ -0,0 +1,26 @@
export async function cmd(inp, k) {
var search = ""
if (inp.indexOf(" ") > 0) {
search = inp.substring(inp.indexOf(" ") + 1)
}
if (k == 'Enter') {
window.open(`https://chatgpt.com/?q=${search}`, '_self');
}
return `
<pre>
press Enter to search chat.openai.com for: '${search}'
</pre>
`;
}
export let man = `
<pre>
GPT(1)
NAME
\tgpt - search chat.openai.com for something. You'll probably only get slop
\tbut it may have a chance of helping.
</pre>
`

53
startpage/root/bin/man.js Normal file
View File

@@ -0,0 +1,53 @@
var getmanval;
async function getman(path) {
try {
const module = await import("/startpage/" + path);
return module.man;
} catch (error) {
return null;
}
}
/* TODO: update to use the path in the env this can be done once we first
* make the env available to the programs running in the shell
*/
export async function cmd(inp) {
var search = ""
if (inp.indexOf(" ") > 0) {
search = inp.substring(inp.indexOf(" ") + 1)
}
switch (search) {
case "fetch": return getman('/root/bin/fetch.js');
case "gpt": return getman('/root/bin/gpt.js');
case "clear": return getman('/root/bin/clear.js');
case "shell": return manshell;
case "man": default: return man;
}
}
export let man = `
<pre>
MAN(1)
NAME
\tman display manual pages
SEE ALSO
\tfetch(1), gpt(1), shell(1), clear(1)
</pre>
`;
export let manshell = `
<pre>
SHELL(1)
NAME
\tshell command interpreter
DESCRIPTION
\tshell is a shell for my startpage. It's not POSIX nor will it ever be. It's
\tsole job it to interpret text and run a command if a valid one is found.
\tWhile this is quite unintuitive in a standard UNIX shell in my opinion this
\tmakes sense here because of such a limited number of commands.
</pre>
`;

103
startpage/style.css Normal file
View File

@@ -0,0 +1,103 @@
:root {
--bg: #161617;
--fg: #c9c7cd;
--bg-dark: #131314;
/* Normal */
--black: #27272a;
--red: #f5a191;
--green: #90b99f;
--yellow: #e6b99d;
--blue: #aca1cf;
--magenta: #e29eca;
--cyan: #ea83a5;
--white: #c1c0d4;
/* Bright */
--bright-black: #353539;
--bright-red: #ffae9f;
--bright-green: #9dc6ac;
--bright-yellow: #f0c5a9;
--bright-blue: #b9aeda;
--bright-magenta: #ecaad6;
--bright-cyan: #f591b2;
--bright-white: #cac9dd;
/* Grays */
--gray01: #1b1b1d;
--gray02: #2a2a2d;
--gray03: #3e3e43;
--gray04: #57575f;
--gray05: #757581;
--gray06: #9998a8;
--gray07: var(--white);
}
html, body {
background-color: var(--bg-dark);
max-width: 80ch;
max-height: 100%;
margin: auto;
}
@media (orientation: portrait) {
html, body {
max-width: 100% !important;
padding: 5px !important;
}
}
#font, p, ul, ol, h1, h2, h3, h4, h5, table {
font-family: sans-serif;
color: white;
}
pre {
color: white;
}
h1 {
font-size: 3em;
}
a {
font-family: sans-serif;
text-decoration: none;
color: var(--cyan);
}
a:hover, a:active {
text-decoration: underline;
}
#search {
display: flex;
align-items: center;
#search-bar, #search-btn {
height: 2.25em;
background-color: var(--bg);
color: white;
padding: 0 15px;
border: none;
}
#search-bar {
width: 100%;
}
#search-bar:focus {
outline: none;
background-color: var(--gray01);
}
#search-btn {
background-color: var(--yellow);
color: var(--bg);
font-weight: bold;
cursor: pointer;
}
#search-btn:focus {
outline: none;
background-color: var(--bright-yellow);
}
}
#search-results {
height: 15lh;
margin-top: 0px;
margin-bottom: 0px;
padding: 15px;
overflow: scroll;
background-color: #111112;
}