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

2
.gitignore vendored
View File

@ -2,4 +2,4 @@
node_modules/
.svelte-kit/
theseus_gui/build/
WixTools
WixTools

View File

@ -0,0 +1,17 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="CssUnknownProperty" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myCustomPropertiesEnabled" value="true" />
<option name="myIgnoreVendorSpecificProperties" value="false" />
<option name="myCustomPropertiesList">
<value>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="scrollbar-width" />
<item index="1" class="java.lang.String" itemvalue="scrollbar-color" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>

View File

@ -4,4 +4,4 @@ members = [
"theseus",
"theseus_cli",
"theseus_gui/src-tauri"
]
]

View File

@ -1,5 +1,4 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100

View File

@ -1,40 +1,16 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm init svelte@next
# create a new project in my-app
npm init svelte@next my-app
```
> Note: the `@next` is temporary
# theseus_gui
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
First, make sure [NodeJS](https://nodejs.org/en/download/package-manager/) & [pnpm](https://pnpm.io/installation#nodejs-is-preinstalled) are installed, then run:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```zsh
pnpm install # Install dependencies
pnpm dev # Start dev server
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
pnpm build
```

View File

@ -1,6 +1,6 @@
{
"scripts": {
"dev": "tauri dev",
"dev": "tauri dev; kill $(lsof -t -i:3000)",
"dev:web": "svelte-kit dev",
"tauri": "tauri",
"build": "tauri build",
@ -10,14 +10,16 @@
"check": "cargo check --manifest-path src-tauri/Cargo.toml && svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@tauri-apps/cli": "^1.0.0-rc.5",
"@sveltejs/adapter-static": "next",
"@sveltejs/kit": "next",
"@tauri-apps/cli": "^1.0.0-rc.5",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-svelte3": "^3.2.1",
"postcss": "^8.4.7",
"postcss-load-config": "^3.1.3",
"prettier": "^2.5.1",
"prettier-plugin-svelte": "^2.5.0",
"svelte": "^3.46.0",
@ -28,6 +30,20 @@
},
"type": "module",
"dependencies": {
"@tauri-apps/api": "^1.0.0-rc.1"
"@fontsource/inter": "^4.5.4",
"@iconify-json/carbon": "^1.1.1",
"@iconify-json/heroicons-outline": "^1.1.1",
"@iconify-json/lucide": "^1.1.5",
"@tauri-apps/api": "^1.0.0-rc.1",
"autoprefixer": "^10.4.2",
"cssnano": "^5.1.0",
"postcss-extend-rule": "^4.0.0",
"postcss-import": "^14.0.2",
"postcss-media-minmax": "^5.0.0",
"postcss-nested": "^5.0.6",
"postcss-preset-env": "^7.4.2",
"sanitize.css": "^13.0.0",
"svrollbar": "^0.10.4",
"unplugin-icons": "^0.13.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
const dev = process.env.NODE_ENV === 'development';
const config = {
plugins: [
require('postcss-import')(),
require('autoprefixer')(),
require('postcss-nested')(),
require('postcss-extend-rule')(),
//require('postcss-preset-env')(), Errors with cssnano
require('postcss-media-minmax')(),
!dev &&
require('cssnano')({
preset: 'default',
}),
],
};
module.exports = config;

View File

@ -78,7 +78,7 @@ fn main() {
let event_name = event.menu_item_id();
match event_name {
"Learn More" => {
let url = "https://github.com/probablykasper/tauri-template".to_string();
let url = "https://modrinth.com".to_string();
shell::open(&event.window().shell_scope(), url, None).unwrap();
}
_ => {}

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;
}

View File

@ -1,13 +1,35 @@
import adapter from '@sveltejs/adapter-static';
import preprocess from 'svelte-preprocess';
import path from "path";
import Icons from 'unplugin-icons/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: preprocess(),
kit: {
adapter: adapter(),
}
preprocess: preprocess({
postcss: true,
}),
kit: {
adapter: adapter({
fallback: '200.html',
}),
vite: {
plugins: [
Icons({
compiler: 'svelte',
}),
],
resolve: {
alias: {
$assets: path.resolve('./src/assets'),
$components: path.resolve('./src/components'),
$lib: path.resolve('./src/lib'),
$stores: path.resolve('./src/stores'),
$styles: path.resolve('./src/styles'),
$generated: path.resolve('./src/generated'),
},
},
}
}
};
export default config;

View File

@ -28,8 +28,13 @@
"allowJs": true,
"checkJs": true,
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
"$assets/*": ["src/assets/*"],
"$components/*": ["src/components/*"],
"$lib/*": ["src/lib/*"],
"$stores/*": ["src/stores/*"],
"$styles/*": ["src/styles/*"],
"$generated/*": ["src/generated/*"],
"$lib":["src/lib"],
}
},
"include": [
@ -37,5 +42,6 @@
"src/**/*.js",
"src/**/*.ts",
"src/**/*.svelte"
]
],
"extends": "./.svelte-kit/tsconfig.json"
}