Compare commits

...
Sign in to create a new pull request.

14 commits

43 changed files with 6652 additions and 4638 deletions

8
.dockerignore Normal file
View file

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

View file

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

3
.gitignore vendored
View file

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

53
Dockerfile Normal file
View file

@ -0,0 +1,53 @@
# 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"]

3
app.config.ts Normal file
View file

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

View file

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

5932
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

40
public/sitemap.xml Normal file
View file

@ -0,0 +1,40 @@
<?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>

108
public/sitemap.xsl Normal file
View file

@ -0,0 +1,108 @@
<?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>

View file

@ -1,144 +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;
}
[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%;
}
}

View file

@ -1,407 +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;
}
[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;
}
}

View file

@ -1,109 +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;
}
[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%;
}
}

110
src/app.tsx Normal file
View file

@ -0,0 +1,110 @@
// @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>
);
}

225
src/components/Asset.tsx Normal file
View file

@ -0,0 +1,225 @@
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,21 +1,18 @@
import { Show } from "solid-js";
import { A } from "solid-start";
function DeviceTile(props: { href?: string; name: string; src: string }) {
return (
<A href={props.href ?? "/soon"}>
<div class="raster">
<h3>{props.name}</h3>
<Show when={props.src.startsWith("/images")}>
<img src={props.src} alt={props.name} />
</Show>
<Show when={props.src.startsWith("/videos")}>
<video width="auto" height="auto" autoplay muted loop>
<source src={props.src} type="video/mp4" />
</video>
</Show>
</div>
</A>
<a href={props.href ?? "/soon"}>
<h3>{props.name}</h3>
<Show when={props.src.startsWith("/images")}>
<img src={props.src} alt={props.name} />
</Show>
<Show when={props.src.startsWith("/videos")}>
<video width="auto" height="auto" autoplay muted loop>
<source src={props.src} type="video/mp4" />
</video>
</Show>
</a>
);
}

View file

@ -0,0 +1,82 @@
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

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

View file

@ -0,0 +1,15 @@
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,100 +1,157 @@
import {
faBars,
faBookOpen,
faCircleHalfStroke,
faGavel,
faGlobe,
faXmark,
} from "@fortawesome/pro-regular-svg-icons";
import { createSignal } from "solid-js";
import { A, useNavigate } from "solid-start";
import {
useIsRouting,
useLocation,
useNavigate,
useSearchParams,
} from "@solidjs/router";
import { createEffect, createSignal, onCleanup } from "solid-js";
import { FontAwesomeIcon } from "../FontAwesomeIcon";
export const [lightMode, setLightMode] = createSignal(false);
const [menu, setMenu] = createSignal(false);
function Navbar() {
const [menu, setMenu] = createSignal(false);
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 (
<>
<div id="navbar" style={{ visibility: menu() ? "visible" : "hidden" }}>
<A href="/de/">
<a href="/de">
<FontAwesomeIcon icon={faBookOpen} /> Einführung
</A>
</a>
<A href="/de/overview">
<a href="/de/overview">
<FontAwesomeIcon icon={faBookOpen} /> Start
</A>
</a>
<ol>
<li>
<A href="/de/overview#start">Was sind EUCs?</A>
<a href="/de/overview#start">Was sind EUCs?</a>
</li>
<li>
<A href="/de/overview#why">Warum EUCs?</A>
<a href="/de/overview#why">Warum EUCs?</a>
</li>
<li>
<A href="/de/overview#funktion">Funktionsweise</A>
<a href="/de/overview#funktion">Funktionsweise</a>
</li>
<li>
<A href="/de/overview#begriffe">Begriffe</A>
<a href="/de/overview#begriffe">Begriffe</a>
</li>
<li>
<A href="/de/overview#sicherheit">Sicherheit</A>
<a href="/de/overview#sicherheit">Sicherheit</a>
</li>
<li>
<A href="/de/overview#ausrüstung">Ausrüstung</A>
<a href="/de/overview#ausrüstung">Ausrüstung</a>
</li>
<li>
<A href="/de/overview#cutout">Cut-out's</A>
<a href="/de/overview#cutout">Cut-out's</a>
</li>
<li>
<A href="/de/overview#akkuss">Akkusicherheit</A>
<a href="/de/overview#akkuss">Akkusicherheit</a>
</li>
<li>
<A href="/de/overview#fahrweise">Fahrweise</A>
<a href="/de/overview#fahrweise">Fahrweise</a>
</li>
<li>
<A href="/de/overview#wobbles">Wobbles</A>
<a href="/de/overview#wobbles">Wobbles</a>
</li>
<li>
<A href="/de/overview#leistung">Leistung</A>
<a href="/de/overview#leistung">Leistung</a>
</li>
<li>
<A href="/de/overview#federung">Federung</A>
<a href="/de/overview#federung">Federung</a>
</li>
<li>
<A href="/de/overview#reifen">Reifen</A>
<a href="/de/overview#reifen">Reifen</a>
</li>
<li>
<A href="/de/overview#historie">Historie</A>
<a href="/de/overview#historie">Historie</a>
</li>
<li>
<A href="/de/overview#geräte">Geräte Liste</A>
<a href="/de/overview#geraete">Geräte Liste</a>
</li>
</ol>
<A href="/de/manufacturers">
<a href="/de/manufacturers">
<FontAwesomeIcon icon={faBookOpen} /> Hersteller
</A>
</a>
<button onClick={() => setLightMode((e) => !e)}>
{lightMode() ? "Dark Mode " : "Light Mode "}
<FontAwesomeIcon icon={faCircleHalfStroke} />
</button>
<button onClick={() => navigate("/en/overview")}>
Englisch <FontAwesomeIcon icon={faGlobe} />
</button>
<button onClick={() => setMenu(false)}>
Close <FontAwesomeIcon icon={faXmark} />
</button>
<a href="/de/imprint">
<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 "}
<FontAwesomeIcon icon={faCircleHalfStroke} />
</button>
<button
onClick={() =>
navigate("/en" + location.pathname.slice(3), { scroll: false })
}
>
Englisch <FontAwesomeIcon icon={faGlobe} />
</button>
<button onClick={() => setMenu(false)}>
Close <FontAwesomeIcon icon={faXmark} />
</button>
</div>
</div>
<div
id="sidenavbar"
style={{ visibility: menu() ? "hidden" : "visible" }}
>
<button onClick={() => navigate(-1)}>Zurück</button>
<A href="#start">Start</A>
<button onClick={() => setMenu(true)}>Menu</button>
</div>
<button class="menu" title="Menu" onClick={() => setMenu(true)}>
<FontAwesomeIcon icon={faBars} />
</button>
</>
);
}

