Working on site and services

This commit is contained in:
Jordan Roher 2023-04-19 15:48:31 -07:00
parent a295940003
commit bf94df244e
10 changed files with 254 additions and 20 deletions

20
src/components/header.tsx Normal file
View File

@ -0,0 +1,20 @@
import React from "react";
import { is } from "../shared/is";
import { IService } from "../shared/types";
interface IProps {
title?: string;
icon?: string;
auth?: IService;
docker?: IService;
}
export const Header: React.FunctionComponent<IProps> = ({ icon, title, auth, docker }) => {
return (
<div className="p-4">
<h1>{title}</h1>
{!is.null(icon) && <img src={icon} alt="icon" />}
</div>
);
};

View File

@ -1,11 +0,0 @@
import React from "react";
interface IService {
name: string;
uri: string;
icon: string;
}
export const Service: React.FunctionComponent<IService> = ({ name, uri, icon }) => {
return null;
};

View File

@ -0,0 +1,26 @@
import React from "react";
import { IService } from "../shared/types";
interface IProps {
services: IService[];
}
export const Services: React.FunctionComponent<IProps> = ({ services }) => {
return (
<ul className="grid grid-flow-col auto-cols-min gap-2">
{services.map((service, index) => (
<Service key={index} {...service} />
))}
</ul>
);
};
const Service: React.FunctionComponent<IService> = ({ name, uri, description, icon }) => {
return (
<li>
<a href={uri} className="p-4 block bg-border">
{name}
</a>
</li>
);
};

View File

@ -1,7 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
background-color: theme(colors.bg);
}

View File

@ -1,7 +1,7 @@
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import { IndexPage } from "./pages";
import "./tailwind.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>

View File

@ -1,4 +1,7 @@
import React from "react";
import { Header } from "../components/header";
import { Services } from "../components/services";
import { FAKE_SERVICES } from "../shared/types";
interface IProps {
title?: string;
@ -6,5 +9,14 @@ interface IProps {
}
export const IndexPage: React.FunctionComponent<IProps> = ({ icon, title }) => {
return <p>Hello there</p>;
return (
<div className="screen-h flex flex-row">
<div className="border-0 border-solid border-l border-l-border p-4">
<Header title={title} icon={icon} />
</div>
<div className="p-4">
<Services services={FAKE_SERVICES} />
</div>
</div>
);
};

161
src/shared/is.ts Normal file
View File

@ -0,0 +1,161 @@
function IsArray(data: any): boolean {
if (data === null || typeof data === "undefined") {
return false;
}
return data.constructor === Array;
}
function IsNull(data: any): boolean {
return (
typeof data === "undefined" ||
data === null ||
(typeof data === "string" && data.length === 0) ||
(IsArray(data) && data.length === 0)
);
}
function IsDate(data: any): boolean {
return data instanceof Date;
}
function IsDateString(data: any): boolean {
return !IsNull(data) && data.indexOf("/Date(") === 0;
}
function IsJsonString(data: any): boolean {
try {
JSON.parse(data);
return true;
} catch {
return false;
}
}
function IsNumeric(data: any): boolean {
return (
typeof data !== "undefined" &&
data !== null &&
data.toString().length > 0 &&
data.toString().replace(/[\d.]+/gi, "").length === 0 &&
!isNaN(data)
);
}
function IsString(data: any): boolean {
return !IsNull(data) && typeof data === "string";
}
function IsValidHttpUrl(data: any): boolean {
// Copyright (c) 2010-2013 Diego Perini, MIT licensed
// https://gist.github.com/dperini/729294
// see also https://mathiasbynens.be/demo/url-regex
// modified to allow protocol-relative URLs
// and modified again to remove ftp (Jordan)
if (IsNull(data)) {
return false;
}
const validUrlRegex =
/^(?:(?:(?:https?):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
return validUrlRegex.test(data);
}
function IsFunction(data: any): boolean {
return !IsNull(data) && data instanceof Function;
}
const IsReactRoute = (uri: string): boolean => {
const reactRouteRegex = /[a-z]{1,4}-[a-z]{1,4}\/r\/[ts]\//gi;
return !IsNull(uri) && reactRouteRegex.test(uri);
};
const IsArrayDifferent = (array1: any[], array2: any[], useDeepComparison = false): boolean => {
const isArray1Null = IsNull(array1);
const isArray2Null = IsNull(array2);
if (isArray1Null && isArray2Null) {
return false;
}
const shallowResult =
isArray1Null !== isArray2Null || (!isArray1Null && !isArray2Null && array1.length !== array2.length);
if (shallowResult) {
return true;
}
if (!useDeepComparison) {
return array1 !== array2;
}
return array1.some((array1Item, index) => {
return array2[index] !== array1Item;
});
};
const IsInArray = (array: any[], element: any): boolean => {
return !IsNull(array) && array.indexOf(element) !== -1;
};
const IsShallowEqual = (obj1: any, obj2: any, ignorePrivateProperties: boolean = false): boolean => {
if (is.null(obj1) && is.null(obj2)) {
return true;
} else if (is.null(obj1) !== is.null(obj2)) {
return false;
} else if (typeof obj1 !== "object" && typeof obj2 !== "object") {
return obj1 === obj2;
}
for (const p in obj1) {
if (ignorePrivateProperties && p.startsWith("_")) {
continue;
}
if (obj1.hasOwnProperty(p)) {
if (obj1[p] !== obj2[p]) {
return false;
}
}
}
for (const p in obj2) {
if (ignorePrivateProperties && p.startsWith("_")) {
continue;
}
if (obj2.hasOwnProperty(p)) {
if (obj1[p] !== obj2[p]) {
return false;
}
}
}
return true;
};
const IsAnythingDifferent = (props: any, nextProps: any, ...keys: string[]): boolean => {
return keys.some(key => {
if (IsArray(props[key])) {
return IsArrayDifferent(props[key], nextProps[key], true);
}
return props[key] !== nextProps[key];
});
};
export const is = {
array: IsArray,
arrayDifferent: IsArrayDifferent,
null: IsNull,
date: IsDate,
dateString: IsDateString,
numeric: IsNumeric,
string: IsString,
validHttpUrl: IsValidHttpUrl,
function: IsFunction,
reactRoute: IsReactRoute,
jsonString: IsJsonString,
inArray: IsInArray,
shallowEqual: IsShallowEqual,
anythingDifferent: IsAnythingDifferent,
};

18
src/shared/types.ts Normal file
View File

@ -0,0 +1,18 @@
export interface IService {
name: string;
uri: string;
description?: string;
icon?: string;
}
export const FAKE_SERVICES: IService[] = [
{
name: "Calibre",
uri: "https://calibre.starbase80.dev",
},
{
name: "Gitea",
uri: "https://git.starbase80.dev",
},
];

14
src/tailwind.css Normal file
View File

@ -0,0 +1,14 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
background-color: theme(colors.bg);
}
h1 {
font-size: theme(fontSize.3xl);
font-weight: theme(fontWeight.semibold);
margin: 0;
padding: 0;
}

View File

@ -4,6 +4,7 @@ export default {
theme: {
colors: {
bg: "#f8fafc",
border: "#336699",
},
extend: {},
},