Compare commits

..

1 commit

Author SHA1 Message Date
8ec5be25d4
Removed pro icons 2023-10-23 18:06:31 +02:00
43 changed files with 4683 additions and 6697 deletions

View file

@ -1,8 +0,0 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.output
.vinxi
.git

View file

@ -2,7 +2,4 @@ module.exports = {
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
plugins: ["solid"], plugins: ["solid"],
extends: ["eslint:recommended", "plugin:solid/typescript", "prettier"], extends: ["eslint:recommended", "plugin:solid/typescript", "prettier"],
env: {
node: true,
},
}; };

3
.gitignore vendored
View file

@ -1,5 +1,6 @@
dist dist
.vinxi .solid
.output .output
.vercel .vercel
.netlify .netlify

View file

@ -1,53 +0,0 @@
# Use the desired base image
FROM node:21-alpine AS base
# Set the NODE_ENV to production
ENV NODE_ENV production
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
# Pass the Font Awesome token as a build argument
ARG FONT_AWESOME_TOKEN
RUN echo "@fortawesome:registry=https://npm.fontawesome.com/" > ~/.npmrc \
&& echo "//npm.fontawesome.com/:_authToken=${FONT_AWESOME_TOKEN}" >> ~/.npmrc \
&& if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
# Remove existing 'node' user and create a new user 'node' with UID 99 and use the existing group with GID 100
RUN deluser --remove-home node \
&& adduser -S -G users -u 99 node
COPY --from=builder /app/public ./public
COPY --from=builder --chown=node:users /app/.output ./.output
COPY --from=builder --chown=node:users /app/.vinxi ./.vinxi
# Switch to the non-root user
USER node
EXPOSE 3000
# Set the default values for environment variables
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", ".output/server/index.mjs"]

View file

@ -1,3 +0,0 @@
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({});

View file

@ -1,34 +1,35 @@
{ {
"name": "jg-eucs", "name": "jg-eucs",
"scripts": { "scripts": {
"dev": "vinxi dev", "dev": "solid-start dev",
"build": "vinxi build", "build": "solid-start build",
"start": "vinxi start", "start": "solid-start start",
"lint": "eslint --fix \"src/**/*.{ts,tsx,js,jsx}\"", "lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
"typecheck": "tsc --noEmit --checkJs false --skipLibCheck" "typecheck": "tsc --noEmit --checkJs false --skipLibCheck"
}, },
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"@types/node": "^20.11.21", "@types/node": "^20.8.6",
"@typescript-eslint/parser": "^7.1.0", "@typescript-eslint/parser": "^6.8.0",
"esbuild": "^0.20.1", "esbuild": "^0.19.5",
"eslint": "^8.57.0", "eslint": "^8.51.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-solid": "^0.13.1", "eslint-plugin-solid": "^0.13.0",
"prettier": "^3.2.5", "postcss": "^8.4.31",
"prettier-plugin-organize-imports": "^3.2.4", "prettier": "^3.0.3",
"typescript": "^5.3.3" "prettier-plugin-organize-imports": "^3.2.3",
"solid-start-node": "^0.3.6",
"typescript": "^5.2.2",
"vite": "^4.4.11"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-brands-svg-icons": "^6.5.1", "@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/pro-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.4.2",
"@solidjs/meta": "^0.29.3", "@solidjs/meta": "^0.28.6",
"@solidjs/router": "^0.12.4", "@solidjs/router": "^0.8.3",
"@solidjs/start": "^0.6.0", "solid-js": "^1.8.1",
"sass": "^1.71.1", "solid-start": "^0.3.6"
"solid-js": "^1.8.15",
"vinxi": "^0.3.4"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"

6010
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://jg-eucs.com/en</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/en/KSS22</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/en/manufacturers</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/en/overview</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/de</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/de/imprint</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/de/KSS22</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/de/manufacturers</loc>
<lastmod>2024-03-13</lastmod>
</url>
<url>
<loc>https://jg-eucs.com/de/overview</loc>
<lastmod>2024-03-13</lastmod>
</url>
</urlset>

View file

@ -1,108 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>XML Sitemap</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body {
font-family: sans-serif;
font-size: 16px;
color: #242628;
}
a {
color: #000;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
table {
border: none;
border-collapse: collapse;
width: 100%
}
th {
text-align: left;
padding-right: 30px;
font-size: 11px;
}
thead th {
border-bottom: 1px solid #7d878a;
cursor: pointer;
}
td {
font-size:11px;
padding: 5px;
}
tr:nth-child(odd) td {
background-color: rgba(0,0,0,0.04);
}
tr:hover td {
background-color: #e2edf2;
}
#content {
margin: 0 auto;
padding: 2% 5%;
max-width: 800px;
}
.desc {
margin: 18px 3px;
line-height: 1.2em;
}
.desc a {
color: #5ba4e5;
}
</style>
</head>
<body>
<div id="content">
<h1>XML Sitemap</h1>
<p class="desc">
This is a sitemap created by <a href="https://unlimited-dev.de">Unlimited Development</a> to allow search engines to discover this site's content.
</p>
<table id="sitemap" cellpadding="3">
<thead>
<tr>
<th width="70%">URL (<xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> total)</th>
<th width="15%">Images</th>
<th title="Last Modification Time" width="15%">Last Modified</th>
</tr>
</thead>
<tbody>
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:for-each select="sitemap:urlset/sitemap:url">
<tr>
<td>
<xsl:variable name="itemURL">
<xsl:value-of select="sitemap:loc"/>
</xsl:variable>
<a href="{$itemURL}">
<xsl:value-of select="sitemap:loc"/>
</a>
</td>
<td>
<xsl:value-of select="count(image:image)"/>
</td>
<td>
<xsl:value-of select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)))"/>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

144
public/styles/devices.css Normal file
View file

@ -0,0 +1,144 @@
* {
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-track {
background: rgb(41, 41, 41);
}
::-webkit-scrollbar-thumb {
background: #7f5af0;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
[class*="col-"] {
float: right;
}
#sidenavbar {
z-index: 1;
margin-left: -8px;
overflow: visible;
background-color: #121629;
position: fixed;
bottom: 0;
width: 100%;
height: 50px;
text-align: left;
display: flex;
justify-content: space-between;
}
#sidenavbar button {
all: unset;
margin: 5px auto;
color: #eff0f3;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 1.4em;
border: none;
}
#sidenavbar button:hover {
background: #eff0f3;
color: #2a2a2a;
cursor: pointer;
}
.main {
height: 100%;
}
body {
background-color: #16161a;
color: #94a1b2;
font-size: 1.4em;
}
h1 {
font-size: 2.5em;
}
h2 {
font-size: 2em;
}
h3 {
font-size: 1.6em;
margin-left: 140px;
}
p {
text-align: justify;
font-size: 0.875em;
}
header {
text-align: center;
}
footer,
aside,
article {
text-align: center;
padding: 2%;
margin: 1.5%;
}
img {
width: 100%;
max-width: max-content;
padding: 16px;
height: auto;
display: block;
}
.col-1 {
width: 8.33%;
}
.col-2 {
width: 16.66%;
}
.col-3 {
width: 25%;
}
.col-4 {
width: 33.33%;
}
.col-5 {
width: 41.66%;
}
.col-6 {
width: 50%;
}
.col-7 {
width: 58.33%;
}
.col-8 {
width: 66.66%;
}
.col-9 {
width: 75%;
}
.col-10 {
width: 83.33%;
}
.col-11 {
width: 91.66%;
}
.col-12 {
width: 100%;
}
@media only screen and (max-width: 767px) {
[class*="col-"] {
width: 100%;
}
}

407
public/styles/overview.css Normal file
View file

@ -0,0 +1,407 @@
* {
scroll-margin-block-start: 60px;
scroll-margin-block-end: 60px;
box-sizing: border-box;
scroll-behavior: smooth;
max-width: 100%;
max-height: 100%;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-track {
background: rgb(41, 41, 41);
}
::-webkit-scrollbar-thumb {
background: #7f5af0;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
[class*="col-"] {
float: left;
}
.row {
clear: both;
}
#navbar {
z-index: 1;
overflow-y: auto;
overflow-x: hidden;
background-color: #121629;
position: fixed;
top: 0;
height: 100%;
margin-left: -8px;
}
#navbar button {
border-radius: 16px;
scale: 0.9;
}
#navbar button:hover {
scale: 1.06;
}
#navbar a {
float: none;
display: block;
color: #eff0f3;
text-align: left;
padding: 8px 8px;
text-decoration: none;
font-size: 0.9em;
}
#navbar a:hover {
background: #eff0f3;
color: #121629;
cursor: pointer;
}
#sidenavbar {
z-index: 1;
margin-left: -8px;
overflow: visible;
background-color: #121629;
position: fixed;
bottom: 0;
width: 100%;
height: 50px;
text-align: left;
display: flex;
justify-content: space-between;
}
#sidenavbar button {
all: unset;
margin: 5px auto;
color: #eff0f3;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 1.4em;
border: none;
}
#sidenavbar button:hover {
background: #eff0f3;
color: #2a2a2a;
cursor: pointer;
}
.main {
height: 100%;
}
body {
background-color: #16161a;
color: #94a1b2;
text-align: center;
font-size: 1.4em;
}
h1 {
font-size: 2.5em;
color: #fffffe;
}
h2 {
font-size: 2em;
color: #fffffe;
}
h3 {
font-size: 1.6em;
clear: both;
color: #fffffe;
}
p {
text-align: justify;
font-size: 0.875em;
}
header {
text-align: center;
padding-left: 140px;
}
footer,
aside,
article {
text-align: center;
padding-left: 15px;
margin: 1.5%;
margin-left: 145px;
}
img {
width: 100%;
max-width: max-content;
height: auto;
margin-top: -8px;
}
button {
background-color: #121629;
color: #eff0f3;
text-align: left;
padding: 8px 8px;
text-decoration: none;
font-size: 0.9em;
}
p a {
text-align: justify;
text-decoration: none;
color: #91c4ff;
border-bottom: 1px solid navy;
}
p a:hover {
border-bottom: 1px solid #91c4ff;
}
.svg-inline--fa,
b {
color: #91c4ff;
}
.righties {
margin: 0 2%;
margin-right: 0%;
padding: 0%;
width: 33%;
float: right;
transition: width 1.5s;
clear: both;
}
.righties:hover {
width: 50%;
}
.lefties {
margin-right: 20px;
width: 33%;
height: 100%;
float: left;
transition: width 1.5s;
display: none;
}
.lefties:hover {
width: 50%;
}
#vcutout {
width: 25%;
}
#vcutout:hover {
width: 30%;
}
.hidden {
/*position:absolute;
transform:translate(-50%,-50%);
height:200px;
width:200px; */
float: left;
padding: 2%;
padding-left: 0%;
display: none;
}
/*wenn hover über text, zeige bild*/
.imghover:hover + .hidden {
display: block;
}
.light-mode {
background-color: #eff0f3;
color: #2a2a2a;
}
.light-mode article p a {
text-align: justify;
text-decoration: underline;
color: #2a2a2a;
}
.light-mode b {
color: #2a2a2a;
}
.light-mode b a {
color: #2a2a2a;
}
.light-mode h3 {
color: #2a2a2a;
}
.light-mode h1 {
color: #2a2a2a;
}
.light-mode h2 {
color: #2a2a2a;
}
.light-mode #navbar {
background-color: #b8c1ec;
}
.light-mode #sidenavbar {
background-color: #b8c1ec;
}
.light-mode #navbar a {
color: black;
}
.light-mode #sidenavbar a {
color: black;
}
.light-mode button {
background-color: #b8c1ec;
color: black;
}
/*Raster Einstellungen*/
.light-mode .raster {
background-color: #eff0f3;
}
.light-mode a {
color: #2a2a2a;
}
a {
display: inline;
color: rgb(225, 223, 210);
}
a svg.left {
margin-right: 2px;
}
a svg.right {
margin-left: 6px;
}
.raster {
width: 300px;
height: 350px;
float: left;
padding: 1%;
padding-top: 0;
border: #555;
border-width: 2px;
border-style: solid;
border-radius: 10%;
scale: 0.9;
font-size: 0.9em;
}
a div img,
a div video {
border-radius: 10%;
max-width: 260px;
max-height: 290px;
padding-top: 8px;
bottom: 0;
}
a div h3 {
margin: 0.5%;
}
.raster:hover {
scale: 1.06;
}
.raster:hover a div img {
width: 110%;
}
.logos {
height: 1.6em;
margin-bottom: -18px;
}
.col-1 {
width: 8.33%;
}
.col-2 {
width: 12.5%;
}
.col-3 {
width: 25%;
}
.col-4 {
width: 33.33%;
}
.col-5 {
width: 41.66%;
}
.col-6 {
width: 50%;
}
.col-7 {
width: 58.33%;
}
.col-8 {
width: 66.66%;
}
.col-9 {
width: 75%;
}
.col-10 {
width: 83.33%;
}
.col-11 {
width: 91.66%;
}
.col-12 {
width: 100%;
}
@media (max-width: 767px) /*unter handy größe*/ {
header,
article,
img,
p,
h1,
h2,
h3 {
margin-left: 0%;
padding-left: 0;
}
[class*="col-"] {
width: 100%;
}
#navbar {
visibility: hidden;
}
#sidenavbar {
visibility: visible;
}
/*.raster {width: calc(100%/2);}*/
.righties {
width: 100%;
}
.righties:hover {
width: 100%;
}
}
@media only screen and (min-width: 767px) /*über handy größe*/ {
#navbar {
visibility: visible;
}
#sidenavbar {
visibility: hidden;
}
/*.raster {width: calc(100%/5);}*/
div div button {
visibility: hidden;
}
}
/*@media screen and (min-width:1200px) {.raster {width: calc(100%/6);}}
@media screen and (min-width:1500px) {.raster {width: calc(100%/8);}}*/
@media screen and (min-width: 1900px) /*HD Fullscreen only*/ {
.lefties {
display: block;
width: 27%;
}
.righties {
width: 27%;
}
}
@media screen and (min-width: 2250px) /*ab 2000px nicht weiter skalieren*/ {
* {
width: 1950px;
margin-left: auto;
margin-right: auto;
}
}

109
public/styles/start.css Normal file
View file