View file

@ -1,100 +1,157 @@
import {
faBars,
faBookOpen,
faCircleHalfStroke,
faGavel,
faGlobe,
faXmark,
} from "@fortawesome/pro-regular-svg-icons";
import { createSignal } from "solid-js";
import { A, useNavigate } from "solid-start";
import {
useIsRouting,
useLocation,
useNavigate,
useSearchParams,
} from "@solidjs/router";
import { createEffect, createSignal, onCleanup } from "solid-js";
import { FontAwesomeIcon } from "../FontAwesomeIcon";
export const [lightMode, setLightMode] = createSignal(false);
const [menu, setMenu] = createSignal(false);
function Navbar() {
const [menu, setMenu] = createSignal(false);
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 (
<>
<div id="navbar" style={{ visibility: menu() ? "visible" : "hidden" }}>
<A href="/en/">
<a href="/en">
<FontAwesomeIcon icon={faBookOpen} /> Introduction
</A>
</a>
<A href="/en/overview">
<a href="/en/overview">
<FontAwesomeIcon icon={faBookOpen} /> Start
</A>
</a>
<ol>
<li>
<A href="/en/overview#start">What are EUCs?</A>
<a href="/en/overview#start">What are EUCs?</a>
</li>
<li>
<A href="/en/overview#why">Why EUCs?</A>
<a href="/en/overview#why">Why EUCs?</a>
</li>
<li>
<A href="/en/overview#funktion">Functionality</A>
<a href="/en/overview#funktion">Functionality</a>
</li>
<li>
<A href="/en/overview#begriffe">Glossarry</A>
<a href="/en/overview#begriffe">Glossarry</a>
</li>
<li>
<A href="/en/overview#sicherheit">Safety</A>
<a href="/en/overview#sicherheit">Safety</a>
</li>
<li>
<A href="/en/overview#ausrüstung">Gear</A>
<a href="/en/overview#ausrüstung">Gear</a>
</li>
<li>
<A href="/en/overview#cutout">Cut-out's</A>
<a href="/en/overview#cutout">Cut-out's</a>
</li>
<li>
<A href="/en/overview#akkuss">Battery safety</A>
<a href="/en/overview#akkuss">Battery safety</a>
</li>
<li>
<A href="/en/overview#fahrweise">Ride style</A>
<a href="/en/overview#fahrweise">Ride style</a>
</li>
<li>
<A href="/en/overview#wobbles">Wobbles</A>
<a href="/en/overview#wobbles">Wobbles</a>
</li>
<li>
<A href="/en/overview#leistung">Performance</A>
<a href="/en/overview#leistung">Performance</a>
</li>
<li>
<A href="/en/overview#federung">Suspension</A>
<a href="/en/overview#federung">Suspension</a>
</li>
<li>
<A href="/en/overview#reifen">Tires</A>
<a href="/en/overview#reifen">Tires</a>
</li>
<li>
<A href="/en/overview#historie">History</A>
<a href="/en/overview#historie">History</a>
</li>
<li>
<A href="/en/overview#geräte">Device list</A>
<a href="/en/overview#geraete">Device list</a>
</li>
</ol>
<A href="/en/manufacturers">
<a href="/en/manufacturers">
<FontAwesomeIcon icon={faBookOpen} /> Manufacturers
</A>
</a>
<button onClick={() => setLightMode((e) => !e)}>
{lightMode() ? "Dark Mode " : "Light Mode "}
<FontAwesomeIcon icon={faCircleHalfStroke} />
</button>
<button onClick={() => navigate("/de/overview")}>
Deutsch <FontAwesomeIcon icon={faGlobe} />
</button>
<button onClick={() => setMenu(false)}>
Close <FontAwesomeIcon icon={faXmark} />
</button>
<a href="/de/imprint">
<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 "}
<FontAwesomeIcon icon={faCircleHalfStroke} />
</button>
<button
onClick={() =>
navigate("/de" + location.pathname.slice(3), { scroll: false })
}
>
Deutsch <FontAwesomeIcon icon={faGlobe} />
</button>
<button onClick={() => setMenu(false)}>
Close <FontAwesomeIcon icon={faXmark} />
</button>
</div>
</div>
<div
id="sidenavbar"
style={{ visibility: menu() ? "hidden" : "visible" }}
>
<button onClick={() => navigate(-1)}>Back</button>
<A href="#start">Start</A>
<button onClick={() => setMenu(true)}>Menu</button>
</div>
<button class="menu" title="Menu" onClick={() => setMenu(true)}>
<FontAwesomeIcon icon={faBars} />
</button>
</>
);
}

