GUI base navigation & home

This commit is contained in:
venashial
2022-03-06 10:55:51 -08:00
parent f3b5155274
commit e6329819c7
26 changed files with 2087 additions and 85 deletions

View File

@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
%svelte.head%
</head>
<body>
<div>%svelte.body%</div>
<body style="background-color: hsl(220, 13%, 15%)">
%svelte.body%
</body>
</html>

View File

@@ -0,0 +1,54 @@
<script lang="ts">
export let title: string;
</script>
<div class="card-row">
<div class="card-row__title">{title}</div>
<div class="card-row__items">
<slot />
</div>
</div>
<style lang="postcss">
.card-row {
display: flex;
flex-direction: column;
padding: 1rem 0;
grid-gap: 1rem;
&__title {
padding: 0 1rem;
display: flex;
grid-gap: 1rem;
align-items: center;
&::after {
flex: 1 1;
content: " ";
background-color: hsla(0,0%,100%,0.2);
height: 0.2rem;
border-radius: var(--rounded-max);
}
}
&__items {
display: flex;
grid-gap: 1rem;
align-items: flex-start;
overflow-x: auto;
padding: 0 1rem;
/* Hide scrollbar */
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
&:nth-of-type(even) {
background-color: hsla(0,0%,0%,0.2);
}
}
</style>

View File

@@ -0,0 +1,78 @@
<script lang="ts">
import IconPlayFilled from "virtual:icons/carbon/play-filled-alt"
export let title: string;
export let id: string;
export let version: string;
export let modpack = false;
export let image: string;
</script>
<a class="instance" href="/library/instance/{id}"
style:background-image="linear-gradient(5deg, hsla(0,0%,0%,0.8) 0%, hsla(0,0%,0%,0) 100%), url('{image}')">
<div class="instance__version">{version}</div>
<div class="instance__title">{title}</div>
<button class="play-button">
<IconPlayFilled />
</button>
</a>
<style lang="postcss">
.instance {
--size: 8rem;
min-width: var(--size);
min-height: var(--size);
border-radius: var(--rounded);
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 0.5rem;
box-shadow: var(--shadow-raised) var(--shadow-inset);
position: relative;
background-size: cover;
&__title {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
&__version {
color: var(--color-text);
font-size: var(--font-size-sm);
}
&:hover .play-button {
visibility: visible;
opacity: 1;
transform: none;
}
.play-button {
position: absolute;
bottom: 0.5rem;
right: 0.5rem;
background-color: var(--color-brand);
width: 2.5rem;
aspect-ratio: 1 / 1;
border-radius: var(--rounded-max);
display: flex;
align-items: center;
justify-content: center;
visibility: hidden;
opacity: 0;
transition-property: opacity, visibility, transform;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
transform: translateY(1rem);
:global(svg) {
width: 1.25rem;
height: auto;
color: black;
}
}
}
</style>

View File

@@ -0,0 +1,36 @@
<script lang="ts">
import { SvelteComponent } from 'svelte'
import { page } from "$app/stores";
export let items: {
label: string,
/** Page href, without slash prefix */
href: string,
icon: SvelteComponent
}[];
/** Path level in URL, zero-indexed */
export let level = 0;
let path: string[];
$: path = $page.url.pathname
.substring(1)
.split('/')
</script>
<div class="vertical-nav">
{#each items as item (item.href)}
<a class="nav-item" href="/{item.href}" class:active={path[level] === item.href}>
<svelte:component this={item.icon} />
{item.label}
</a>
{/each}
</div>
<style lang="postcss">
.vertical-nav {
display: flex;
flex-direction: column;
grid-gap: 0.25rem;
}
</style>

View File

@@ -0,0 +1,51 @@
<script lang="ts">
import { Svrollbar } from 'svrollbar'
let viewport: Element
let contents: Element
</script>
<div class="page">
<div bind:this={viewport} class="viewport">
<div bind:this={contents} class="contents">
<slot />
</div>
</div>
<Svrollbar {viewport} {contents} />
</div>
<style>
.page {
position: relative;
width: 100%;
overflow: hidden;
--svrollbar-track-width: 20px;
--svrollbar-track-opacity: 0;
--svrollbar-thumb-width: 8px;
--svrollbar-thumb-background: hsla(216,5%,60%);
--svrollbar-thumb-opacity: 0.9;
}
.viewport {
position: relative;
width: 100%;
height: calc(100vh - 2.5rem);
overflow-y: scroll;
overflow-x: hidden;
/* hide scrollbar */
-ms-overflow-style: none;
scrollbar-width: none;
}
.viewport::-webkit-scrollbar {
/* hide scrollbar */
display: none;
}
:global(.v-thumb) {
margin: 4px auto 4px auto !important;
}
</style>

View File

@@ -0,0 +1,77 @@
<script lang="ts">
import VerticalNav from '../components/VerticalNav.svelte'
import IconHome from 'virtual:icons/lucide/home'
import IconSearch from 'virtual:icons/heroicons-outline/search'
import IconLibrary from 'virtual:icons/lucide/library';
import IconSettings from 'virtual:icons/lucide/settings'
import { page } from "$app/stores";
</script>
<div class="sidebar">
<div class="account">
<div class="account__heads">
<img src="https://mc-heads.net/avatar/venashial" alt="Minecraft head"/>
</div>
<a class="account__info" href="/settings/accounts">
<div>venashial</div>
<div class="account__info__manage">Manage accounts</div>
</a>
</div>
<VerticalNav items={[
{
label: 'Home',
href: '',
icon: IconHome,
},
{
label: 'Search',
href: 'search',
icon: IconSearch,
},
{
label: 'Library',
href: 'library',
icon: IconLibrary,
}
]}/>
<a class="nav-item" href="/settings" class:active={$page.url.pathname.startsWith('/settings')}>
<IconSettings />
Settings
</a>
</div>
<style lang="postcss">
.sidebar {
display: flex;
flex-direction: column;
padding: 1rem;
grid-gap: 2rem;
height: 100%;
background-color: var(--sidebar-bg);
.account {
display: flex;
grid-gap: 0.75rem;
&__heads {
img {
width: 2.5rem;
border-radius: var(--rounded-sm);
}
}
&__info {
&__manage {
color: var(--color-text-light)
}
}
}
*:last-child {
margin-top: auto;
}
}
</style>

View File

@@ -0,0 +1,70 @@
<script lang="ts">
import IconChevronLeft from 'virtual:icons/lucide/chevron-left';
import IconChevronRight from 'virtual:icons/lucide/chevron-right';
import IconCaretRight from 'virtual:icons/carbon/caret-right';
import { page } from '$app/stores'
let path: string[];
$: path = $page.url.pathname
.substring(1)
.split('/')
</script>
<div class="status-bar">
<div class="page-nav">
<button title="Back" on:click={() => window.history.back()}>
<IconChevronLeft />
</button>
<button title="Forward" on:click={() => window.history.forward()}>
<IconChevronRight />
</button>
</div>
<div class="breadcrumbs">
{#each path as crumb, index}
{#if index !== 0}
<div class="breadcrumbs__separator"><IconCaretRight /></div>
{/if}
<a class="breadcrumbs__crumb" href={crumb}>{crumb || 'home'}</a>
{/each}
</div>
<div class="statuses">
<div>Updating 12 mods...</div>
<div>236 mods installed</div>
</div>
</div>
<style lang="postcss">
.status-bar {
display: flex;
padding: 0.75rem;
grid-gap: 0.75rem;
background-color: var(--status-bg);
width: 100%;
height: 100%;
align-items: center;
box-shadow: var(--shadow-raised);
}
.breadcrumbs {
display: flex;
grid-gap: 0.25rem;
text-transform: capitalize;
&__crumb:hover {
text-decoration: underline;
}
&__separator {
color: var(--color-text-lightest)
}
}
.statuses {
margin-left: auto;
display: flex;
grid-gap: 1rem;
color: var(--color-text-lightest);
}
</style>

13
theseus_gui/src/global.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
/// <reference types="@sveltejs/kit" />
/// <reference types="unplugin-icons/types/svelte" />
declare module '$assets/images/*' {
export { SvelteComponentDev as default } from 'svelte/internal';
}
declare module '$locales/*';
declare module '*.svg' {
import { SvelteComponent } from 'svelte';
const content: SvelteComponent;
export default content;
}

6
theseus_gui/src/hooks.ts Normal file
View File

@@ -0,0 +1,6 @@
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
return await resolve(event, {
ssr: false,
});
}

View File

@@ -1,11 +1,45 @@
<script lang="ts">
import '@fontsource/inter'
import Sidebar from '$lib/../components/layout/Sidebar.svelte'
import StatusBar from "../components/layout/StatusBar.svelte";
import Page from "../components/layout/Page.svelte";
</script>
<main>
<slot />
</main>
<svelte:head>
<style lang="postcss">
@import "../styles/global.postcss";
</style>
</svelte:head>
<style>
<div class="app">
<Sidebar />
<StatusBar />
<Page>
<slot/>
</Page>
</div>
<style lang="postcss">
.app {
height: 100%;
width: 100%;
display: grid;
grid-template-areas:
"sidebar status-bar"
"sidebar page";
grid-template-rows: 2.5rem 1fr;
grid-template-columns: 14rem 1fr;
}
:global(.page) {
grid-area: page;
}
:global(.sidebar) {
grid-area: sidebar;
}
:global(.status-bar) {
grid-area: status-bar;
}
</style>

View File

@@ -1,9 +1,27 @@
<script lang="ts">
import Instance from "../components/components/Instance.svelte";
import CardRow from "../components/components/CardRow.svelte";
</script>
<h1>Modrinth</h1>
<CardRow title="Jump back in">
{#each Array(5) as _, i}
<Instance title="New Caves" id="234" version="1.18" image="https://i.ibb.co/8KDxBwq/patchnotes-cavesandcliffs.jpg" />
{/each}
</CardRow>
<style>
<CardRow title="Popular packs">
{#each Array(5) as _, i}
<Instance title="All of Fabric 5" id="567" version="1.18.1" image="https://media.forgecdn.net/avatars/458/829/637733746768258525.png" modpack />
{/each}
</CardRow>
<CardRow title="Most played">
{#each Array(5) as _, i}
<Instance title="New Caves" id="234" version="1.18.2" image="https://i.ibb.co/8KDxBwq/patchnotes-cavesandcliffs.jpg" />
{/each}
</CardRow>
<style lang="postcss">
</style>

View File

@@ -0,0 +1,13 @@
<script context="module" lang="ts">
</script>
<script lang="ts">
</script>
<style lang="postcss">
</style>

View File

@@ -0,0 +1,19 @@
.nav-item {
display: flex;
align-items: center;
grid-gap: 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: var(--rounded-sm);
box-shadow: var(--shadow-inset-sm) var(--shadow-raised);
transition: background-color 0.2s ease-in-out,
color 0.1s ease-in-out;
color: var(--color-text-light);
&:hover, &.active {
color: var(--color-text);
}
&.active {
background-color: var(--nav-active-bg);
}
}

View File

@@ -0,0 +1,110 @@
@import 'normalize.postcss';
@import 'components.postcss';
.theme {
--color-brand-light: hsl(155, 54%, 30%);
--color-brand-dark: hsl(155, 58%, 25%);
--color-brand-contrast: hsl(0, 0%, 100%);
--shadow-inset-lg: inset 0px -2px 2px hsla(221, 39%, 11%, 0.1);
--shadow-inset: inset 0px -2px 2px hsla(221, 39%, 11%, 0.05);
--shadow-inset-sm: inset 0px -1px 1px hsla(221, 39%, 11%, 0.25);
--shadow-raised-lg: 0px 2px 4px hsla(221, 39%, 11%, 0.2);
--shadow-raised: 0px -2px 4px hsla(221, 39%, 11%, 0.1);
--shadow-floating: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px,
rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
--shadow-bar: rgba(0,0,0,.3) 0 0 20px 2px;
--color-text: hsl(221, 10%, 95%);
--color-text-light: hsl(215, 14%, 74%);
--color-text-lightest: hsl(220, 9%, 70%);
--color-heading: hsl(222, 16%, 80%);
--color-link: hsl(215, 100%, 75%);
--color-raised-bg: hsl(220, 13%, 25%);
--color-raised-bg-hover: hsl(220, 13%, 20%);
--color-divider: hsl(220, 13%, 50%);
--color-button-bg: hsl(220, 13%, 35%);
--color-button-bg-hover: hsl(220, 13%, 32%);
--color-badge-gray-text: hsl(0, 2%, 69%);
--color-badge-gray-dot: hsl(0, 6%, 77%);
--color-badge-red-text: hsl(343, 63%, 67%);
--color-badge-red-dot: hsl(342, 70%, 53%);
--color-badge-green-text: hsl(156, 53%, 50%);
--color-badge-green-dot: hsl(140, 64%, 40%);
--color-badge-yellow-text: hsl(40, 57%, 60%);
--color-badge-yellow-dot: hsl(40, 92%, 62%);
--color-table-border: hsl(214, 12%, 35%);
--color-table-alternate-row: hsl(216, 12%, 17%);
--color-code-bg: hsl(217, 12%, 29%);
--color-danger-bg: hsl(355deg, 70%, 20%);
--color-danger-text: hsl(342deg, 70%, 75%);
--color-input-light: hsl(220, 13%, 20%);
--color-scrollbar: hsl(220, 13%, 40%);
/* Launcher added */
--status-bg: hsl(216, 5%, 29%);
--sidebar-bg: hsl(216, 10%, 3%);
--nav-active-bg: hsla(0,0%,100%,0.1);
--font-size-sm: 0.75rem;
--color-bg: hsl(217, 9%, 18%);
--color-brand: hsl(145, 78%, 48%);
}
html, body {
overflow: hidden;
padding: 0;
margin: 0;
}
body {
@extend .theme;
--rounded: 1rem;
--rounded-top: 1rem 1rem 0 0;
--rounded-bottom: 0 0 1rem 1rem;
--rounded-sm: 0.6rem;
--rounded-max: 999999999px;
--font-standard: Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto,
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
--font-size-nm: 0.875rem; /* 16px */
--font-size-xl: 1.5rem; /* 24px */
--font-weight-regular: 400;
--font-weight-medium: 600;
--font-weight-bold: 700;
display: flex;
background-color: var(--color-bg) !important; /* overrides style set on first load */
color: var(--color-text);
font-family: var(--font-standard);
font-size: var(--font-size-nm);
font-weight: var(--font-weight-regular);
min-height: 100vh;
max-height: 100vh;
scrollbar-color: var(--color-scrollbar) var(--color-bg);
*::-webkit-scrollbar {
width: 14px;
}
*::-webkit-scrollbar-track {
background-color: var(--color-bg);
}
*::-webkit-scrollbar-thumb {
background-color: var(--color-scrollbar);
border-radius: 999px;
border: 3px solid var(--color-bg);
}
}

View File

@@ -0,0 +1,55 @@
@import 'sanitize.css';
@import 'sanitize.css/forms.css';
@import 'sanitize.css/typography.css';
/* Overrides */
button {
margin: 0;
padding: 0;
font-size: inherit;
box-shadow: none;
border: none;
cursor: pointer;
}
a {
color: inherit;
text-decoration: none;
}
*:focus {
outline: none;
}
button:focus-visible,
a:focus-visible,
[tabindex='0']:focus-visible {
outline: 0.2rem solid var(--color-brand);
}
html,
body,
#svelte {
height: 100%;
}
html {
overflow-y: hidden;
overflow-x: hidden;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
line-height: 100%;
margin: 0;
}
ul {
padding: 0 0 0 1.5rem;
}