@ -0,0 +1,109 @@
* {
scroll-margin-block-start: 60px;
scroll-margin-block-end: 60px;
box-sizing: border-box;
scroll-behavior: smooth;
max-width: 100%;
max-height: 100%;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-track {
background: rgb(41, 41, 41);
}
::-webkit-scrollbar-thumb {
background: #ff8906;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
[class*="col-"] {
float: left;
}
.row {
clear: both;
}
body {
background-color: #0f0e17;
color: #a7a9be;
text-align: left;
font-size: 1.4em;
max-width: 900px;
margin: auto;
}
p {
padding: 10px;
}
#cover {
opacity: 60%;
}
.container {
position: relative;
text-align: center;
color: white;
}
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#gone {
display: none;
color: #fffffe;
text-align: center;
}
#MoreButton {
margin: auto;
position: relative;
height: auto;
max-height: max-content;
width: auto;
max-width: max-content;
background-color: #ff8906;
border-radius: 5px;
color: #fffffe;
font-size: 1.2em;
}
a {
text-decoration: none;
}
a div p {
text-align: center;
padding: 20px;
}
a :hover {
scale: 1.06;
}
.righties {
padding-bottom: 30px;
padding-top: 20px;
width: 100%;
clear: both;
}
@media (max-width: 767px) /*unter handy größe*/ {
.centered {
display: none;
}
#gone {
display: block;
}
#cover {
opacity: 100%;
}
.righties {
width: 100%;
}
}

View file