View file

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

View file

@ -1,9 +1,29 @@
import {
createHandler,
renderAsync,
StartServer,
} from "solid-start/entry-server";
import { StartServer, createHandler } from "@solidjs/start/server";
import { getRequestEvent } from "solid-js/web";
export default createHandler(
renderAsync((event) => <StartServer event={event} />),
);
export default createHandler(() => (
<StartServer
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="solid-start/env" />
/// <reference types="@solidjs/start/env" />

View file

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

View file

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

55
src/routes/de/imprint.tsx Normal file
View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -1,218 +1,220 @@
import { Body, Link, Title } from "solid-start";
import { lightMode } from "~/components/en/Navbar";
import { Title } from "@solidjs/meta";
import AssetHandler from "~/components/Asset";
import Wrapper from "~/components/Wrapper";
import Navbar, { lightMode } from "~/components/en/Navbar";
import "~/styles/devices.scss";
function KSS22() {
const { FullscreenView, Asset } = AssetHandler();
return (
<Body classList={{ "light-mode": lightMode() }}>
<Wrapper class="devices" classList={{ "light-mode": lightMode() }}>
<Title>KS S22</Title>
<Link rel="stylesheet" href="/styles/devices.css" />
{/* <Navbar /> */}
<FullscreenView />
<Navbar />
<div class="row">
<div class="col-4">
<img src="/images/KSS22/S22shutterkode2.jpg" />
<article>
<div>
<h2>Kingsong S22</h2>
<div class="righties">
<Asset src="/images/KSS22/S22shutterkode2.jpg" />
</div>
<p>
The Kingsong S22, formerly S20, is a clearly off-road and
trail-oriented unicycle. Among other things, it has 130 mm
suspension travel and a robust metal construction, which makes it
ideal for big jumps and high drops.
</p>
<p>
It is the successor to the smaller S18, but with double the battery
and 50 % more motor power, such as a top speed of 70 instead of 50
km/h. The freespin is up to 114 km/h, so ideal for longer jumps
where the tire is spinning up in the air.
</p>
<p>
It also comes with a seat, pretty good jump- and power pads and
spiked pedals. Plus, a sturdy, albeit oddly placed and somewhat
short trolley handle, as well as a sturdy kickstand and
height-adjustable bright lights. It's waterproof, but not
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
removed with just 2 screws
</p>
<p>
While all of this is true, many problems have unfortunately arisen
with this highly anticipated and hyped wheel. There were motor
problems with the first devices, which led to cut-offs and burned
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
long time for replacement motors, such as upgrading the sliders for
100 to 200 . However, with the upgrades, it is currently the best
suspension unicycle on the market. (Until the Veteran Sherman S goes
on sale.)
</p>
</div>
<div class="col-8">
<article>
<h2>Kingsong S22</h2>
<p>
The Kingsong S22, formerly S20, is a clearly off-road and trail
oriented unicycle. Among other things, it has 130mm suspension
travel and a robust metal construction, which makes it ideal for
big jumps and high drops.
</p>
<p>
It is the successor to the smaller S18, but with double the
battery and 50% more motor power, such as a top speed of 70
instead of 50 km/h. The freespin is up to 114 km/h, so ideal for
longer jumps where the tire is spinning up in the air.
</p>
<p>
It also comes with a seat, pretty good jump- and power pads and
spiked pedals. Plus a sturdy, albeit oddly placed and somewhat
short trolley handle, as well as a sturdy kickstand and
height-adjustable bright lights. It's waterproof, but not
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 removed with just 2 screws
</p>
<p>
While all of this is true, many problems have unfortunately arisen
with this highly anticipated and hyped wheel. There were motor
problems with the first devices, which led to cut-offs and burned
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
long time for replacement motors, such as upgrading the sliders
for 100 to 200. However, with the upgrades, it is currently the
best suspension unicycle on the market. (Until the Veteran Sherman
S goes on sale.)
</p>
</article>
<div class="grid">
<Asset src="/images/KSS22/S22shutterkode5.jpg" />
<Asset class="span-2" src="/images/KSS22/BusJump.jpg" />
<Asset src="/images/KSS22/S22shutterkode4.jpg" />
</div>
</div>
<div class="row">
<div class="col-4">
<img src="/images/KSS22/S22shutterkode5.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>
<table>
<tbody>
<tr>
<td>Size</td>
<td>582L 330W 747H</td>
</tr>
<tr>
<td>Wheel Circumference</td>
<td>20 inches</td>
</tr>
<tr>
<td>Pedal Height</td>
<td>231+-26mm</td>
</tr>
<tr>
<td>Weight</td>
<td>35kg</td>
</tr>
<tr>
<td>Suspension travel</td>
<td>130mm</td>
</tr>
<tr>
<td>Suspension Type</td>
<td>Oil Shock</td>
</tr>
<tr>
<td>Suspension Adjustments (for suspension)</td>
<td>Rebound, compression</td>
</tr>
<tr>
<td>Free Spin</td>
<td>114kmh</td>
</tr>
<tr>
<td>Top speed</td>
<td>70kmh</td>
</tr>
<tr>
<td>Range at 30kmh</td>
<td>200km</td>
</tr>
<tr>
<td>Minimum range for heavy use</td>
<td>70km</td>
</tr>
<tr>
<td>Max climb angle</td>
<td>45°</td>
</tr>
<tr>
<td>Max. payload</td>
<td>120kg</td>
</tr>
<tr>
<td>Engine Type</td>
<td>High Speed</td>
</tr>
<tr>
<td>Engine Power</td>
<td>3300W</td>
</tr>
<tr>
<td>Peak Power</td>
<td>7500W</td>
</tr>
<tr>
<td>Battery Size</td>
<td>2220wh</td>
</tr>
<tr>
<td>Voltage</td>
<td>126V</td>
</tr>
<tr>
<td>Max amps</td>
<td>100A</td>
</tr>
<tr>
<td>BMS</td>
<td>Smart BMS</td>
</tr>
<tr>
<td>Battery cell type</td>
<td>LG 18600</td>
</tr>
<tr>
<td>IPRating</td>
<td>nope</td>
</tr>
<tr>
<td>Accessories</td>
<td>Powerpads, Jumppads, Seat, Spiked Pedals</td>
</tr>
<tr>
<td>Lights</td>
<td>8x5W adjustable headlights</td>
</tr>
<tr>
<td>Default tires</td>
<td>Nobby</td>
</tr>
<tr>
<td>Anti spin button?</td>
<td>under control</td>
</tr>
<tr>
<td>Display?</td>
<td>dot matrix</td>
</tr>
<tr>
<td>RGB?</td>
<td>Taillight</td>
</tr>
<tr>
<td>Pads?</td>
<td>All inclusive</td>
</tr>
<tr>
<td>Charge outlets?</td>
<td>nope</td>
</tr>
<tr>
<td>Charger:</td>
<td />
</tr>
<tr>
<td>Default load time:</td>
<td>3.3h</td>
</tr>
<tr>
<td>Max Amps:</td>
<td>10A</td>
</tr>
<tr>
<td>Fastest load time:</td>
<td>100min</td>
</tr>
<tr>
<td>Load ports:</td>
<td>2</td>
</tr>
</tbody>
</table>
</Body>
<table>
<thead>
<tr>
<th>Attribute</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Size</td>
<td>582L 330W 747H</td>
</tr>
<tr>
<td>Wheel Circumference</td>
<td>20 inches</td>
</tr>
<tr>
<td>Pedal Height</td>
<td>231 &plusmn; 26 mm</td>
</tr>
<tr>
<td>Weight</td>
<td>35 kg</td>
</tr>
<tr>
<td>Suspension travel</td>
<td>130 mm</td>
</tr>
<tr>
<td>Suspension Type</td>
<td>Oil Shock</td>
</tr>
<tr>
<td>Suspension Adjustments (for suspension)</td>
<td>Rebound, compression</td>
</tr>
<tr>
<td>Free Spin</td>
<td>114 km/h</td>
</tr>
<tr>
<td>Top speed</td>
<td>70 km/h</td>
</tr>
<tr>
<td>Range at 30 km/h</td>
<td>200 km</td>
</tr>
<tr>
<td>Minimum range for heavy use</td>
<td>70 km</td>
</tr>
<tr>
<td>Max climb angle</td>
<td>45°</td>
</tr>
<tr>
<td>Max. payload</td>
<td>120 kg</td>
</tr>
<tr>
<td>Engine Type</td>
<td>High Speed</td>
</tr>
<tr>
<td>Engine Power</td>
<td>3,300 W</td>
</tr>
<tr>
<td>Peak Power</td>
<td>7,500 W</td>
</tr>
<tr>
<td>Battery Size</td>
<td>2,220 Wh</td>
</tr>
<tr>
<td>Voltage</td>
<td>126 V</td>
</tr>
<tr>
<td>Max amps</td>
<td>100 A</td>
</tr>
<tr>
<td>BMS</td>
<td>Smart BMS</td>
</tr>
<tr>
<td>Battery cell type</td>
<td>LG 18600</td>
</tr>
<tr>
<td>IP-Rating</td>
<td>nope</td>
</tr>
<tr>
<td>Accessories</td>
<td>Powerpads, Jumppads, Seat, Spiked Pedals</td>
</tr>
<tr>
<td>Lights</td>
<td>8 x 5 W adjustable headlights</td>
</tr>
<tr>
<td>Default tires</td>
<td>Knobby</td>
</tr>
<tr>
<td>Anti spin button?</td>
<td>under control</td>
</tr>
<tr>
<td>Display?</td>
<td>dot matrix</td>
</tr>
<tr>
<td>RGB?</td>
<td>Taillight</td>
</tr>
<tr>
<td>Pads?</td>
<td>All inclusive</td>
</tr>
<tr>
<td>Charge outlets?</td>
<td>nope</td>
</tr>
<tr>
<td>Charger:</td>
<td />
</tr>
<tr>
<td>Default load time:</td>
<td>3.3 h</td>
</tr>
<tr>
<td>Max Amps:</td>
<td>10 A</td>
</tr>
<tr>
<td>Fastest load time:</td>
<td>100 minutes</td>
</tr>
<tr>
<td>Load ports:</td>
<td>2</td>
</tr>
</tbody>
</table>
</article>
</Wrapper>
);
}

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

125
src/styles/devices.scss Normal file
View file

@ -0,0 +1,125 @@
* {
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%;
// }
}
}

221
src/styles/global.scss Normal file
View file

@ -0,0 +1,221 @@
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;
}
}

180
src/styles/overview.scss Normal file
View file

@ -0,0 +1,180 @@
* {
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;
}
}

119
src/styles/start.scss Normal file
View file

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

View file

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