@ -1,110 +0,0 @@
// @refresh reload
import "@fortawesome/fontawesome-svg-core/styles.css";
import { Link, Meta, MetaProvider, Title } from "@solidjs/meta";
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start";
import { Suspense } from "solid-js";
import "./styles/global.scss";
export default function App() {
return (
<Router
root={(props) => (
<MetaProvider>
<Link
rel="apple-touch-icon"
sizes="57x57"
href="/favicon/apple-icon-57x57.png"
/>
<Link
rel="apple-touch-icon"
sizes="60x60"
href="/favicon/apple-icon-60x60.png"
/>
<Link
rel="apple-touch-icon"
sizes="72x72"
href="/favicon/apple-icon-72x72.png"
/>
<Link
rel="apple-touch-icon"
sizes="76x76"
href="/favicon/apple-icon-76x76.png"
/>
<Link
rel="apple-touch-icon"
sizes="114x114"
href="/favicon/apple-icon-114x114.png"
/>
<Link
rel="apple-touch-icon"
sizes="120x120"
href="/favicon/apple-icon-120x120.png"
/>
<Link
rel="apple-touch-icon"
sizes="144x144"
href="/favicon/apple-icon-144x144.png"
/>
<Link
rel="apple-touch-icon"
sizes="152x152"
href="/favicon/apple-icon-152x152.png"
/>
<Link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-icon-180x180.png"
/>
<Link
rel="icon"
type="image/png"
sizes="192x192"
href="/favicon/android-icon-192x192.png"
/>
<Link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png"
/>
<Link
rel="icon"
type="image/png"
sizes="96x96"
href="/favicon/favicon-96x96.png"
/>
<Link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon/favicon-16x16.png"
/>
<Link rel="manifest" href="/favicon/manifest.json" />
<Meta name="msapplication-TileColor" content="#ffffff" />
<Meta
name="msapplication-TileImage"
content="/favicon/ms-icon-144x144.png"
/>
<Meta name="theme-color" content="#ffffff" />
<Meta http-equiv="X-UA-Compatible" content="IE=edge" />
<Meta charset="UTF-8" />
<Meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<Meta name="author" content="Julian Gerhardt" />
<Meta
name="keywords"
content="Elektrische Einräder, EUC, Monowheels, Kingsong, Inmotion, Gotway"
/>
<Title>jg-eucs.com</Title>
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}
>
<FileRoutes />
</Router>
);
}

View file

@ -1,225 +0,0 @@
import {
faMagnifyingGlassMinus,
faMagnifyingGlassPlus,
faSlidersSimple,
faVolume,
faVolumeSlash,
faXmark,
} from "@fortawesome/pro-regular-svg-icons";
import {
Match,
Setter,
Show,
Switch,
createEffect,
createSignal,
onCleanup,
} from "solid-js";
import { FontAwesomeIcon } from "./FontAwesomeIcon";
interface Asset {
src: string;
}
function AssetHandler() {
const [moving, setMoving] = createSignal(false);
const [active, setActive] = createSignal("");
const [zoomLevel, setZoomLevel] = createSignal(0);
const zoomAmount = () => 1 + zoomLevel() * 0.5;
const [x, setX] = createSignal(0);
const [y, setY] = createSignal(0);
function FullscreenView() {
const [muted, setMuted] = createSignal(true);
const [controlls, setControlls] = createSignal(false);
const [clientX, setClientX] = createSignal(0);
const [clientY, setClientY] = createSignal(0);
const [ref, setRef] = createSignal<HTMLElement | null>(null);
const handleMouseMove = (event: MouseEvent) => {
const { clientX, clientY } = event;
setClientX(clientX);
setClientY(clientY);
};
createEffect(() => {
const thisRef = ref();
if (!thisRef) return;
const rectA = thisRef.getBoundingClientRect();
const origSizeW = rectA.width / zoomAmount();
const origSizeH = rectA.height / zoomAmount();
const rectW = wrapperRef.getBoundingClientRect();
const hori = rectW.width - origSizeW + origSizeW / zoomAmount();
const verti = rectW.height - origSizeH + origSizeH / zoomAmount();
const xP = (clientX() - hori / 2) / (rectW.width - hori);
const yP = (clientY() - verti / 2) / (rectW.height - verti);
setX((xP > 0 ? (xP < 1 ? xP : 1) : 0) * origSizeW);
setY((yP > 0 ? (yP < 1 ? yP : 1) : 0) * origSizeH);
const moving =
clientX() > (rectW.width - origSizeW) / 2 &&
clientX() < rectW.width - (rectW.width - origSizeW) / 2 &&
clientY() > (rectW.height - origSizeH) / 2 &&
clientY() < rectW.height - (rectW.height - origSizeH) / 2;
setMoving(moving);
});
let wrapperRef: HTMLDivElement;
createEffect(() => {
if (active()) return;
setZoomLevel(0);
setMuted(true);
setControlls(false);
});
const handleKeyDown = (event: KeyboardEvent) => {
if (!active() || "Escape" != event.key) return;
event.preventDefault();
setActive("");
};
const handleWheel = (event: WheelEvent) => {
if (!active()) return;
event.preventDefault();
if (event.deltaY > 0 && !(zoomLevel() <= 0)) setZoomLevel((e) => e - 1);
else if (event.deltaY < 0 && !(zoomLevel() >= 4))
setZoomLevel((e) => e + 1);
};
createEffect(() => {
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("wheel", handleWheel, { passive: false });
onCleanup(() => {
window.removeEventListener("keydown", handleKeyDown);
window.removeEventListener("wheel", handleWheel);
});
});
return (
<div
ref={wrapperRef!}
onClick={(e) => e.target === wrapperRef && setActive("")}
onMouseMove={handleMouseMove}
classList={{ "fullscreen-asset": true, active: !!active() }}
>
<Asset
src={active()}
volume={!muted()}
controlls={controlls()}
setRef={setRef}
/>
<div class="controlls">
<button onClick={() => setActive("")} title="Close">
<FontAwesomeIcon icon={faXmark} />
</button>
<Show when={active().startsWith("/videos")}>
<button
onClick={() => setMuted((e) => !e)}
style={{ "border-style": controlls() ? "dashed" : "" }}
title={muted() ? "Unmute" : "Mute"}
>
<FontAwesomeIcon icon={!muted() ? faVolume : faVolumeSlash} />
</button>
<button
onClick={() => setControlls((e) => !e)}
style={{ "border-style": controlls() ? "inset" : "" }}
title="Show controlls"
>
<FontAwesomeIcon icon={faSlidersSimple} />
</button>
</Show>
<button
onClick={() => setZoomLevel((e) => e + 1)}
disabled={zoomLevel() >= 4}
title="Zoom +"
>
<FontAwesomeIcon icon={faMagnifyingGlassPlus} />
</button>
<button
onClick={() => setZoomLevel((e) => e - 1)}
disabled={zoomLevel() <= 0}
title="Zoom -"
>
<FontAwesomeIcon icon={faMagnifyingGlassMinus} />
</button>
</div>
</div>
);
}
function Asset(
props: Asset & {
class?: string;
volume?: boolean;
controlls?: boolean;
setRef?: Setter<HTMLElement | null>;
},
) {
let imgRef: HTMLImageElement;
let videoRef: HTMLVideoElement;
const shouldZoom = () => active() === props.src && !!zoomLevel();
return (
<Switch>
<Match when={props.src.startsWith("/images")}>
<img
ref={imgRef!}
style={
shouldZoom()
? {
"--zoom": zoomAmount(),
"--x": x() + "px",
"--y": y() + "px",
}
: {}
}
onMouseEnter={() => props.setRef && props.setRef(imgRef)}
classList={{
[props.class ?? ""]: !!props.class,
zoomed: shouldZoom(),
move: moving(),
}}
onClick={() => setActive(props.src)}
src={props.src}
alt={props.src}
/>
</Match>
<Match when={props.src.startsWith("/videos")}>
<video
ref={videoRef!}
onMouseEnter={() => props.setRef && props.setRef(videoRef)}
style={
shouldZoom()
? {
"--zoom": zoomAmount(),
"--x": x() + "px",
"--y": y() + "px",
}
: {}
}
classList={{
[props.class ?? ""]: !!props.class,
zoomed: shouldZoom(),
move: moving(),
active: !props.setRef && active() === props.src,
}}
onClick={() => setActive(props.src)}
width="auto"
height="auto"
autoplay
muted={!props.volume}
loop
controls={props.controlls}
>
<source src={props.src} type="video/mp4" />
</video>
</Match>
</Switch>
);
}
return { FullscreenView, Asset };
}
export default AssetHandler;

View file

@ -1,8 +1,10 @@
import { Show } from "solid-js"; import { Show } from "solid-js";
import { A } from "solid-start";
function DeviceTile(props: { href?: string; name: string; src: string }) { function DeviceTile(props: { href?: string; name: string; src: string }) {
return ( return (
<a href={props.href ?? "/soon"}> <A href={props.href ?? "/soon"}>
<div class="raster">
<h3>{props.name}</h3> <h3>{props.name}</h3>
<Show when={props.src.startsWith("/images")}> <Show when={props.src.startsWith("/images")}>
<img src={props.src} alt={props.name} /> <img src={props.src} alt={props.name} />
@ -12,7 +14,8 @@ function DeviceTile(props: { href?: string; name: string; src: string }) {
<source src={props.src} type="video/mp4" /> <source src={props.src} type="video/mp4" />
</video> </video>
</Show> </Show>
</a> </div>
</A>
); );
} }

View file

@ -1,82 +0,0 @@
import { JSX, createEffect, createSignal, onCleanup } from "solid-js";
function ProgressHandler() {
const [scrollPercentage, setScrollPercentage] = createSignal(0);
// const [active, setActive] = createSignal("");
// const [zoomLevel, setZoomLevel] = createSignal(0);
// const zoomAmount = () => 1 + zoomLevel() * 0.5;
// const [x, setX] = createSignal(0);
// const [y, setY] = createSignal(0);
function ProgressBar() {
// const [muted, setMuted] = createSignal(true);
// const [controlls, setControlls] = createSignal(false);
// const [clientX, setClientX] = createSignal(0);
// const [clientY, setClientY] = createSignal(0);
// const [ref, setRef] = createSignal<HTMLElement | null>(null);
const handleScroll = () => {
const scrollHeight =
document.documentElement.scrollHeight - window.innerHeight;
const currentScroll = window.scrollY;
const scrollPercentage = (currentScroll / scrollHeight) * 100;
setScrollPercentage(scrollPercentage);
};
createEffect(() => {
window.addEventListener("scroll", handleScroll);
onCleanup(() => {
window.removeEventListener("scroll", handleScroll);
});
});
createEffect(() => {
// const thisRef = ref();
// if (!thisRef) return;
// const rectA = thisRef.getBoundingClientRect();
// const origSizeW = rectA.width / zoomAmount();
// const origSizeH = rectA.height / zoomAmount();
// const rectW = wrapperRef.getBoundingClientRect();
// const hori = rectW.width - origSizeW + origSizeW / zoomAmount();
// const verti = rectW.height - origSizeH + origSizeH / zoomAmount();
// const xP = (clientX() - hori / 2) / (rectW.width - hori);
// const yP = (clientY() - verti / 2) / (rectW.height - verti);
// setX((xP > 0 ? (xP < 1 ? xP : 1) : 0) * origSizeW);
// setY((yP > 0 ? (yP < 1 ? yP : 1) : 0) * origSizeH);
// const moving =
// clientX() > (rectW.width - origSizeW) / 2 &&
// clientX() < rectW.width - (rectW.width - origSizeW) / 2 &&
// clientY() > (rectW.height - origSizeH) / 2 &&
// clientY() < rectW.height - (rectW.height - origSizeH) / 2;
// setMoving(moving);
});
// let wrapperRef: HTMLDivElement;
createEffect(() => {
// if (active()) return;
// setZoomLevel(0);
// setMuted(true);
// setControlls(false);
});
return (
<div class="progress">
<></>
</div>
);
}
function Chapter(props: { children: JSX.Element }) {
let divRef: HTMLDivElement;
// let videoRef: HTMLVideoElement;
// const shouldZoom = () => active() === props.src && !!zoomLevel();
return <div ref={divRef!}>{props.children}</div>;
}
return { FullscreenView: ProgressBar, Asset: Chapter };
}
export default ProgressHandler;

View file

@ -2,8 +2,9 @@ import {
faArrowUpRightFromSquare, faArrowUpRightFromSquare,
faBookOpen, faBookOpen,
faHashtag, faHashtag,
} from "@fortawesome/pro-regular-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { JSXElement, Show, createMemo } from "solid-js"; import { JSXElement, Show, createMemo } from "solid-js";
import { A } from "solid-start";
import { FontAwesomeIcon } from "./FontAwesomeIcon"; import { FontAwesomeIcon } from "./FontAwesomeIcon";
const types = { const types = {
@ -37,12 +38,12 @@ function R(props: {
return ( return (
<> <>
{" "} {" "}
<a <A
href={props.href} href={props.href}
target={type() === "external" ? "_blank" : ""} target={type() === "external" ? "_blank" : ""}
rel={type() === "external" ? "noreferrer noopener" : ""} rel={type() === "external" ? "noreferrer noopener" : ""}
id={props.id} id={props.id}
classList={{ reference: true, [props.class ?? ""]: !!props.class }} class={props.class}
> >
<Show when={type() === "id"}> <Show when={type() === "id"}>
<FontAwesomeIcon class="left" icon={types["id"]} /> <FontAwesomeIcon class="left" icon={types["id"]} />
@ -51,7 +52,7 @@ function R(props: {
<Show when={type() !== "id"}> <Show when={type() !== "id"}>
<FontAwesomeIcon class="right" icon={types[type()]} title={type()} /> <FontAwesomeIcon class="right" icon={types[type()]} title={type()} />
</Show> </Show>
</a>{" "} </A>{" "}
</> </>
); );
} }

View file

@ -1,15 +0,0 @@
import { JSX, Suspense } from "solid-js";
function Wrapper(props: {
class: string;
classList: Record<string, boolean>;
children: JSX.Element | JSX.Element[];
}) {
return (
<div id="body" class={props.class} classList={props.classList}>
<Suspense>{props.children}</Suspense>
</div>
);
}
export default Wrapper;

View file

@ -1,157 +1,100 @@
import { import {
faBars,
faBookOpen, faBookOpen,
faCircleHalfStroke, faCircleHalfStroke,
faGavel,
faGlobe, faGlobe,
faXmark, faXmark,
} from "@fortawesome/pro-regular-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { import { createSignal } from "solid-js";
useIsRouting, import { A, useNavigate } from "solid-start";
useLocation,
useNavigate,
useSearchParams,
} from "@solidjs/router";
import { createEffect, createSignal, onCleanup } from "solid-js";
import { FontAwesomeIcon } from "../FontAwesomeIcon"; import { FontAwesomeIcon } from "../FontAwesomeIcon";
export const [lightMode, setLightMode] = createSignal(false); export const [lightMode, setLightMode] = createSignal(false);
const [menu, setMenu] = createSignal(false);
function Navbar() { function Navbar() {
const [menu, setMenu] = createSignal(false);
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const [searchParams] = useSearchParams();
const isRouting = useIsRouting();
createEffect(() => {
const mode = searchParams.lightMode;
const prefersDarkMode =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
if (typeof mode === "undefined") {
setLightMode(!prefersDarkMode);
return;
}
const parsedMode = JSON.parse(mode);
if (typeof parsedMode !== "boolean") return;
setLightMode(parsedMode);
});
createEffect(() => {
if (!isRouting() || !menu()) return;
setMenu(false);
});
const handleKeyDown = (event: KeyboardEvent) => {
if (!menu() || "Escape" != event.key) return;
event.preventDefault();
setMenu(false);
};
createEffect(() => {
window.addEventListener("keydown", handleKeyDown);
onCleanup(() => {
window.removeEventListener("keydown", handleKeyDown);
});
});
return ( return (
<> <>
<div id="navbar" style={{ visibility: menu() ? "visible" : "hidden" }}> <div id="navbar" style={{ visibility: menu() ? "visible" : "hidden" }}>
<a href="/de"> <A href="/de/">
<FontAwesomeIcon icon={faBookOpen} /> Einführung <FontAwesomeIcon icon={faBookOpen} /> Einführung
</a> </A>
<a href="/de/overview"> <A href="/de/overview">
<FontAwesomeIcon icon={faBookOpen} /> Start <FontAwesomeIcon icon={faBookOpen} /> Start
</a> </A>
<ol> <ol>
<li> <li>
<a href="/de/overview#start">Was sind EUCs?</a> <A href="/de/overview#start">Was sind EUCs?</A>
</li> </li>
<li> <li>
<a href="/de/overview#why">Warum EUCs?</a> <A href="/de/overview#why">Warum EUCs?</A>
</li> </li>
<li> <li>
<a href="/de/overview#funktion">Funktionsweise</a> <A href="/de/overview#funktion">Funktionsweise</A>
</li> </li>
<li> <li>
<a href="/de/overview#begriffe">Begriffe</a> <A href="/de/overview#begriffe">Begriffe</A>
</li> </li>
<li> <li>
<a href="/de/overview#sicherheit">Sicherheit</a> <A href="/de/overview#sicherheit">Sicherheit</A>
</li> </li>
<li> <li>
<a href="/de/overview#ausrüstung">Ausrüstung</a> <A href="/de/overview#ausrüstung">Ausrüstung</A>
</li> </li>
<li> <li>
<a href="/de/overview#cutout">Cut-out's</a> <A href="/de/overview#cutout">Cut-out's</A>
</li> </li>
<li> <li>
<a href="/de/overview#akkuss">Akkusicherheit</a> <A href="/de/overview#akkuss">Akkusicherheit</A>
</li> </li>
<li> <li>
<a href="/de/overview#fahrweise">Fahrweise</a> <A href="/de/overview#fahrweise">Fahrweise</A>
</li> </li>
<li> <li>
<a href="/de/overview#wobbles">Wobbles</a> <A href="/de/overview#wobbles">Wobbles</A>
</li> </li>
<li> <li>
<a href="/de/overview#leistung">Leistung</a> <A href="/de/overview#leistung">Leistung</A>
</li> </li>
<li> <li>
<a href="/de/overview#federung">Federung</a> <A href="/de/overview#federung">Federung</A>
</li> </li>
<li> <li>
<a href="/de/overview#reifen">Reifen</a> <A href="/de/overview#reifen">Reifen</A>
</li> </li>
<li> <li>
<a href="/de/overview#historie">Historie</a> <A href="/de/overview#historie">Historie</A>
</li> </li>
<li> <li>
<a href="/de/overview#geraete">Geräte Liste</a> <A href="/de/overview#geräte">Geräte Liste</A>
</li> </li>
</ol> </ol>
<a href="/de/manufacturers"> <A href="/de/manufacturers">
<FontAwesomeIcon icon={faBookOpen} /> Hersteller <FontAwesomeIcon icon={faBookOpen} /> Hersteller
</a> </A>
<a href="/de/imprint"> <button onClick={() => setLightMode((e) => !e)}>
<FontAwesomeIcon icon={faGavel} /> Impressum
</a>
<div class="modes">
<button
onClick={() => {
const mode = !lightMode() ? "?lightMode=true" : "";
const url = location.pathname + mode;
navigate(url, {
replace: true,
scroll: false,
});
}}
>
{lightMode() ? "Dark Mode " : "Light Mode "} {lightMode() ? "Dark Mode " : "Light Mode "}
<FontAwesomeIcon icon={faCircleHalfStroke} /> <FontAwesomeIcon icon={faCircleHalfStroke} />
</button> </button>
<button <button onClick={() => navigate("/en/overview")}>
onClick={() =>
navigate("/en" + location.pathname.slice(3), { scroll: false })
}
>
Englisch <FontAwesomeIcon icon={faGlobe} /> Englisch <FontAwesomeIcon icon={faGlobe} />
</button> </button>
<button onClick={() => setMenu(false)}> <button onClick={() => setMenu(false)}>
Close <FontAwesomeIcon icon={faXmark} /> Close <FontAwesomeIcon icon={faXmark} />
</button> </button>
</div> </div>
</div>
<button class="menu" title="Menu" onClick={() => setMenu(true)}> <div
<FontAwesomeIcon icon={faBars} /> id="sidenavbar"
</button> style={{ visibility: menu() ? "hidden" : "visible" }}
>
<button onClick={() => navigate(-1)}>Zurück</button>
<A href="#start">Start</A>
<button onClick={() => setMenu(true)}>Menu</button>
</div>
</> </>
); );
} }

View file

@ -1,157 +1,100 @@
import { import {
faBars,
faBookOpen, faBookOpen,
faCircleHalfStroke, faCircleHalfStroke,
faGavel,
faGlobe, faGlobe,
faXmark, faXmark,
} from "@fortawesome/pro-regular-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { import { createSignal } from "solid-js";
useIsRouting, import { A, useNavigate } from "solid-start";
useLocation,
useNavigate,
useSearchParams,
} from "@solidjs/router";
import { createEffect, createSignal, onCleanup } from "solid-js";
import { FontAwesomeIcon } from "../FontAwesomeIcon"; import { FontAwesomeIcon } from "../FontAwesomeIcon";
export const [lightMode, setLightMode] = createSignal(false); export const [lightMode, setLightMode] = createSignal(false);
const [menu, setMenu] = createSignal(false);
function Navbar() { function Navbar() {
const [menu, setMenu] = createSignal(false);
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const [searchParams] = useSearchParams();
const isRouting = useIsRouting();
createEffect(() => {
const mode = searchParams.lightMode;
const prefersDarkMode =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
if (typeof mode === "undefined") {
setLightMode(!prefersDarkMode);
return;
}
const parsedMode = JSON.parse(mode);
if (typeof parsedMode !== "boolean") return;
setLightMode(parsedMode);
});
createEffect(() => {
if (!isRouting() || !menu()) return;
setMenu(false);
});
const handleKeyDown = (event: KeyboardEvent) => {
if (!menu() || "Escape" != event.key) return;
event.preventDefault();
setMenu(false);
};
createEffect(() => {
window.addEventListener("keydown", handleKeyDown);
onCleanup(() => {
window.removeEventListener("keydown", handleKeyDown);
});
});
return ( return (
<> <>
<div id="navbar" style={{ visibility: menu() ? "visible" : "hidden" }}> <div id="navbar" style={{ visibility: menu() ? "visible" : "hidden" }}>
<a href="/en"> <A href="/en/">
<FontAwesomeIcon icon={faBookOpen} /> Introduction <FontAwesomeIcon icon={faBookOpen} /> Introduction
</a> </A>
<a href="/en/overview"> <A href="/en/overview">
<FontAwesomeIcon icon={faBookOpen} /> Start <FontAwesomeIcon icon={faBookOpen} /> Start
</a> </A>
<ol> <ol>
<li> <li>
<a href="/en/overview#start">What are EUCs?</a> <A href="/en/overview#start">What are EUCs?</A>
</li> </li>
<li> <li>
<a href="/en/overview#why">Why EUCs?</a> <A href="/en/overview#why">Why EUCs?</A>
</li> </li>
<li> <li>
<a href="/en/overview#funktion">Functionality</a> <A href="/en/overview#funktion">Functionality</A>
</li> </li>
<li> <li>
<a href="/en/overview#begriffe">Glossarry</a> <A href="/en/overview#begriffe">Glossarry</A>
</li> </li>
<li> <li>
<a href="/en/overview#sicherheit">Safety</a> <A href="/en/overview#sicherheit">Safety</A>
</li> </li>
<li> <li>
<a href="/en/overview#ausrüstung">Gear</a> <A href="/en/overview#ausrüstung">Gear</A>
</li> </li>
<li> <li>
<a href="/en/overview#cutout">Cut-out's</a> <A href="/en/overview#cutout">Cut-out's</A>
</li> </li>
<li> <li>
<a href="/en/overview#akkuss">Battery safety</a> <A href="/en/overview#akkuss">Battery safety</A>
</li> </li>
<li> <li>
<a href="/en/overview#fahrweise">Ride style</a> <A href="/en/overview#fahrweise">Ride style</A>
</li> </li>
<li> <li>
<a href="/en/overview#wobbles">Wobbles</a> <A href="/en/overview#wobbles">Wobbles</A>
</li> </li>
<li> <li>
<a href="/en/overview#leistung">Performance</a> <A href="/en/overview#leistung">Performance</A>
</li> </li>
<li> <li>
<a href="/en/overview#federung">Suspension</a> <A href="/en/overview#federung">Suspension</A>
</li> </li>
<li> <li>
<a href="/en/overview#reifen">Tires</a> <A href="/en/overview#reifen">Tires</A>
</li> </li>
<li> <li>
<a href="/en/overview#historie">History</a> <A href="/en/overview#historie">History</A>
</li> </li>
<li> <li>
<a href="/en/overview#geraete">Device list</a> <A href="/en/overview#geräte">Device list</A>
</li> </li>
</ol> </ol>
<a href="/en/manufacturers"> <A href="/en/manufacturers">
<FontAwesomeIcon icon={faBookOpen} /> Manufacturers <FontAwesomeIcon icon={faBookOpen} /> Manufacturers
</a> </A>
<a href="/de/imprint"> <button onClick={() => setLightMode((e) => !e)}>
<FontAwesomeIcon icon={faGavel} /> Legal Notice (DE)
</a>
<div class="modes">
<button
onClick={() => {
const mode = !lightMode() ? "?lightMode=true" : "";
const url = location.pathname + mode;
navigate(url, {
replace: true,
scroll: false,
});
}}
>
{lightMode() ? "Dark Mode " : "Light Mode "} {lightMode() ? "Dark Mode " : "Light Mode "}
<FontAwesomeIcon icon={faCircleHalfStroke} /> <FontAwesomeIcon icon={faCircleHalfStroke} />
</button> </button>
<button <button onClick={() => navigate("/de/overview")}>
onClick={() =>
navigate("/de" + location.pathname.slice(3), { scroll: false })
}
>
Deutsch <FontAwesomeIcon icon={faGlobe} /> Deutsch <FontAwesomeIcon icon={faGlobe} />
</button> </button>
<button onClick={() => setMenu(false)}> <button onClick={() => setMenu(false)}>
Close <FontAwesomeIcon icon={faXmark} /> Close <FontAwesomeIcon icon={faXmark} />
</button> </button>
</div> </div>
</div>
<button class="menu" title="Menu" onClick={() => setMenu(true)}> <div
<FontAwesomeIcon icon={faBars} /> id="sidenavbar"
</button> style={{ visibility: menu() ? "hidden" : "visible" }}
>
<button onClick={() => navigate(-1)}>Back</button>
<A href="#start">Start</A>
<button onClick={() => setMenu(true)}>Menu</button>
</div>
</> </>
); );
} }

View file

@ -1,3 +1,3 @@
import { mount, StartClient } from "@solidjs/start/client"; import { mount, StartClient } from "solid-start/entry-client";
mount(() => <StartClient />, document.getElementById("app")!); mount(() => <StartClient />, document);

View file

@ -1,29 +1,9 @@
import { StartServer, createHandler } from "@solidjs/start/server"; import {
import { getRequestEvent } from "solid-js/web"; createHandler,
renderAsync,
StartServer,
} from "solid-start/entry-server";
export default createHandler(() => ( export default createHandler(
<StartServer renderAsync((event) => <StartServer event={event} />),
document={({ assets, children, scripts }) => { );
const event = getRequestEvent();
const pathname = event?.request.url
? new URL(event?.request.url).pathname
: "/";
return (
<html lang={pathname.startsWith("/de") ? "de" : "en"}>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
{assets}
</head>
<body id="app">
{children}
{scripts}
</body>
</html>
);
}}
/>
));

2
src/global.d.ts vendored
View file

@ -1 +1 @@
/// <reference types="@solidjs/start/env" /> /// <reference types="solid-start/env" />

115
src/root.tsx Normal file
View file

@ -0,0 +1,115 @@
// @refresh reload
import "@fortawesome/fontawesome-svg-core/styles.css";
import { Suspense } from "solid-js";
import {
FileRoutes,
Head,
Html,
Link,
Meta,
Routes,
Scripts,
Title,
useLocation,
} from "solid-start";
export default function Root() {
const location = useLocation();
return (
<Html lang={location.pathname.startsWith("/de") ? "de" : "en"}>
<Head>
<Link
rel="apple-touch-icon"
sizes="57x57"
href="/favicon/apple-icon-57x57.png"
/>
<Link
rel="apple-touch-icon"
sizes="60x60"
href="/favicon/apple-icon-60x60.png"
/>
<Link
rel="apple-touch-icon"
sizes="72x72"
href="/favicon/apple-icon-72x72.png"
/>
<Link
rel="apple-touch-icon"
sizes="76x76"
href="/favicon/apple-icon-76x76.png"
/>
<Link
rel="apple-touch-icon"
sizes="114x114"
href="/favicon/apple-icon-114x114.png"
/>
<Link
rel="apple-touch-icon"
sizes="120x120"
href="/favicon/apple-icon-120x120.png"
/>
<Link
rel="apple-touch-icon"
sizes="144x144"
href="/favicon/apple-icon-144x144.png"
/>
<Link
rel="apple-touch-icon"
sizes="152x152"
href="/favicon/apple-icon-152x152.png"
/>
<Link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-icon-180x180.png"
/>
<Link
rel="icon"
type="image/png"
sizes="192x192"
href="/favicon/android-icon-192x192.png"
/>
<Link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png"
/>
<Link
rel="icon"
type="image/png"
sizes="96x96"
href="/favicon/favicon-96x96.png"
/>
<Link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon/favicon-16x16.png"
/>
<Link rel="manifest" href="/favicon/manifest.json" />
<Meta name="msapplication-TileColor" content="#ffffff" />
<Meta
name="msapplication-TileImage"
content="/favicon/ms-icon-144x144.png"
/>
<Meta name="theme-color" content="#ffffff" />
<Meta http-equiv="X-UA-Compatible" content="IE=edge" />
<Meta charset="UTF-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1.0" />
<Meta name="author" content="Julian Gerhardt" />
<Meta
name="keywords"
content="Elektrische einräder, EUC, Monowheels, Kingsong, Inmotion, Gotway"
/>
<Title>SolidStart - Bare</Title>
</Head>
<Suspense>
<Routes>
<FileRoutes />
</Routes>
</Suspense>
<Scripts />
</Html>
);
}

View file

@ -1,26 +1,19 @@
import { Title } from "@solidjs/meta"; import { Title } from "solid-start";
import { useNavigate } from "@solidjs/router"; import { HttpStatusCode } from "solid-start/server";
import { HttpStatusCode } from "@solidjs/start";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/overview.scss";
export default function NotFound() { export default function NotFound() {
const navigate = useNavigate();
return ( return (
<Wrapper class="overview" classList={{ "light-mode": lightMode() }}> <main>
<Title>Not Found</Title> <Title>Not Found</Title>
<HttpStatusCode code={404} /> <HttpStatusCode code={404} />
<Navbar /> <h1>Page Not Found</h1>
<div <p>
style={{ Visit{" "}
"min-height": "100vh", <a href="https://start.solidjs.com" target="_blank">
display: "inline-block", start.solidjs.com
}} </a>{" "}
> to learn how to build SolidStart apps.
<p style={{ "text-align": "center" }}>This side could not be found.</p> </p>
<button onClick={() => navigate(-1)}>Back</button> </main>
</div>
</Wrapper>
); );
} }

View file

@ -1,75 +1,80 @@
import { Title } from "@solidjs/meta"; import { Body, Link, Title, useNavigate } from "solid-start";
import AssetHandler from "~/components/Asset"; import { lightMode } from "~/components/en/Navbar";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/devices.scss";
function KSS22() { function KSS22() {
const { FullscreenView, Asset } = AssetHandler(); const navigate = useNavigate();
return ( return (
<Wrapper class="devices" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>KS S22</Title> <Title>KS S22</Title>
<FullscreenView /> <Link rel="stylesheet" href="/styles/devices.css" />
<Navbar />
<article> <div id="sidenavbar">
<div> <button onClick={() => navigate(-1)}>Zurück</button>
<h2>Kingsong S22</h2> <button onClick={() => navigate("/de/overview")}>Start</button>
<div class="righties">
<Asset src="/images/KSS22/S22shutterkode2.jpg" />
</div> </div>
<div class="row">
<div class="col-4">
<img src="/images/KSS22/S22shutterkode2.jpg" />
</div>
<div class="col-8">
<article>
<h2>Kingsong S22</h2>
<p> <p>
Das Kingsong S22, früher S20, ist ein klar Offroad und Trail Das Kingsong S22, früher S20, ist ein klar Offroad und Trail
orientiertes Einrad. Es hat unter anderem 130 mm travel und eine orientiertes Einrad. Es hat unter anderem 130mm travel und eine
robuste Metallkonstruktion, welches es einmalig ideal für große robuste Metallkonstruktion, welches es einmalig ideal für große
Sprünge und hohe Drops macht. Sprünge und hohe Drops macht.
</p> </p>
<p> <p>
Es ist der Nachfolger vom kleineren S18, aber mit doppeltem Akku und Es ist der Nachfolger vom kleineren S18, aber mit doppeltem Akku
50 % mehr Motor Leistung, so wie 70 statt 50 km/h top und 50% mehr Motor Leistung, so wie 70 statt 50 km/h top
Geschwindigkeit. Wobei der Freespin bis zu 114 km/h hoch ist, also Geschwindigkeit. Wobei der Freespin bis zu 114 km/h hoch ist, also
ideal für längere Sprünge bei denen der Reifen in der Luft ist. ideal für längere Sprünge bei denen der Reifen in der Luft ist.
</p> </p>
<p> <p>
Außerdem hat es gleich mitgeliefert einen Sitz, ziemlich brauchbare Außerdem hat es gleich mitgeliefert einen Sitz, ziemlich
Jump wie Powerpads und Spiked-Pedals. Dazu einen robusten, wenn auch brauchbare Jump wie Powerpads und Spiked-Pedals. Dazu einen
komisch platzierten und etwas kurzen Trolleyhandle, sowie einen robusten, wenn auch komisch platzierten und etwas kurzen
stabilen Kickstand und höhenverstellbare helle Lichter. Es ist Trolleyhandle, sowie einen stabilen Kickstand und
Wasserfest, aber nicht eintauchbar, und das Beste: es ist höhenverstellbare helle Lichter. Es ist Wasserfest, aber nicht
superleicht daran zu arbeiten, weil das Gerät sehr modular designt eintauchbar, und das Beste: es ist superleicht daran zu arbeiten,
wurde. So lässt sich der Reifen mit theoretisch nur 2 schrauben weil das Gerät sehr modular designt wurde. So lässt sich der
rausnehmen Reifen mit theoretisch nur 2 schrauben rausnehmen
</p> </p>
<p> <p>
Während all das wahr ist, haben sich leider mit diesem hoch Während all das wahr ist, haben sich leider mit diesem hoch
erwartetem und gehypten Rad auch viele Probleme ergeben. So gab es erwartetem und gehypten Rad auch viele Probleme ergeben. So gab es
Motorprobleme mit den ersten Geräten, welche zu cut-offs führten und Motorprobleme mit den ersten Geräten, welche zu cut-offs führten
dadurch das Motherboard durchbrannten. Auch ist das Slider Design und dadurch das Motherboard durchbrannten. Auch ist das Slider
sehr schwerfällig und über die Zeit immer schwerer zu bewegen. So Design sehr schwerfällig und über die Zeit immer schwerer zu
mussten viele s22 Käufer lange auf Ersatzmotoren warten, so wie für bewegen. So mussten viele s22 Käufer lange auf Ersatzmotoren
100 bis 200 die Slider upgraden. Mit den Upgrades jedoch ist es warten, so wie für 100 bis 200 die Slider upgraden. Mit den
das momentan bester Suspension Einrad auf dem Markt. (Bis das Upgrades jedoch ist es das momentan bester Suspension Einrad auf
Veteran Sherman S zu kaufen ist.) dem Markt. (Bis das Veteran Sherman S zu kaufen ist.)
</p> </p>
</article>
</div>
</div> </div>
<div class="grid"> <div class="row">
<Asset src="/images/KSS22/S22shutterkode5.jpg" /> <div class="col-4">
<Asset class="span-2" src="/images/KSS22/BusJump.jpg" /> <img src="/images/KSS22/S22shutterkode5.jpg" />
<Asset src="/images/KSS22/S22shutterkode4.jpg" /> </div>
<div class="col-4">
<img src="/images/KSS22/BusJump.jpg" />
</div>
<div class="col-4">
<img src="/images/KSS22/S22shutterkode4.jpg" />
</div>
</div> </div>
<table> <table>
<thead>
<tr>
<th>Eigenschaft</th>
<th>Wert</th>
</tr>
</thead>
<tbody> <tbody>
<tr> <tr>
<td>Größe</td> <td>Größe</td>
@ -81,15 +86,15 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Pedalhöhe</td> <td>Pedalhöhe</td>
<td>231 &plusmn; 26 mm</td> <td>231+-26mm</td>
</tr> </tr>
<tr> <tr>
<td>Gewicht</td> <td>Gewicht</td>
<td>35 kg</td> <td>35kg</td>
</tr> </tr>
<tr> <tr>
<td>Suspension travel (bei Federung)</td> <td>Suspension travel (bei Federung)</td>
<td>130 mm</td> <td>130mm</td>
</tr> </tr>
<tr> <tr>
<td>Suspension Type (bei Federung)</td> <td>Suspension Type (bei Federung)</td>
@ -101,19 +106,19 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Freespin</td> <td>Freespin</td>
<td>114 km/h</td> <td>114kmh</td>
</tr> </tr>
<tr> <tr>
<td>Top speed</td> <td>Top speed</td>
<td>70 km/h</td> <td>70kmh</td>
</tr> </tr>
<tr> <tr>
<td>Reichweite bei 30 km/h</td> <td>Reichweite bei 30kmh</td>
<td>200 km</td> <td>200km</td>
</tr> </tr>
<tr> <tr>
<td>Minimale Reichweite bei starker Nutzung</td> <td>Minimale Reichweite bei starker Nutzung</td>
<td>70 km</td> <td>70km</td>
</tr> </tr>
<tr> <tr>
<td>Max climb angle</td> <td>Max climb angle</td>
@ -121,7 +126,7 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Max. Zuladung</td> <td>Max. Zuladung</td>
<td>120 kg</td> <td>120kg</td>
</tr> </tr>
<tr> <tr>
@ -130,23 +135,23 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Motor Leistung</td> <td>Motor Leistung</td>
<td>3.300 W</td> <td>3300W</td>
</tr> </tr>
<tr> <tr>
<td>Peak Leistung</td> <td>Peak Leistung</td>
<td>7.500 W</td> <td>7500W</td>
</tr> </tr>
<tr> <tr>
<td>Battery Size</td> <td>Battery Size</td>
<td>2.220 Wh</td> <td>2220wh</td>
</tr> </tr>
<tr> <tr>
<td>Voltage</td> <td>Voltage</td>
<td>126 V</td> <td>126V</td>
</tr> </tr>
<tr> <tr>
<td>Max amps</td> <td>Max amps</td>
<td>100 A</td> <td>100A</td>
</tr> </tr>
<tr> <tr>
<td>BMS</td> <td>BMS</td>
@ -167,11 +172,11 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Lichter</td> <td>Lichter</td>
<td>8 x 5 W Verstellbare Scheinwerfer</td> <td>8x5W Verstellbare Scheinwerfer</td>
</tr> </tr>
<tr> <tr>
<td>Standard Reifen</td> <td>Standard Reifen</td>
<td>Knobby (Noppenreifen)</td> <td>Nobby</td>
</tr> </tr>
<tr> <tr>
<td>Anti spin button?</td> <td>Anti spin button?</td>
@ -199,15 +204,15 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Standard Ladezeit:</td> <td>Standard Ladezeit:</td>
<td>3,3 h</td> <td>3.3h</td>
</tr> </tr>
<tr> <tr>
<td>Max Amps:</td> <td>Max Amps:</td>
<td>10 A</td> <td>10A</td>
</tr> </tr>
<tr> <tr>
<td>Schnellste Ladezeit:</td> <td>Schnellste Ladezeit:</td>
<td>100 Minuten</td> <td>100 Min</td>
</tr> </tr>
<tr> <tr>
<td>Ladeports:</td> <td>Ladeports:</td>
@ -215,8 +220,7 @@ function KSS22() {
</tr> </tr>
</tbody> </tbody>
</table> </table>
</article> </Body>
</Wrapper>
); );
} }

View file

@ -1,55 +0,0 @@
import { Title } from "@solidjs/meta";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/overview.scss";
function imprint() {
return (
<Wrapper class="overview" classList={{ "light-mode": lightMode() }}>
<Title>Impressum</Title>
<Navbar />
<article
style={{
"min-height": "100vh",
display: "inline-block",
}}
>
<h1>Impressum</h1>
<h2>Verantwortlich für den Inhalt gemäß § 18 Abs. 1 MStV:</h2>
<p>Julian Gerhardt</p>
<h2>Technischer Ansprechpartner:</h2>
<p>
Aron Malcher
<br />
<br />
Unlimited Development
<br />
<br />
Brunnenstr. 12
<br />
48531 Nordhorn
<br />
Deutschland
<br />
<br />
E-Mail:{" "}
<a href="mailto:aron@unlimited-dev.de">aron@unlimited-dev.de</a>
</p>
<h2>Hinweis:</h2>
<p>
Die redaktionelle Verantwortung für die Inhalte der Webseite liegt bei
Julian Gerhardt. Technische Fragen und Anfragen richten Sie bitte an
den technischen Ansprechpartner von Unlimited Development, welche als
Hosting- und IT-Service agiert, jedoch nicht für den redaktionellen
Inhalt verantwortlich ist.
</p>
</article>
</Wrapper>
);
}
export default imprint;

View file

@ -1,19 +1,14 @@
import { faYoutube } from "@fortawesome/free-brands-svg-icons"; import { faYoutube } from "@fortawesome/free-brands-svg-icons";
import { faBookOpen, faGlobe } from "@fortawesome/pro-regular-svg-icons"; import { faBookOpen, faGlobe } from "@fortawesome/free-solid-svg-icons";
import { Title } from "@solidjs/meta"; import { A, Body, Link, Title } from "solid-start";
import AssetHandler from "~/components/Asset";
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"; import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
import Wrapper from "~/components/Wrapper";
import { lightMode } from "~/components/de/Navbar"; import { lightMode } from "~/components/de/Navbar";
import "~/styles/start.scss";
function Introduction() { function Introduction() {
const { FullscreenView, Asset } = AssetHandler();
return ( return (
<Wrapper class="start" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>Einführung</Title> <Title>Einführung</Title>
<Link rel="stylesheet" href="/styles/start.css" />
<FullscreenView />
<div class="container"> <div class="container">
<img id="cover" src="/images/Gear3.webp" /> <img id="cover" src="/images/Gear3.webp" />
@ -28,52 +23,66 @@ function Introduction() {
Flexible - Modern - schneller als die Polizei erlaubt. Das sind moderne Flexible - Modern - schneller als die Polizei erlaubt. Das sind moderne
eletrische Einräder. eletrische Einräder.
</p> </p>
<Asset src="/images/ShermanStanding.jpg" /> <div class="righties">
<img src="/images/ShermanStanding.jpg" />
</div>
<p> <p>
Von 0 auf 50 km/h in 3 s, 100 km/h top Geschwindigkeit und 230 km Von 0 auf 50kmh in 3s, 100kmh top Geschwindigkeit und 230km Reichweite
Reichweite machen aus diesen Geräten den ultimativen Sport. machen aus diesen Geräten den ultimativen Sport.
</p> </p>
<Asset src="/images/UltimativeSport.jpg" /> <div class="righties">
<img src="/images/UltimativeSport.jpg" />
</div>
<p> <p>
Gleichzeitig 50° steile Wände hochfahren und MTB Trails mit leichtigkeit Gleichzeitig 50° steile Wände hochfahren und MTB Trails mit leichtigkeit
nehmen. nehmen.
</p> </p>
<Asset src="/videos/MTBtrailsEase.mp4" /> <div class="righties">
<video width="auto" height="auto" autoplay muted loop>
<source src="/videos/MTBtrailsEase.mp4" type="video/mp4" />
</video>
</div>
<p>Jeden Weg nutzen und nie wieder im Verkehr stecken.</p> <p>Jeden Weg nutzen und nie wieder im Verkehr stecken.</p>
<Asset src="/videos/traffic.mp4" /> <div class="righties">
<video width="auto" height="auto" autoplay muted loop>
<source src="/videos/traffic.mp4" type="video/mp4" />
</video>
</div>
<p>Und trotzdem leicht zu transportiren und untern Tisch zu packen.</p> <p>Und trotzdem leicht zu transportiren und untern Tisch zu packen.</p>
<Asset src="/images/KidsKS16X.jpg" /> <div class="righties">
<img src="/images/KidsKS16X.jpg" />
</div>
<p>Interessiert? Dann tauche in die Welt der PEV's und EUC's ein:</p> <p>Interessiert? Dann tauche in die Welt der PEV's und EUC's ein:</p>
<a href="/de/overview"> <A href="/de/overview">
<div id="MoreButton"> <div id="MoreButton">
<p> <p>
Ich will alles darüber lesen! <FontAwesomeIcon icon={faBookOpen} /> Ich will alles darüber lesen! <FontAwesomeIcon icon={faBookOpen} />
</p> </p>
</div> </div>
</a> </A>
<a href="https://youtube.com/playlist?list=PLfoxTRt1qLuAg-Al9JNHrl_7KVl-uSxwV"> <A href="https:/youtube.com/playlist?list=PLfoxTRt1qLuAg-Al9JNHrl_7KVl-uSxwV">
<div id="MoreButton"> <div id="MoreButton">
<p> <p>
Mir reichen Videos <FontAwesomeIcon icon={faYoutube} /> Mir reichen Videos <FontAwesomeIcon icon={faYoutube} />
</p> </p>
</div> </div>
</a> </A>
<a href="/en"> <A href="/en/">
<div id="MoreButton"> <div id="MoreButton">
<p> <p>
Switch to English <FontAwesomeIcon icon={faGlobe} /> Switch to English <FontAwesomeIcon icon={faGlobe} />
</p> </p>
</div> </div>
</a> </A>
</Wrapper> </Body>
); );
} }

View file

@ -1,23 +1,18 @@
import { Title } from "@solidjs/meta"; import { Body, Link, Title } from "solid-start";
import AssetHandler from "~/components/Asset";
import R from "~/components/Reference"; import R from "~/components/Reference";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/de/Navbar"; import Navbar, { lightMode } from "~/components/de/Navbar";
import "~/styles/overview.scss";
function Manufacturers() { function Manufacturers() {
const { FullscreenView, Asset } = AssetHandler();
return ( return (
<Wrapper class="overview" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>Hersteller</Title> <Title>Hersteller</Title>
<FullscreenView /> <Link rel="stylesheet" href="/styles/overview.css" />
<Navbar /> <Navbar />
<article> <article>
{/* {/*
<!--hersteller--> <!--hersteller-->
*/} */}
<div> <div class="row">
<h3 id="manufacturers">Erklärung und Geschichte der Produzenten</h3> <h3 id="manufacturers">Erklärung und Geschichte der Produzenten</h3>
<p> <p>
Es gibt/gab viele Hersteller von elektrischen Einrädern, hier werden Es gibt/gab viele Hersteller von elektrischen Einrädern, hier werden
@ -29,22 +24,17 @@ function Manufacturers() {
</p> </p>
<h3 id="ninebot"> <h3 id="ninebot">
Ninebot <img src="/images/ninebotLogo.jpg" /> Ninebot <img class="logos" src="/images/ninebotLogo.jpg" />
</h3> </h3>
<img class="righties" src="/images/NineBot.webp" />
<div class="righties"> <img class="lefties" src="/images/NinebotZ10goood.webp" />
<Asset src="/images/NineBot.webp" />
</div>
<div class="lefties">
<Asset src="/images/NinebotZ10goood.webp" />
</div>
<p> <p>
Ninebot ist für die Meisten bekannt als Scooter Hersteller, manche Ninebot ist für die Meisten bekannt als Sooter Hersteller, manche
kenne auch vielleicht deren elektrische Schuhe oder die Segway kenne auch vielleicht deren elektrische Schuhe oder die Segway
ähnlichen Geräte mit kurzer Lenkstange. Ninebot ist die größte und ähnlichen Geräte mit kurzer Lenkstange. Ninebot ist die größte und
vielseitigste Firma der hier gelisteten. Sie experimentieren viel vielseitigste Firma der hier gelisteten. Sie experimentieren viel
herum, und haben bei den standard-Scootern viel Erfolg, aber leider herum, und haben bei den standard-Scootern viel Erfolg, aber leider
bei den Einrädern aufgegeben. So gibt es heute nur wenige Modelle, bei den Einrädern aufgegeben. So gibt es Heute nur wenige Modelle,
alle sind eher Anfängergeräte bis untere Mittelklasse. Trotzdem hat alle sind eher Anfängergeräte bis untere Mittelklasse. Trotzdem hat
Ninebot vor allem durch das Ninebot Z10 ein ikonisches Gerät auf dem Ninebot vor allem durch das Ninebot Z10 ein ikonisches Gerät auf dem
Markt hinterlassen, welches durch außergewöhnliches Design und Markt hinterlassen, welches durch außergewöhnliches Design und
@ -52,103 +42,91 @@ function Manufacturers() {
</p> </p>
<h3 id="inmotion"> <h3 id="inmotion">
Inmotion <img src="/images/inmotionLogo.png" /> Inmotion <img class="logos" src="/images/inmotionLogo.png" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/InmotionLineup.jpg" />
<Asset src="/images/InmotionLineup.jpg" /> <img class="lefties" src="/images/V11 3.webp" />
</div>
<div class="lefties">
<Asset src="/images/V11 3.webp" />
</div>
<p> <p>
Inmotion ist der zweitgrößte Hersteller der hier gelisteten. Inmotion ist der zweitgrößte Hersteller der hier gelisteten.
Ebenfalls groß im standard-Scooter Segment, hat Inmotion aber auch Ebenfallsgroß im standard-Scooter Segment, hat Inmotion aber auch
einen großen, wenn nicht den größten Marktanteil an EUCs. Vor allen einen großen wenn nicht den größten Marktanteil an EUCs. Vor allen
das Inmotion V8 hat als Einsteiger und Commuter Gerät eine hohe das Inmotion V8 hat als einsteiger und Commuter Gerät eine hohe
Beliebtheit und somit hohe Verkaufszahlen. Auch war es Inmotion, Beliebtheit und somit hohe Verkaufszahlen. Auch war es Inmotion,
welches das äußerst professionell aussehende erste Suspension EUC welches das äußerst professionell aussehende erste Suspension EUC
V11 auf den Markt brachte. Inmotion steht im Allgemeinen für V11 auf den Markt brachte. Inmotion steht im allgemeinen für
Qualität, Design und Sicherheit dank gutem{" "} Qualität, Design und Sicherheit dank gutem{" "}
<R href="#tiltback">Tiltback</R> und hoher Sicherheitsmarge. Aber <R href="#tiltback">Tiltback</R> und hoher Sicherheitsmarge. Aber
das alles im Tausch gegen Performance. Bis vor kurzem war Inmotion das alles im Tausch gegen Performance. Bis vor kurzem war Inmotion
Synonym für schwach und wenig Reichweite. Das änderte sich, als das Synonym für schwach und wenig Reichweite. Das änderte sich, als das
V12 rauskam und bald das V13 rauskommt. Jetzt erhofft man sich V12 rauskam und bald das V13 rauskommt. Jetzt erhofft man sich
sichere und gut designte 90+ km/h mit hoher Sicherheitsmarge, und sichere und gut designte 90+kmh mit hoher Sicherheitsmarge, und
sollte das V13 funktionieren wie erhofft wird es das Image der Firma sollte das V13 funktionieren wie erhofft wird es das Image der Firma
ändern. ändern.
</p> </p>
<h3 id="kingsong"> <h3 id="kingsong">
Kingsong <img src="/images/kingsongLogo.png" /> Kingsong <img class="logos" src="/images/kingsongLogo.png" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/KidsKS16X.jpg" />
<Asset src="/images/KidsKS16X.jpg" /> <img class="lefties" src="/images/kingsong2.jpg" />
</div>
<div class="lefties">
<Asset src="/images/kingsong2.jpg" />
</div>
<p> <p>
Kingsong ist sehr ähnlich zu Inmotion, nur kleiner und ohne den Kingsong ist sehr ähnlich zu Inmotion, nur kleiner und ohne den
großen Scooter und E-Bike Markt dahinter. Qualität und Design waren großen Scooter und E-bike Markt dahinter. Qualität und Design waren
die Merkmale, so wie Langlebigkeit und Robustheit. Mit dem S18 war die Merkmale, so wie Langlebigkeit und Robustheit. Mit dem S18 war
Kingsong auch einer der ersten Firmen mit Federung für EUCs. Kingsong auch einer der ersten Firmen mit Federung für EUCs.
Kingsong pionierte das heute oft genutzte Schwingarm Design für Kingsong pionierte das heute oft genutze Schwingarm Design für
Federungen. Aber mit dem S18, und später S20 hat das Image etwas Federungen. Aber mit dem S18, und später S20 hat das Image etwas
Schaden genommen. Beide Geräte hatten große Problem am Anfang, bis Schaden genommen. Beide Geräte hatten große Proble am Anfang, bis
hin zum Abbrennen des S20 Prototypen. Trotzdem waren beide Geräte hin zum abbrennen des S20 Prototypen. Trotzdem waren beide Geräte
ein großer Erfolg, und die Fehler wurden größtenteils behoben. ein großer Erfolg, und die Fehler wurden größtenteils behoben.
Kingsong ist ebenfalls bekannt für die extrem guten{" "} Kingsong ist ebenfals bekannt für die extrem guten{" "}
<R href="#trolley">Trolley Handle</R>, wie der beim KS 16X und <R href="#trolley">Trolley Handle</R>, wie der beim KS 16X und
vorherigen Modellen. voherigen Modellen.
</p> </p>
<h3 id="begode"> <h3 id="begode">
Gotway/Begode <img src="/images/BEGODElogo.jpg" /> Gotway/Begode <img class="logos" src="/images/BEGODElogo.jpg" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/BegodeLineup.jpg" />
<Asset src="/images/BegodeLineup.jpg" /> <img class="lefties" src="/images/BegodeMemeBurn.jpg" />
</div>
<div class="lefties">
<Asset src="/images/BegodeMemeBurn.jpg" />
</div>
<p> <p>
Gotway, oder wie sie sich heute nennen, Begode, ist schwer zu Gotway, oder wie sie sich heute nennen Begode, ist schwer zu
beschreiben und einzuordnen. Viele Meinungen und Kontroversen. Die beschreiben und einzuordnen. Viele Meinungen und Kontroversen. Die
Firma wurde nach allen oben genannten gegründet, und wie im Kapitel{" "} Firma wurde nach allen oben genannten gegründet, und wie im Kapitel{" "}
<R href="#historie">Historie</R> zu lesen, hatten sie den Fokus <R href="#historie">Historie</R> zu lesen, hatten sie den Fokus
gleich auf Leistung gesetzt. Das Design und die Qualität waren am gleich auf Leistung gesetzt. Das Design und die Qualität waren am
Anfang und auch eigentlich bis vor kurzem grauenvoll. Aber sie waren Anfang und auch eigentlich bis vor kurzem grauenvoll. Aber sie waren
die ersten die 40 km/h, dann 50, dann 60, dann 70, dann 80 und heute die ersten die 40kmh, dann 50, dann 60, dann 70, dann 80 und heute
100 km/h erreichen können, sie sind die die{" "} 100kmh erreichen können, sie sind die die <R href="#wh">4800wh</R>{" "}
<R href="#wh">4.800 Wh</R> in ein Gerät packen, egal wies aussieht in ein Gerät packen, egal wies aussieht oder wie schwer es ist.
oder wie schwer es ist. Gotway hat aktiv die Grenzen des Sports und Gotway hat aktiv die grenzen des Sports und der Einräder nach vorne
der Einräder nach vorne gebracht. Immer wenn ein neues schnelleres gebracht. Immer wenn ein neues schnelleres Gerät raus kam hieß es,
Gerät rauskam, hieß es, ach wer fährt denn schon 40 km/h mit so ach wer fährt denn schon 40kmh mit so nem Teil. Heute ist 40kmh die
einem Teil. Heute ist 40 km/h die mittel Geschwindigkeit, und es mittel Geschwindigkeit, und es wird 70+ erwartet. Auch typisch
wird 70+ erwartet. Auch typisch Begode ist es, durch bis zu 7+ neue Begode ist es, durch bis zu 7+ neue Geräte im Jahr die eigenen
Geräte im Jahr die eigenen Geräte schnell veralten zu lassen. Geräte schnell veralten zu lassen. Kingsong und Inmotion bringen
Kingsong und Inmotion bringen meist 1 Gerät pro Jahr raus. meist 1 Gerät pro jahr raus.
</p> </p>
<p> <p>
Durch die fehlende Qualität, die fehlenden Sicherheitsmaßnahmen und Durch die fehlende Qualität, die fehlenden Sicherheitesmaßnahmen und
minimalen <R href="#BMS">BMSs</R> die Gotway verbaute kam es in der minimalen <R href="#BMS">BMSs</R> die Gotway verbaute kam es in der
Vergangenheit allzu oft zu <R href="#akkuss">Akkubränden</R>, wofür Vergangenheit all zu oft zu <R href="#akkuss">Akkubränden</R>, wofür
Begode auch in der ganzen Community bekannt ist. Dazu gibt es da die Begode auch in der ganzen Community bekannt ist. Dazu gibt es da die
fehlende Kommunikation mit der Community und fehlende Reaktion auf fehlende Kommunikation mit der Community und fehlende Reaktion auf
Fehler der Geräte. Trotzdem war Begode die erste Firma die Fehler der Geräte. Trotzdem war Begode die erste Firma die
standardmäßig <R href="#spiked-pedals">Spiked-pedals</R> verbaute, standardmäßig <R href="#spiked-pedals">Spiked-pedals</R> verbaute,
was ein Wunsch, der der Community war und welche bis heute die was ein Wunsch der der Community war und welche bis heute die besten
besten mitgelieferten Spiked-pedals sind. Alle anderen Firmen zogen mitgelieferten Spiked-pedals sind. Alle anderen Firmen zogen mit
mit schlechteren Versionen nach, was normalerweise von Begode schlechteren Versionen nach, was normalerweise von Begode erwartet
erwartet wird. Begode waren die ersten, die von 84 V auf 100 V wird. Begode waren die ersten, die von 84V auf 100V umstiegen, und
umstiegen, und neuerdings auch auf 134 V, welches ungesehene neuerdings auch auf 134V, welches ungesehene Leistung bereitstellt.
Leistung bereitstellt. Wieder ziehen die anderen Hersteller langsam Wieder ziehen die anderen Hersteller langsam nach, und haben
nach, und haben trotzdem schwächere Geräte. Die neue Generation von trotzdem schwächere Geräte. Die neue Generation von Begode hat
Begode hat besseres, fast gutes Design und in manchen Aspekten auch besseres, fast gutes Design und in manchen Aspekten auch bessere
bessere Federungen als die Konkurrenz, trotzdem brechen die (völlig Federungen als die Konkurrenz, trotzdem brechen die (völlig
freiliegenden) Batterie Befestigungen leicht ab und man muss sich freiliegenden) Batterie Befestigungen leicht ab und man muss sich
DIY-Lösungen kaufen, um weiter fahren zu können (bei fast 5.000 DIY Lösungen kaufen um weiter fahren zu können (bei fast 5000
Geräten). Geräten).
</p> </p>
@ -158,26 +136,23 @@ function Manufacturers() {
</p> </p>
<h3 id="veteran"> <h3 id="veteran">
Leaperkim/Veteran <img src="/images/veteranLogo.png" /> Leaperkim/Veteran{" "}
<img class="logos" src="/images/veteranLogo.png" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/Shermangrey.jpg" />
<Asset src="/images/Shermangrey.jpg" /> <img class="lefties" src="/images/abrahams.jpg" />
</div>
<div class="lefties">
<Asset src="/images/abrahams.jpg" />
</div>
<p> <p>
Veteran ist für viele der Liebling. Bestehend aus Ex Gotway Veteran ist für viele der Lieling. Bestehend aus Ex Gotway
Ingenieuren und Mitarbeitern, die mit den Entscheidungen von Gotway Ingenieuren und Mitarbeitern, die mit den Entscheidungen von Gotway
nicht einverstanden waren, brachte Veteran 2020 als erstes Gerät das nicht einverstanden waren, brachte Veteran 2020 als erstes Gerät das
Veteran Sherman raus. Und es schlug ein wie eine Bombe, es war ein Veteran Sherman raus. Und es Schlug ein wie eine Bombe, es war ein
voller Erfolg. Das Robuste, fast militärische Design zusammen mit voller Erfolg. Das Robuste, fast militärische Design zusammen mit
der hohen stabilen Geschwindigkeit und der großen Reichweite sorgte der hohen stabilen Geschwindigkeit und der großen Reichweite sorgte
für eine starke Beliebtheit, auch heute noch und sogar außerhalb der für eine starke Beliebtheit, auch Heute noch und sogar außerhalb der
EUC-Community. Allein dieses Gerät und der Content dazu brachte eine EUC Community. Allein dieses Gerät und der Kontent dazu brachte eine
ganze Welle an neuen Fahrern zum Sport. Schnell war Veteran in den ganze Welle an neuen Fahrern zum Sport. Schnell war Veteran in den
Köpfen als robust, zuverlässig und schnell eingespeichert. Als dann Köpfen als robust, zuverlässig und schnell eingespeichert. Als dann
das neue Modell Veteran Abrahams mit größerem Reifen angekündigt das neue Modell Veteran Abrahams mit größerem Reifen angeküdigt
wurde, war der Hype groß. Doch als es dann raus kam gab es große wurde, war der Hype groß. Doch als es dann raus kam gab es große
Enttäuschungen, das Gerät hat in jeder Hinsicht versagt und war dazu Enttäuschungen, das Gerät hat in jeder Hinsicht versagt und war dazu
sehr anfällig für <R href="#cutout">Cut-outs</R>. Danach war das sehr anfällig für <R href="#cutout">Cut-outs</R>. Danach war das
@ -189,23 +164,23 @@ function Manufacturers() {
Veteran scheint aus den Fehlern mit dem Abrahams gelernt zu haben, Veteran scheint aus den Fehlern mit dem Abrahams gelernt zu haben,
denn mit dem neusten Release des Sherman S haben sie ein weiteres denn mit dem neusten Release des Sherman S haben sie ein weiteres
vielversprechenden Gerät vorgestellt. Vollständige Metall vielversprechenden Gerät vorgestellt. Vollständige Metall
Konstruktion, Weltklasse Federung, Großer Akku und genug Leistung. Konsstruktion, weltklasse Federung, Großer Akku und genug Leistung.
</p> </p>
<h3 id="extremebull">Extreme Bull</h3> <h3 id="extremebull">Extreme Bull</h3>
<p> <p>
Bei Extreme Bull ist nicht alles ganz klar. Es scheint eine Bei Extreme Bull ist nicht alles ganz klar. Es scheint eine
Untermarke von Begode zu sein, die noch dreister andere Geräte Untermarke von Begode zu sein, die noch dreister andere Geräte
kopiert und in billiger anbietet als es Begode tut. Man sieht kaum kopiert und in billger anbietet als es Begode tut. Man sieht kaum
Geräte von Extreme Bull herumfahren, und viele Verkäufer bieten die Geräte von Extreme Bull herumfahren, und viele Verkäufer bieten die
auch gar nicht erst an. Aber seit kurzem gibt es Gerüchte über eine auch gar nicht erst an. Aber seit kurzem gibt es Gerüchte über eine
Sherman S Kopie namens Commander Pro. Sollten die Gerüchte stimmen Sherman S Kopie namens Commander Pro. Sollten die Gerüchte stimmen
und das Gerät halten, was es verspricht, könnte Extreme Bull auf dem und das Gerät halten was es verspricht, könnte Extreme Bull auf dem
Vormarsch sein. Vormarsch sein.
</p> </p>
</div> </div>
</article> </article>
</Wrapper> </Body>
); );
} }

File diff suppressed because it is too large Load diff

View file

@ -1,47 +1,44 @@
import { Title } from "@solidjs/meta"; import { Body, Link, Title } from "solid-start";
import AssetHandler from "~/components/Asset"; import { lightMode } from "~/components/en/Navbar";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/devices.scss";
function KSS22() { function KSS22() {
const { FullscreenView, Asset } = AssetHandler();
return ( return (
<Wrapper class="devices" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>KS S22</Title> <Title>KS S22</Title>
<FullscreenView /> <Link rel="stylesheet" href="/styles/devices.css" />
<Navbar /> {/* <Navbar /> */}
<article> <div class="row">
<div> <div class="col-4">
<h2>Kingsong S22</h2> <img src="/images/KSS22/S22shutterkode2.jpg" />
<div class="righties">
<Asset src="/images/KSS22/S22shutterkode2.jpg" />
</div> </div>
<div class="col-8">
<article>
<h2>Kingsong S22</h2>
<p> <p>
The Kingsong S22, formerly S20, is a clearly off-road and The Kingsong S22, formerly S20, is a clearly off-road and trail
trail-oriented unicycle. Among other things, it has 130 mm oriented unicycle. Among other things, it has 130mm suspension
suspension travel and a robust metal construction, which makes it travel and a robust metal construction, which makes it ideal for
ideal for big jumps and high drops. big jumps and high drops.
</p> </p>
<p> <p>
It is the successor to the smaller S18, but with double the battery It is the successor to the smaller S18, but with double the
and 50 % more motor power, such as a top speed of 70 instead of 50 battery and 50% more motor power, such as a top speed of 70
km/h. The freespin is up to 114 km/h, so ideal for longer jumps instead of 50 km/h. The freespin is up to 114 km/h, so ideal for
where the tire is spinning up in the air. longer jumps where the tire is spinning up in the air.
</p> </p>
<p> <p>
It also comes with a seat, pretty good jump- and power pads and It also comes with a seat, pretty good jump- and power pads and
spiked pedals. Plus, a sturdy, albeit oddly placed and somewhat spiked pedals. Plus a sturdy, albeit oddly placed and somewhat
short trolley handle, as well as a sturdy kickstand and short trolley handle, as well as a sturdy kickstand and
height-adjustable bright lights. It's waterproof, but not height-adjustable bright lights. It's waterproof, but not
submersible, and best of all, it's super easy to work with because submersible, and best of all, it's super easy to work with because
the device has a very modular design. The tire can theoretically be the device has a very modular design. The tire can theoretically
removed with just 2 screws be removed with just 2 screws
</p> </p>
<p> <p>
@ -50,26 +47,28 @@ function KSS22() {
problems with the first devices, which led to cut-offs and burned problems with the first devices, which led to cut-offs and burned
the motherboard. Also, the slider design is very clumsy and gets the motherboard. Also, the slider design is very clumsy and gets
harder and harder to move over time. Many S22 buyers had to wait a harder and harder to move over time. Many S22 buyers had to wait a
long time for replacement motors, such as upgrading the sliders for long time for replacement motors, such as upgrading the sliders
100 to 200 . However, with the upgrades, it is currently the best for 100 to 200. However, with the upgrades, it is currently the
suspension unicycle on the market. (Until the Veteran Sherman S goes best suspension unicycle on the market. (Until the Veteran Sherman
on sale.) S goes on sale.)
</p> </p>
</article>
</div>
</div> </div>
<div class="grid"> <div class="row">
<Asset src="/images/KSS22/S22shutterkode5.jpg" /> <div class="col-4">
<Asset class="span-2" src="/images/KSS22/BusJump.jpg" /> <img src="/images/KSS22/S22shutterkode5.jpg" />
<Asset src="/images/KSS22/S22shutterkode4.jpg" /> </div>
<div class="col-4">
<img src="/images/KSS22/BusJump.jpg" />
</div>
<div class="col-4">
<img src="/images/KSS22/S22shutterkode4.jpg" />
</div>
</div> </div>
<table> <table>
<thead>
<tr>
<th>Attribute</th>
<th>Value</th>
</tr>
</thead>
<tbody> <tbody>
<tr> <tr>
<td>Size</td> <td>Size</td>
@ -81,15 +80,15 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Pedal Height</td> <td>Pedal Height</td>
<td>231 &plusmn; 26 mm</td> <td>231+-26mm</td>
</tr> </tr>
<tr> <tr>
<td>Weight</td> <td>Weight</td>
<td>35 kg</td> <td>35kg</td>
</tr> </tr>
<tr> <tr>
<td>Suspension travel</td> <td>Suspension travel</td>
<td>130 mm</td> <td>130mm</td>
</tr> </tr>
<tr> <tr>
<td>Suspension Type</td> <td>Suspension Type</td>
@ -101,19 +100,19 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Free Spin</td> <td>Free Spin</td>
<td>114 km/h</td> <td>114kmh</td>
</tr> </tr>
<tr> <tr>
<td>Top speed</td> <td>Top speed</td>
<td>70 km/h</td> <td>70kmh</td>
</tr> </tr>
<tr> <tr>
<td>Range at 30 km/h</td> <td>Range at 30kmh</td>
<td>200 km</td> <td>200km</td>
</tr> </tr>
<tr> <tr>
<td>Minimum range for heavy use</td> <td>Minimum range for heavy use</td>
<td>70 km</td> <td>70km</td>
</tr> </tr>
<tr> <tr>
<td>Max climb angle</td> <td>Max climb angle</td>
@ -121,7 +120,7 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Max. payload</td> <td>Max. payload</td>
<td>120 kg</td> <td>120kg</td>
</tr> </tr>
<tr> <tr>
<td>Engine Type</td> <td>Engine Type</td>
@ -129,23 +128,23 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Engine Power</td> <td>Engine Power</td>
<td>3,300 W</td> <td>3300W</td>
</tr> </tr>
<tr> <tr>
<td>Peak Power</td> <td>Peak Power</td>
<td>7,500 W</td> <td>7500W</td>
</tr> </tr>
<tr> <tr>
<td>Battery Size</td> <td>Battery Size</td>
<td>2,220 Wh</td> <td>2220wh</td>
</tr> </tr>
<tr> <tr>
<td>Voltage</td> <td>Voltage</td>
<td>126 V</td> <td>126V</td>
</tr> </tr>
<tr> <tr>
<td>Max amps</td> <td>Max amps</td>
<td>100 A</td> <td>100A</td>
</tr> </tr>
<tr> <tr>
<td>BMS</td> <td>BMS</td>
@ -156,7 +155,7 @@ function KSS22() {
<td>LG 18600</td> <td>LG 18600</td>
</tr> </tr>
<tr> <tr>
<td>IP-Rating</td> <td>IPRating</td>
<td>nope</td> <td>nope</td>
</tr> </tr>
<tr> <tr>
@ -165,11 +164,11 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Lights</td> <td>Lights</td>
<td>8 x 5 W adjustable headlights</td> <td>8x5W adjustable headlights</td>
</tr> </tr>
<tr> <tr>
<td>Default tires</td> <td>Default tires</td>
<td>Knobby</td> <td>Nobby</td>
</tr> </tr>
<tr> <tr>
<td>Anti spin button?</td> <td>Anti spin button?</td>
@ -197,15 +196,15 @@ function KSS22() {
</tr> </tr>
<tr> <tr>
<td>Default load time:</td> <td>Default load time:</td>
<td>3.3 h</td> <td>3.3h</td>
</tr> </tr>
<tr> <tr>
<td>Max Amps:</td> <td>Max Amps:</td>
<td>10 A</td> <td>10A</td>
</tr> </tr>
<tr> <tr>
<td>Fastest load time:</td> <td>Fastest load time:</td>
<td>100 minutes</td> <td>100min</td>
</tr> </tr>
<tr> <tr>
<td>Load ports:</td> <td>Load ports:</td>
@ -213,8 +212,7 @@ function KSS22() {
</tr> </tr>
</tbody> </tbody>
</table> </table>
</article> </Body>
</Wrapper>
); );
} }

View file

@ -1,18 +1,14 @@
import { faYoutube } from "@fortawesome/free-brands-svg-icons"; import { faYoutube } from "@fortawesome/free-brands-svg-icons";
import { faBookOpen, faGlobe } from "@fortawesome/pro-regular-svg-icons"; import { faBookOpen, faGlobe } from "@fortawesome/free-solid-svg-icons";
import { Title } from "@solidjs/meta"; import { A, Body, Link, Title } from "solid-start";
import AssetHandler from "~/components/Asset";
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"; import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
import Wrapper from "~/components/Wrapper";
import { lightMode } from "~/components/en/Navbar"; import { lightMode } from "~/components/en/Navbar";
import "~/styles/start.scss";
function Introduction() { function Introduction() {
const { FullscreenView, Asset } = AssetHandler();
return ( return (
<Wrapper class="start" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>Introduction</Title> <Title>Introduction</Title>
<FullscreenView /> <Link rel="stylesheet" href="/styles/start.css" />
<div class="container"> <div class="container">
<img id="cover" src="/images/Gear3.webp" /> <img id="cover" src="/images/Gear3.webp" />
@ -28,54 +24,68 @@ function Introduction() {
unicycles: unicycles:
</p> </p>
<Asset src="/images/ShermanStanding.jpg" /> <div class="righties">
<img src="/images/ShermanStanding.jpg" />
</div>
<p> <p>
From 0 auf 50 km/h in 3 s, 100 km/h top speed and 230 km range make From 0 auf 50kmh in 3s, 100kmh top speed and 230km range make these
these devices the ultimate sport. devices the ultimate sport.
</p> </p>
<Asset src="/images/UltimativeSport.jpg" /> <div class="righties">
<img src="/images/UltimativeSport.jpg" />
</div>
<p>Meanwhile climbing 50° steep walls and taking MTB trails with ease.</p> <p>Meanwhile climbing 50° steep walls and taking MTB trails with ease.</p>
<Asset src="/videos/MTBtrailsEase.mp4" /> <div class="righties">
<video width="auto" height="auto" autoplay muted loop>
<source src="/videos/MTBtrailsEase.mp4" type="video/mp4" />
</video>
</div>
<p>Taking every path and never get stuck in traffic again.</p> <p>Taking every path and never get stuck in traffic again.</p>
<Asset src="/videos/traffic.mp4" /> <div class="righties">
<video width="auto" height="auto" autoplay muted loop>
<source src="/videos/traffic.mp4" type="video/mp4" />
</video>
</div>
<p>But still being easy to carry and store just under your desk.</p> <p>But still being easy to carry and store just under your desk.</p>
<Asset src="/images/KidsKS16X.jpg" /> <div class="righties">
<img src="/images/KidsKS16X.jpg" />
</div>
<p>Interested? Then take a deep dive into PEV's and EUC's:</p> <p>Interested? Then take a deep dive into PEV's and EUC's:</p>
<a href="/en/overview"> <A href="/en/overview">
<div id="MoreButton"> <div id="MoreButton">
<p> <p>
I want to read everything about it!{" "} I want to read everything about it!{" "}
<FontAwesomeIcon icon={faBookOpen} /> <FontAwesomeIcon icon={faBookOpen} />
</p> </p>
</div> </div>
</a> </A>
<a href="https://youtube.com/playlist?list=PLfoxTRt1qLuAg-Al9JNHrl_7KVl-uSxwV"> <A href="https:/youtube.com/playlist?list=PLfoxTRt1qLuAg-Al9JNHrl_7KVl-uSxwV">
<div id="MoreButton"> <div id="MoreButton">
<p> <p>
Na, videos are just fine <FontAwesomeIcon icon={faYoutube} /> Na, videos are just fine <FontAwesomeIcon icon={faYoutube} />
</p> </p>
</div> </div>
</a> </A>
<a href="/de"> <A href="/de/">
<div id="MoreButton"> <div id="MoreButton">
<p> <p>
Wechsel zu Deutsch <FontAwesomeIcon icon={faGlobe} /> Wechsel zu Deutsch <FontAwesomeIcon icon={faGlobe} />
</p> </p>
</div> </div>
</a> </A>
</Wrapper> </Body>
); );
} }

View file

@ -1,24 +1,18 @@
import { Title } from "@solidjs/meta"; import { Body, Link, Title } from "solid-start";
import AssetHandler from "~/components/Asset";
import R from "~/components/Reference"; import R from "~/components/Reference";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar"; import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/overview.scss";
function Manufacturers() { function Manufacturers() {
const { FullscreenView, Asset } = AssetHandler();
return ( return (
<Wrapper class="overview" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>Manufacturers</Title> <Title>Manufacturers</Title>
<FullscreenView /> <Link rel="stylesheet" href="/styles/overview.css" /> <Navbar />
<Navbar />
<article> <article>
{/* {/*
<!--hersteller--> <!--hersteller-->
*/} */}
<div> <div class="row">
<h3 id="manufacturers">History and explanation of manufacturers</h3> <h3 id="manufacturers">History and explonation of manufacturers</h3>
<p> <p>
There are/were many manufacturers of electric unicycles, only the There are/were many manufacturers of electric unicycles, only the
larger and more important ones are described here. In addition to larger and more important ones are described here. In addition to
@ -29,14 +23,10 @@ function Manufacturers() {
</p> </p>
<h3 id="ninebot"> <h3 id="ninebot">
Ninebot <img src="/images/ninebotLogo.jpg" /> Ninebot <img class="logos" src="/images/ninebotLogo.jpg" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/NineBot.webp" />
<Asset src="/images/NineBot.webp" /> <img class="lefties" src="/images/NinebotZ10goood.webp" />
</div>
<div class="lefties">
<Asset src="/images/NinebotZ10goood.webp" />
</div>
<p> <p>
Ninebot is known to most as a sooter manufacturer, some may also Ninebot is known to most as a sooter manufacturer, some may also
know their electric shoes or Segway-like devices with short know their electric shoes or Segway-like devices with short
@ -50,14 +40,10 @@ function Manufacturers() {
</p> </p>
<h3 id="inmotion"> <h3 id="inmotion">
Inmotion <img src="/images/inmotionLogo.png" /> Inmotion <img class="logos" src="/images/inmotionLogo.png" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/InmotionLineup.jpg" />
<Asset src="/images/InmotionLineup.jpg" /> <img class="lefties" src="/images/V11 3.webp" />
</div>
<div class="lefties">
<Asset src="/images/V11 3.webp" />
</div>
<p> <p>
Inmotion is the second largest manufacturer of those listed here. Inmotion is the second largest manufacturer of those listed here.
Also big in the standard scooter segment, Inmotion also has a large Also big in the standard scooter segment, Inmotion also has a large
@ -67,22 +53,18 @@ function Manufacturers() {
professional looking first Suspension EUC V11. Inmotion generally professional looking first Suspension EUC V11. Inmotion generally
stands for quality, design and safety thanks to good{" "} stands for quality, design and safety thanks to good{" "}
<R href="#tiltback">Tiltback</R> and high safety margin. But all <R href="#tiltback">Tiltback</R> and high safety margin. But all
this is in exchange for performance. Until recently, inmotion was this in exchange for performance. Until recently, inmotion was
synonymous with weak and little range. That changed when the V12 synonymous with weak and little range. That changed when the V12
came out and soon the V13 will come out. Now we are hoping for a came out and soon the V13 will come out. Now we are hoping for a
safe and well-designed 90+ km/h with a high safety margin and should safe and well-designed 90+kmh with a high safety margin, and should
the V13 perform as hoped it will change the company's image. the V13 perform as hoped it will change the company's image.
</p> </p>
<h3 id="kingsong"> <h3 id="kingsong">
Kingsong <img src="/images/kingsongLogo.png" /> Kingsong <img class="logos" src="/images/kingsongLogo.png" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/KidsKS16X.jpg" />
<Asset src="/images/KidsKS16X.jpg" /> <img class="lefties" src="/images/kingsong2.jpg" />
</div>
<div class="lefties">
<Asset src="/images/kingsong2.jpg" />
</div>
<p> <p>
Kingsong is very similar to Inmotion, only smaller and without the Kingsong is very similar to Inmotion, only smaller and without the
big scooter and e-bike market behind it. Quality and design were the big scooter and e-bike market behind it. Quality and design were the
@ -99,14 +81,10 @@ function Manufacturers() {
</p> </p>
<h3 id="begode"> <h3 id="begode">
Gotway/Begode <img src="/images/BEGODElogo.jpg" /> Gotway/Begode <img class="logos" src="/images/BEGODElogo.jpg" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/BegodeLineup.jpg" />
<Asset src="/images/BegodeLineup.jpg" /> <img class="lefties" src="/images/BegodeMemeBurn.jpg" />
</div>
<div class="lefties">
<Asset src="/images/BegodeMemeBurn.jpg" />
</div>
<p> <p>
Gotway, or Begode as they call themselves today, is difficult to Gotway, or Begode as they call themselves today, is difficult to
describe and classify. Many opinions and controversies. The company describe and classify. Many opinions and controversies. The company
@ -114,15 +92,15 @@ function Manufacturers() {
<R href="#historie">History</R> chapter, they had the focus on <R href="#historie">History</R> chapter, they had the focus on
performance right away. The design and the quality were terrible in performance right away. The design and the quality were terrible in
the beginning and actually until recently. But they were the first the beginning and actually until recently. But they were the first
to be able to hit 40 km/h, then 50, then 60, then 70, then 80 and to be able to hit 40kmh, then 50, then 60, then 70, then 80 and now
now 100 km/h, they're the ones who pack <R href="#wh">4,800 Wh</R>{" "} 100kmh, they're the ones who pack <R href="#wh">4800wh</R> into one
into one device, no matter what it looks like or how heavy it is. device, no matter what it looks like or how heavy it is. Gotway has
Gotway has actively pushed the boundaries of the sport and actively pushed the boundaries of the sport and unicycles. Whenever
unicycles. Whenever a new, faster device came out, it was said, oh a new, faster device came out, it was said, oh who rides 40kmh on a
who rides 40 km/h on a unicycle anyway. Today 40 km/h is the medium unicycle anyway. Today 40kmh is the medium speed and 70+ is
speed and 70+ is expected. It is also typical of Begode to let their expected. It is also typical of Begode to let their own devices
own devices quickly become obsolete with up to 7+ new devices a quickly become obsolete with up to 7+ new devices a year. Kingsong
year. Kingsong and Inmotion usually release 1 device per year. and Inmotion usually release 1 device per year.
</p> </p>
<p> <p>
@ -133,17 +111,17 @@ function Manufacturers() {
is also a lack of communication with the community and a lack of is also a lack of communication with the community and a lack of
reaction to productions defects. Nevertheless, Begode was the first reaction to productions defects. Nevertheless, Begode was the first
company to use <R href="#spiked-pedals">spiked pedals</R> as company to use <R href="#spiked-pedals">spiked pedals</R> as
standard, which was a request from the community, and which are the standard, which was a request from the community and which are the
best included default <R href="#spiked-pedals">spiked pedals</R> to best included default <R href="#spiked-pedals">spiked pedals</R> to
date. All other companies followed suit with worse versions, which date. All other companies followed suit with worse versions, which
is what is normally expected of Begode. Begode were the first to is what is normally expected of Begode. Begode were the first to
move from 84 V to 100 V, and more recently to 134 V, which provides move from 84V to 100V, and more recently to 134V, which provides
unprecedented power. Again, the other manufacturers are slowly unprecedented power. Again, the other manufacturers are slowly
catching up and still have weaker devices. The new generation of catching up and still have weaker devices. The new generation of
Begode has better, almost good design and in some aspects also Begode has better, almost good design and in some aspects also
better suspension than the competition, nevertheless the (completely better suspension than the competition, nevertheless the (completely
exposed) battery mounts break off easily and you have to buy DIY exposed) battery mounts break off easily and you have to buy DIY
solutions to continue riding (for an almost 5,000 Device). solutions to continue riding (for an almost 5000 Device).
</p> </p>
<p> <p>
@ -152,14 +130,11 @@ function Manufacturers() {
</p> </p>
<h3 id="veteran"> <h3 id="veteran">
Leaperkim/Veteran <img src="/images/veteranLogo.png" /> Leaperkim/Veteran{" "}
<img class="logos" src="/images/veteranLogo.png" />
</h3> </h3>
<div class="righties"> <img class="righties" src="/images/Shermangrey.jpg" />
<Asset src="/images/Shermangrey.jpg" /> <img class="lefties" src="/images/abrahams.jpg" />
</div>
<div class="lefties">
<Asset src="/images/abrahams.jpg" />
</div>
<p> <p>
Veteran is the favorite for many. Comprised of ex-Gotway engineers Veteran is the favorite for many. Comprised of ex-Gotway engineers
and employees who disagreed with Gotway's decisions, Veteran and employees who disagreed with Gotway's decisions, Veteran
@ -191,12 +166,12 @@ function Manufacturers() {
and offers them cheaper than Begode does. Extreme Bull devices are and offers them cheaper than Begode does. Extreme Bull devices are
rarely seen riding around, and many resellers don't even offer them. rarely seen riding around, and many resellers don't even offer them.
But, as of recently there are rumors about a Sherman S copy called But, as of recently there are rumors about a Sherman S copy called
Commander pro. Should the rumors be true, and should the device Commander pro. should the rumors be true, and should the device
deliver what's promised, Extreme Bull might be on the rise. deliver whats promised, Extreme Bull might be on the rise.
</p> </p>
</div> </div>
</article> </article>
</Wrapper> </Body>
); );
} }

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,11 @@
import { Title } from "@solidjs/meta";
import { useNavigate } from "@solidjs/router";
import { HttpStatusCode } from "@solidjs/start";
import { createEffect } from "solid-js"; import { createEffect } from "solid-js";
import { Title, useNavigate } from "solid-start";
export default function Home() { export default function Home() {
const navigate = useNavigate(); const navigate = useNavigate();
createEffect(() => { createEffect(() => {
const isGerman = navigator.language.startsWith("de"); const isGerman = navigator.language.startsWith("de");
navigate(isGerman ? "/de" : "/en", { replace: true }); navigate(isGerman ? "/de/" : "/en/");
}); });
return ( return <Title>Language detection...</Title>;
<>
<Title>Language detection...</Title>
<HttpStatusCode code={302} />
</>
);
} }

View file

@ -1,27 +1,16 @@
import { Title } from "@solidjs/meta"; import { Body, Link, Title, useNavigate } from "solid-start";
import { useNavigate } from "@solidjs/router";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar"; import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/overview.scss";
function soon() { function soon() {
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
<Wrapper class="overview" classList={{ "light-mode": lightMode() }}> <Body classList={{ "light-mode": lightMode() }}>
<Title>soon</Title> <Title>soon</Title>
<Link rel="stylesheet" href="/styles/overview.css" />
<Navbar /> <Navbar />
<div <p style={{ "text-align": "center" }}>This side is not available yet.</p>
style={{
"min-height": "100vh",
display: "inline-block",
}}
>
<p style={{ "text-align": "center" }}>
This side is not available yet.
</p>
<button onClick={() => navigate(-1)}>Back</button> <button onClick={() => navigate(-1)}>Back</button>
</div> </Body>
</Wrapper>
); );
} }

View file

@ -1,125 +0,0 @@
* {
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-track {
background: rgb(41, 41, 41);
}
::-webkit-scrollbar-thumb {
background: #7f5af0;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
#body.devices {
background-color: #16161a;
color: #94a1b2;
font-size: 1.4em;
// #sidenavbar {
// z-index: 1;
// margin-left: -8px;
// overflow: visible;
// background-color: #121629;
// position: fixed;
// bottom: 0;
// width: 100%;
// height: 50px;
// text-align: left;
// display: flex;
// justify-content: space-between;
// button {
// all: unset;
// margin: 5px auto;
// color: #eff0f3;
// padding-left: 10px;
// padding-right: 10px;
// text-decoration: none;
// font-size: 1.4em;
// border: none;
// &:hover {
// background: #eff0f3;
// color: #2a2a2a;
// cursor: pointer;
// }
// }
// }
.main {
height: 100%;
}
h1 {
font-size: 2.5em;
}
h2 {
font-size: 2em;
}
h3 {
font-size: 1.6em;
margin-left: 140px;
}
p {
text-align: justify;
font-size: 0.875em;
}
header {
text-align: center;
}
footer,
aside,
article {
text-align: center;
}
img {
width: 100%;
max-width: max-content;
padding: 16px;
height: auto;
display: block;
}
.grid {
display: grid;
grid-template-columns: repeat(4, auto);
.span-2 {
grid-column: span 2;
}
}
table {
width: 100%;
border-collapse: collapse;
td,
th {
border: 1px solid;
padding: 0.25rem;
}
tbody td {
text-align: left;
}
}
@media only screen and (max-width: 767px) {
// [class*="col-"] {
// width: 100%;
// }
}
}

View file

@ -1,221 +0,0 @@
body {
margin: 0;
}
#body {
.fullscreen-asset {
position: fixed;
height: 100vh;
width: 100vw;
background-color: rgba(0, 0, 0, 0.8);
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&:not(.active) {
display: none;
}
img,
video {
max-width: 80vw;
transform-origin: center;
transform: scale(var(--zoom));
&.active {
opacity: 0;
}
}
img:not(.move),
video:not(.move) {
transition: transform-origin 1s;
}
img.move,
video.move {
transform-origin: var(--x) var(--y);
}
.controlls {
position: absolute;
top: 2rem;
right: 2rem;
display: flex;
flex-direction: column;
gap: 1rem;
button {
padding: 0.5rem 0.6rem;
border-radius: 10%;
svg {
height: 2rem;
width: 2rem;
@media (max-width: 1200px) {
height: 5vw;
width: 5vw;
}
}
}
}
}
.menu {
position: fixed;
top: 2rem;
left: 2rem;
padding: 0.5rem 0.6rem;
border-radius: 10%;
svg {
height: 2rem;
width: 2rem;
}
@media (max-width: 1200px) {
position: fixed;
top: 5vw;
left: 5vw;
padding: 2vw;
svg {
height: 5vw;
width: 5vw;
}
}
}
article > div {
clear: both;
}
.righties {
margin-top: -8px;
margin-left: 24px;
width: 33%;
float: right;
clear: both;
}
.lefties {
margin-top: -8px;
margin-right: 24px;
width: 33%;
float: left;
display: none;
}
#navbar {
z-index: 1;
overflow-y: auto;
overflow-x: hidden;
background-color: #121629;
position: fixed;
top: 0;
height: 100%;
margin-left: -8px;
padding: 1rem;
.modes {
margin: 1rem 0;
button {
border-radius: 16px;
scale: 0.9;
&:hover {
scale: 1.06;
}
}
}
a {
float: none;
display: block;
color: #eff0f3;
text-align: left;
padding: 8px 8px;
text-decoration: none;
font-size: 0.9em;
&:hover {
background: #eff0f3;
color: #121629;
cursor: pointer;
}
}
}
&.light-mode {
background-color: #eff0f3;
color: #2a2a2a;
.lefties,
.righties {
> * {
box-shadow: #eff0f3 0 0 1rem 1rem;
}
}
article p a {
text-align: justify;
color: #2a2a2a;
border-bottom: 1px solid #2a2a2a;
&:hover {
color: blue;
border-bottom: 1px solid blue;
.svg-inline--fa {
color: blue;
}
}
}
.svg-inline--fa {
color: #2a2a2a;
}
b {
color: #2a2a2a;
a {
color: #2a2a2a;
}
}
h3 {
color: #2a2a2a;
}
h1 {
color: #2a2a2a;
}
h2 {
color: #2a2a2a;
}
#navbar {
background-color: #b8c1ec;
a {
color: black;
}
}
button {
background-color: #b8c1ec;
color: black;
}
.raster > a {
background-color: #eff0f3;
}
a {
color: #2a2a2a;
}
}
article {
max-width: 80vw;
margin: auto;
}
}

View file

@ -1,180 +0,0 @@
* {
scroll-margin-block-start: 60px;
scroll-margin-block-end: 60px;
box-sizing: border-box;
scroll-behavior: smooth;
max-width: 100%;
max-height: 100%;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-track {
background: rgb(41, 41, 41);
}
::-webkit-scrollbar-thumb {
background: #7f5af0;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
.overview {
background-color: #16161a;
color: #94a1b2;
text-align: center;
font-size: 1.4em;
.main {
height: 100%;
}
h1 {
font-size: 2.5em;
color: #fffffe;
}
h2 {
font-size: 2em;
color: #fffffe;
}
h3 {
font-size: 1.6em;
clear: both;
color: #fffffe;
}
p {
text-align: justify;
font-size: 0.875em;
}
header {
text-align: center;
}
footer,
aside,
article {
text-align: center;
}
> img {
width: 100%;
max-width: max-content;
height: auto;
}
button {
background-color: #121629;
color: #eff0f3;
text-align: left;
padding: 8px 8px;
text-decoration: none;
font-size: 0.9em;
}
p a {
display: inline-block;
text-align: justify;
text-decoration: none;
color: #91c4ff;
border-bottom: 1px solid navy;
&:hover {
border-bottom: 1px solid #91c4ff;
}
}
.svg-inline--fa,
b {
color: #91c4ff;
}
#vcutout {
width: 25%;
}
#vcutout:hover {
width: 30%;
}
.hidden {
/*position:absolute;
transform:translate(-50%,-50%);
height:200px;
width:200px; */
float: left;
padding: 2%;
padding-left: 0%;
display: none;
}
/*wenn hover über text, zeige bild*/
.imghover:hover + .hidden {
display: block;
}
a {
display: inline;
color: rgb(225, 223, 210);
svg.left {
margin-right: 2px;
}
svg.right {
margin-left: 6px;
}
div img,
div video {
border-radius: 10%;
max-width: 260px;
max-height: 290px;
padding-top: 8px;
bottom: 0;
}
div h3 {
margin: 0.5%;
}
}
.raster {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
> a {
border: #555;
padding: 2rem 1rem;
border-width: 2px;
border-style: solid;
border-radius: 2rem;
display: flex;
flex-direction: column;
gap: 1rem;
transition: scale 0.5s;
&:hover {
scale: 1.06;
}
h3 {
font-size: 1.5rem;
margin: 0;
}
img,
video {
height: 100%;
object-fit: cover;
border-radius: 1rem;
}
}
}
.logos {
height: 1.6em;
margin-bottom: -18px;
}
.table-half {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2rem;
}
}

View file

@ -1,119 +0,0 @@
* {
scroll-margin-block-start: 60px;
scroll-margin-block-end: 60px;
box-sizing: border-box;
scroll-behavior: smooth;
max-width: 100%;
max-height: 100%;
}
::-webkit-scrollbar {
width: 9px;
}
::-webkit-scrollbar-track {
background: rgb(41, 41, 41);
}
::-webkit-scrollbar-thumb {
background: #ff8906;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
body {
background-color: #0f0e17;
}
#body.start {
color: #a7a9be;
text-align: left;
font-size: 1.4em;
max-width: 1200px;
margin: auto;
display: flex;
align-items: center;
flex-direction: column;
> img,
> video {
max-height: 60vh;
}
.row {
clear: both;
}
p {
padding: 10px;
}
#cover {
opacity: 60%;
}
.container {
position: relative;
text-align: center;
color: white;
}
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#gone {
display: none;
color: #fffffe;
text-align: center;
}
#MoreButton {
margin: auto;
position: relative;
height: auto;
max-height: max-content;
width: auto;
max-width: max-content;
background-color: #ff8906;
border-radius: 5px;
color: #fffffe;
font-size: 1.2em;
}
a {
text-decoration: none;
&:hover {
scale: 1.06;
}
div p {
text-align: center;
padding: 20px;
}
}
.righties {
padding-bottom: 30px;
padding-top: 20px;
width: 100%;
clear: both;
}
@media (max-width: 767px) /*unter handy größe*/ {
.centered {
display: none;
}
#gone {
display: block;
}
#cover {
opacity: 100%;
}
.righties {
width: 100%;
}
}
}

View file

@ -1,17 +1,14 @@
{ {
"compilerOptions": { "compilerOptions": {
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"target": "ESNext", "target": "ESNext",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js", "jsxImportSource": "solid-js",
"allowJs": true, "jsx": "preserve",
"strict": true, "strict": true,
"noEmit": true, "baseUrl": "./",
"types": ["vinxi/client"],
"isolatedModules": true,
"paths": { "paths": {
"~/*": ["./src/*"] "~/*": ["./src/*"]
} }

10
vite.config.ts Normal file
View file

@ -0,0 +1,10 @@
import solid from "solid-start/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [solid()],
server: {
host: "0.0.0.0",
strictPort: true,
},
});