You've already forked AstralRinth
forked from didirus/AstralRinth
Adds base UI for launcher. (#48)
* launcher base gui initial * Bootstraps router, Omorphia, and prettier. * Adds pages. Adds Vuex. SideBar nav contains user section and pages section. * Adds Instance markup. Instances added to Home page. * Adds News to home page. * Adds settings to nav. Other touches. * Polishing initial base GUI. * Moves some styling to assets. Changes px values to rem. * Removes pointless border-radius CSS. * Implements Omorphia vars. * Adds trending mods section. * Updates home page. * Swaps Vuex implementation for Pinia. * Fixes invalid CSS on instance list item hover. * Adds @ path resolve for imports. * Fix some styling of row display * Cleaning up styles and markup. * Fixes overall layout issues. * Cleans up more styling. Modifies AppBar coloring. * Allows pagination arrows to conditionally appear in RowDisplay. * Adds paging behavior in RowDisplay. * Updates nav and settings button styling. * Brings in Knossos style for trending mods. Polishes News CSS. * Updates Omorphia. Starts addressing PR comments. * Addresses some more PR comments. * Changes side navigation styling. Active route class implemented. * Combines trending and popular row. * Makes images more realistic. Adds CTA to instances. * Converts all instances to card style. Converts more styles to rem. * Moves Navigation and UserSection into App.vue * Adds Modrinth favicon. * Removes unused styling. * Adds transition to news card. --------- Co-authored-by: Jai A <jaiagr+gpg@pm.me> Co-authored-by: CodexAdrian <83074853+CodexAdrian@users.noreply.github.com>
This commit is contained in:
88
theseus_gui/.prettierignore
Normal file
88
theseus_gui/.prettierignore
Normal file
@@ -0,0 +1,88 @@
|
||||
node_modules
|
||||
*.log*
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
.output
|
||||
.env
|
||||
dist
|
||||
*.md
|
||||
|
||||
generated/
|
||||
!.gitkeep
|
||||
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
/logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
||||
|
||||
# pnpm files
|
||||
pnpm-lock.yaml
|
||||
/.npmrc
|
||||
6
theseus_gui/.prettierrc.json
Normal file
6
theseus_gui/.prettierrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
# Tauri + Vue 3
|
||||
|
||||
This template should help get you started developing with Tauri + Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
||||
32
theseus_gui/eslintrc.json
Normal file
32
theseus_gui/eslintrc.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/vue3-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"vue",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"vue/no-v-html": "off",
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
"only-multiline"
|
||||
],
|
||||
"vue/multi-word-component-names": "off",
|
||||
"import/no-named-as-default": "off"
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,23 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"axios": "^1.3.4",
|
||||
"omorphia": "^0.4.0",
|
||||
"pinia": "^2.0.33",
|
||||
"vue": "^3.2.45",
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"vue-router": "4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-alias": "^4.0.3",
|
||||
"@tauri-apps/cli": "^1.2.2",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"prettier": "^2.8.4",
|
||||
"sass": "^1.58.3",
|
||||
"vite": "^4.0.0",
|
||||
"@tauri-apps/cli": "^1.2.2"
|
||||
"vite-plugin-eslint": "^1.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
theseus_gui/src-tauri/icons/favicon.ico
Normal file
BIN
theseus_gui/src-tauri/icons/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -27,11 +27,7 @@
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
"icons/favicon.ico"
|
||||
],
|
||||
"identifier": "com.tauri.dev",
|
||||
"longDescription": "",
|
||||
@@ -60,11 +56,11 @@
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
"height": 600,
|
||||
"height": 650,
|
||||
"resizable": true,
|
||||
"title": "theseus_gui",
|
||||
"width": 800
|
||||
"title": "Modrinth Launcher",
|
||||
"width": 1140
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,299 @@
|
||||
<script setup></script>
|
||||
<script setup>
|
||||
import { watch } from 'vue'
|
||||
import { RouterView, useRoute, useRouter, RouterLink } from 'vue-router'
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
SearchIcon,
|
||||
BookIcon,
|
||||
ClientIcon,
|
||||
PlusIcon,
|
||||
SettingsIcon,
|
||||
Button,
|
||||
Avatar,
|
||||
} from 'omorphia'
|
||||
import { useTheming, useInstances } from '@/store/state'
|
||||
import { toggleTheme } from '@/helpers/theme'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const theme = useTheming()
|
||||
const instances = useInstances()
|
||||
instances.fetchInstances()
|
||||
|
||||
toggleTheme(theme.darkTheme)
|
||||
|
||||
watch(theme, (newState) => {
|
||||
toggleTheme(newState.darkTheme)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<h1>Modrinth</h1>
|
||||
<div class="navigation">
|
||||
<div class="nav-container">
|
||||
<section class="user-section">
|
||||
<Avatar size="sm" src="https://cdn.modrinth.com/data/AANobbMI/icon.png" />
|
||||
<section>
|
||||
<p class="username">OreoViking</p>
|
||||
<a href="#">Manage accounts</a>
|
||||
</section>
|
||||
</section>
|
||||
<div class="pages-list">
|
||||
<RouterLink to="/" class="btn"> <ClientIcon />Home</RouterLink>
|
||||
<RouterLink to="/browse" class="btn"> <SearchIcon />Browse</RouterLink>
|
||||
<RouterLink to="/library" class="btn"> <BookIcon />Library</RouterLink>
|
||||
</div>
|
||||
<div class="instance-list">
|
||||
<p>Instances</p>
|
||||
<Instance v-for="instance in instances.instances" display="list" :instance="instance" />
|
||||
</div>
|
||||
<Button class="add-instance-btn">
|
||||
<PlusIcon />
|
||||
Create Instance
|
||||
</Button>
|
||||
|
||||
<div class="settings">
|
||||
<RouterLink to="/settings" class="btn"><SettingsIcon /> Settings</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view">
|
||||
<div class="appbar">
|
||||
<section class="navigation-controls">
|
||||
<ChevronLeftIcon @click="router.back()" />
|
||||
<ChevronRightIcon @click="router.forward()" />
|
||||
<p>{{ route.name }}</p>
|
||||
</section>
|
||||
<section class="mod-stats">
|
||||
<p>Updating 2 mods...</p>
|
||||
<p>123 mods installed</p>
|
||||
</section>
|
||||
</div>
|
||||
<RouterView />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
min-width: 100%;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
|
||||
.navigation {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.view {
|
||||
height: 100%;
|
||||
margin-left: 210px;
|
||||
|
||||
.appbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
border-bottom: 1px solid rgba(64, 67, 74, 0.2);
|
||||
background: var(--color-button-bg);
|
||||
padding: 1.2rem;
|
||||
|
||||
.navigation-controls {
|
||||
display: inherit;
|
||||
align-items: inherit;
|
||||
justify-content: stretch;
|
||||
width: 30%;
|
||||
font-size: 0.9rem;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
transition: all ease-in-out 0.1s;
|
||||
|
||||
&:hover {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin-left: 0.3rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin: auto 0.1rem;
|
||||
transition: all ease-in-out 0.1s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mod-stats {
|
||||
display: inherit;
|
||||
align-items: inherit;
|
||||
justify-content: flex-end;
|
||||
width: 50%;
|
||||
font-size: 0.8rem;
|
||||
margin-right: 1rem;
|
||||
|
||||
p:nth-child(1) {
|
||||
margin-right: 0.55rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 210px;
|
||||
height: 100vh;
|
||||
box-shadow: var(--shadow-inset-sm), var(--shadow-floating);
|
||||
}
|
||||
|
||||
.dark-mode {
|
||||
.nav-container {
|
||||
background: var(--color-bg);
|
||||
}
|
||||
}
|
||||
.pages-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 80%;
|
||||
margin: 0.2rem auto;
|
||||
text-align: left;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 400;
|
||||
word-spacing: 3px;
|
||||
background: inherit;
|
||||
transition: all ease-in-out 0.1s;
|
||||
color: var(--color-primary);
|
||||
|
||||
&.router-link-active {
|
||||
color: #000;
|
||||
background: var(--color-button-bg);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-button-bg);
|
||||
color: var(--color-contrast);
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-right: 1rem;
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark-mode {
|
||||
.pages-list {
|
||||
a.router-link-active {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.instance-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 70%;
|
||||
margin: 0.4rem;
|
||||
|
||||
p:nth-child(1) {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
& > p {
|
||||
color: var(--color-base);
|
||||
margin: 0.8rem 0;
|
||||
font-size: 0.7rem;
|
||||
line-height: 0.8125rem;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
.add-instance-btn {
|
||||
background-color: var(--color-bg);
|
||||
font-size: 0.9rem;
|
||||
margin-right: 0.6rem;
|
||||
|
||||
svg {
|
||||
background-color: var(--color-green);
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
color: var(--color-accent-contrast);
|
||||
border-radius: var(--radius-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: auto auto 0.5rem 1rem;
|
||||
width: 9.375rem;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
background: inherit;
|
||||
color: var(--color-primary);
|
||||
|
||||
svg {
|
||||
margin-right: 0.9em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-section {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 4.375rem;
|
||||
margin-left: 3rem;
|
||||
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.username {
|
||||
margin-bottom: 0.3rem;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
11
theseus_gui/src/assets/stylesheets/global.css
Normal file
11
theseus_gui/src/assets/stylesheets/global.css
Normal file
@@ -0,0 +1,11 @@
|
||||
@import url('https://rsms.me/inter/inter.css');
|
||||
|
||||
:root {
|
||||
font-family: var(--font-standard);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
182
theseus_gui/src/components/RowDisplay.vue
Normal file
182
theseus_gui/src/components/RowDisplay.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<script setup>
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from 'omorphia'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import News from '@/components/ui/News.vue'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
instances: Array,
|
||||
news: Array,
|
||||
label: String,
|
||||
canPaginate: Boolean,
|
||||
})
|
||||
|
||||
const allowPagination = ref(false)
|
||||
const modsRow = ref(null)
|
||||
const newsRow = ref(null)
|
||||
|
||||
// Remove after state is populated with real data
|
||||
const shouldRenderNormalInstances = props.instances && props.instances?.length !== 0
|
||||
const shouldRenderNews = props.news && props.news?.length !== 0
|
||||
|
||||
const handlePaginationDisplay = () => {
|
||||
let parentsRow
|
||||
if (shouldRenderNormalInstances) parentsRow = modsRow.value
|
||||
if (shouldRenderNews) parentsRow = newsRow.value
|
||||
|
||||
if (!parentsRow) return
|
||||
|
||||
const children = parentsRow.children
|
||||
const lastChild = children[children.length - 1]
|
||||
const childBox = lastChild.getBoundingClientRect()
|
||||
|
||||
if (childBox.x + childBox.width > window.innerWidth) allowPagination.value = true
|
||||
else allowPagination.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.canPaginate) window.addEventListener('resize', handlePaginationDisplay)
|
||||
|
||||
// Check if pagination should be rendered on mount
|
||||
handlePaginationDisplay()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (props.canPaginate) window.removeEventListener('resize', handlePaginationDisplay)
|
||||
})
|
||||
|
||||
const handleLeftPage = () => {
|
||||
if (shouldRenderNormalInstances) modsRow.value.scrollLeft -= 170
|
||||
else if (shouldRenderNews) newsRow.value.scrollLeft -= 170
|
||||
}
|
||||
|
||||
const handleRightPage = () => {
|
||||
if (shouldRenderNormalInstances) modsRow.value.scrollLeft += 170
|
||||
else if (shouldRenderNews) newsRow.value.scrollLeft += 170
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="header">
|
||||
<p>{{ props.label }}</p>
|
||||
<hr aria-hidden="true" />
|
||||
<div v-if="allowPagination" class="pagination">
|
||||
<ChevronLeftIcon @click="handleLeftPage" />
|
||||
<ChevronRightIcon @click="handleRightPage" />
|
||||
</div>
|
||||
</div>
|
||||
<section ref="modsRow" class="instances" v-if="shouldRenderNormalInstances">
|
||||
<Instance
|
||||
v-for="instance in props.instances"
|
||||
:key="instance.id"
|
||||
display="card"
|
||||
:instance="instance"
|
||||
/>
|
||||
</section>
|
||||
<section ref="newsRow" class="news" v-else-if="shouldRenderNews">
|
||||
<News v-for="news in props.news" :key="news.id" :news="news" />
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
|
||||
&:nth-child(even) {
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: inherit;
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
gap: 1rem;
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
white-space: nowrap;
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: var(--color-gray);
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: inherit;
|
||||
align-items: inherit;
|
||||
|
||||
svg {
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--radius-lg);
|
||||
width: 1.3rem;
|
||||
height: 1.2rem;
|
||||
cursor: pointer;
|
||||
margin-right: 0.5rem;
|
||||
transition: all ease-in-out 0.1s;
|
||||
|
||||
&:hover {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
display: flex;
|
||||
align-items: inherit;
|
||||
transition: all ease-in-out 0.4s;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.news {
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
scroll-behavior: smooth;
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.instances {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
gap: 1rem;
|
||||
margin-right: auto;
|
||||
margin-top: 0.8rem;
|
||||
scroll-behavior: smooth;
|
||||
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark-mode {
|
||||
.row {
|
||||
&:nth-child(odd) {
|
||||
background-color: rgb(30, 31, 34);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
127
theseus_gui/src/components/ui/Instance.vue
Normal file
127
theseus_gui/src/components/ui/Instance.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<script setup>
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Card, PlusIcon } from 'omorphia'
|
||||
|
||||
const props = defineProps({
|
||||
display: String,
|
||||
instance: Object,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<RouterLink v-if="display === 'list'" class="instance-list-item" :to="`${props.instance.id}`">{{
|
||||
props.instance.name
|
||||
}}</RouterLink>
|
||||
<Card class="instance-card-item" v-else-if="display === 'card'">
|
||||
<img :src="props.instance.img" alt="Trending mod card" />
|
||||
<div class="project-info">
|
||||
<p class="title">{{ props.instance.name }}</p>
|
||||
<p class="description">{{ props.instance.version }}</p>
|
||||
</div>
|
||||
<div class="cta"><PlusIcon /></div>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.instance-list-item {
|
||||
display: inline-block;
|
||||
margin: 0.25rem auto;
|
||||
cursor: pointer;
|
||||
transition: all ease-out 0.1s;
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-primary);
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
filter: brightness(150%);
|
||||
}
|
||||
}
|
||||
|
||||
.instance-card-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
width: 180px;
|
||||
padding: 0.75rem;
|
||||
transition: 0.1s ease-in-out all;
|
||||
|
||||
&:hover {
|
||||
filter: brightness(0.85);
|
||||
|
||||
.cta {
|
||||
opacity: 1;
|
||||
bottom: 4.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.cta {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-brand);
|
||||
border-radius: var(--radius-lg);
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
right: 1rem;
|
||||
bottom: 3.5rem;
|
||||
opacity: 0;
|
||||
transition: 0.3s ease-in-out bottom, 0.1s ease-in-out opacity;
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
filter: brightness(0.75);
|
||||
box-shadow: var(--shadow-floating);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 160px;
|
||||
border-radius: var(--radius-sm);
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.project-info {
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
|
||||
.title {
|
||||
color: var(--color-contrast);
|
||||
max-width: 6rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
line-height: 110%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.description {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-weight: 500;
|
||||
font-size: 0.775rem;
|
||||
line-height: 125%;
|
||||
margin: 0.25rem 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark-mode {
|
||||
.cta > svg {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
97
theseus_gui/src/components/ui/News.vue
Normal file
97
theseus_gui/src/components/ui/News.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<script setup>
|
||||
import { Card, ChevronRightIcon } from 'omorphia'
|
||||
|
||||
const props = defineProps({
|
||||
news: Object,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card class="news-cta">
|
||||
<img :src="props.news.img" alt="News Image" />
|
||||
<div class="body">
|
||||
<div class="headline">
|
||||
<h2>{{ props.news.headline }}</h2>
|
||||
<p>{{ props.news.blurb }}</p>
|
||||
</div>
|
||||
<div class="underline">
|
||||
<p>{{ props.news.source }}</p>
|
||||
<a href="#"><ChevronRightIcon /></a>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-cta {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
background: var(--color-raised-bg);
|
||||
min-width: 24.125rem; /* from wireframe */
|
||||
min-height: 8.5rem; /* from wireframe */
|
||||
box-shadow: var(--shadow-raised-lg);
|
||||
cursor: pointer;
|
||||
transition: all ease-in-out 0.1s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--shadow-floating);
|
||||
filter: brightness(0.85);
|
||||
}
|
||||
|
||||
img {
|
||||
display: flex;
|
||||
width: 8.4375rem; /* from wireframe */
|
||||
height: 8.5rem; /* from wireframe */
|
||||
border-radius: 0.9rem 0 0 0.9rem;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 8.5rem; /* from wireframe */
|
||||
padding: 0.45rem;
|
||||
|
||||
.headline {
|
||||
display: inherit;
|
||||
flex-direction: inherit;
|
||||
margin: 0.4rem 0;
|
||||
width: 100%;
|
||||
|
||||
h2 {
|
||||
font-size: 1rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
.underline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-top: auto;
|
||||
|
||||
p {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
a {
|
||||
transition: all ease-in-out 0.2s;
|
||||
width: 1.5rem;
|
||||
color: var(--color-primary);
|
||||
font-size: 1.3rem;
|
||||
|
||||
&:hover {
|
||||
transform: translate(1px);
|
||||
filter: brightness(150%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
13
theseus_gui/src/helpers/theme.js
Normal file
13
theseus_gui/src/helpers/theme.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Sets the dark-mode or light-mode class on <html> if dark mode is on.
|
||||
* @param {Boolean} isDarkMode Bool value indicating if dark mode is on.
|
||||
*/
|
||||
export const toggleTheme = (isDarkMode) => {
|
||||
if (isDarkMode) {
|
||||
document.getElementsByTagName('html')[0].classList.remove('light-mode')
|
||||
document.getElementsByTagName('html')[0].classList.add('dark-mode')
|
||||
} else {
|
||||
document.getElementsByTagName('html')[0].classList.remove('dark-mode')
|
||||
document.getElementsByTagName('html')[0].classList.add('light-mode')
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
import { createApp } from "vue";
|
||||
import "./style.css";
|
||||
import App from "./App.vue";
|
||||
import { createApp } from 'vue'
|
||||
import router from '@/routes'
|
||||
import App from '@/App.vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import '../node_modules/omorphia/dist/style.css'
|
||||
import '@/assets/stylesheets/global.css'
|
||||
|
||||
createApp(App).mount("#app");
|
||||
const pinia = createPinia()
|
||||
|
||||
createApp(App).use(router).use(pinia).mount('#app')
|
||||
|
||||
7
theseus_gui/src/pages/Browse.vue
Normal file
7
theseus_gui/src/pages/Browse.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>Browse page</p>
|
||||
</div>
|
||||
</template>
|
||||
31
theseus_gui/src/pages/Index.vue
Normal file
31
theseus_gui/src/pages/Index.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup>
|
||||
import { useInstances, useNews } from '@/store/state'
|
||||
import RowDisplay from '@/components/RowDisplay.vue'
|
||||
|
||||
const instances = useInstances()
|
||||
const news = useNews()
|
||||
instances.fetchInstances()
|
||||
news.fetchNews()
|
||||
|
||||
// Remove once state is populated with real data
|
||||
const recentInstances = instances.instances.slice(0, 4)
|
||||
const popularInstances = instances.instances.filter((i) => i.downloads > 50 || i.trending)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<RowDisplay label="Jump back in" :instances="recentInstances" :canPaginate="false" />
|
||||
<RowDisplay label="Popular packs" :instances="popularInstances" :canPaginate="true" />
|
||||
<RowDisplay label="News & updates" :news="news.news" :canPaginate="true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
7
theseus_gui/src/pages/Library.vue
Normal file
7
theseus_gui/src/pages/Library.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>Library</p>
|
||||
</div>
|
||||
</template>
|
||||
7
theseus_gui/src/pages/Project.vue
Normal file
7
theseus_gui/src/pages/Project.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>Project page</p>
|
||||
</div>
|
||||
</template>
|
||||
7
theseus_gui/src/pages/Settings.vue
Normal file
7
theseus_gui/src/pages/Settings.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>Settings page</p>
|
||||
</div>
|
||||
</template>
|
||||
7
theseus_gui/src/pages/index.js
Normal file
7
theseus_gui/src/pages/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import Index from './Index.vue'
|
||||
import Browse from './Browse.vue'
|
||||
import Library from './Library.vue'
|
||||
import Project from './Project.vue'
|
||||
import Settings from './Settings.vue'
|
||||
|
||||
export { Index, Browse, Library, Project, Settings }
|
||||
14
theseus_gui/src/pages/instances/Instance.vue
Normal file
14
theseus_gui/src/pages/instances/Instance.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
console.log(route.path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
AAAAAH
|
||||
{{ route.params.name }}
|
||||
</div>
|
||||
</template>
|
||||
38
theseus_gui/src/routes.js
Normal file
38
theseus_gui/src/routes.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import * as Pages from '@/pages'
|
||||
|
||||
/**
|
||||
* Configures application routing. Add page to pages/index and then add to route table here.
|
||||
*/
|
||||
export default new createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Pages.Index,
|
||||
},
|
||||
{
|
||||
path: '/browse',
|
||||
name: 'Browse',
|
||||
component: Pages.Browse,
|
||||
},
|
||||
{
|
||||
path: '/library',
|
||||
name: 'Library',
|
||||
component: Pages.Library,
|
||||
},
|
||||
{
|
||||
path: '/project',
|
||||
name: 'Project',
|
||||
component: Pages.Project,
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
component: Pages.Settings,
|
||||
},
|
||||
],
|
||||
linkActiveClass: 'router-link-active',
|
||||
linkExactActiveClass: 'router-link-exact-active',
|
||||
})
|
||||
156
theseus_gui/src/store/state.js
Normal file
156
theseus_gui/src/store/state.js
Normal file
@@ -0,0 +1,156 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useTheming = defineStore('theme', {
|
||||
state: () => ({ darkTheme: true }),
|
||||
actions: {
|
||||
toggleTheme() {
|
||||
this.darkTheme = !this.darkTheme
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const useInstances = defineStore('instances', {
|
||||
state: () => ({ instances: [] }),
|
||||
actions: {
|
||||
fetchInstances() {
|
||||
// Fetch from backend.
|
||||
const instances = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Fabulously Optimized',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.18.1',
|
||||
downloads: 10,
|
||||
trending: true,
|
||||
img: 'https://cdn.modrinth.com/user/MpxzqsyW/eb0038489a55e7e7a188a5b50462f0b10dfc1613.jpeg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'New Caves',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.18 ',
|
||||
downloads: 8,
|
||||
trending: true,
|
||||
img: 'https://cdn.modrinth.com/data/ssUbhMkL/icon.png',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'All the Mods 6',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.16.5',
|
||||
downloads: 4,
|
||||
trending: true,
|
||||
img: 'https://avatars1.githubusercontent.com/u/6166773?v=4',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Bees',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.15.2',
|
||||
downloads: 9,
|
||||
trending: false,
|
||||
img: 'https://cdn.modrinth.com/data/ssUbhMkL/icon.png',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'SkyFactory 4',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.12.2',
|
||||
downloads: 1000,
|
||||
trending: false,
|
||||
img: 'https://cdn.modrinth.com/user/MpxzqsyW/eb0038489a55e7e7a188a5b50462f0b10dfc1613.jpeg',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'RLCraft',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.12.2',
|
||||
downloads: 10000,
|
||||
trending: false,
|
||||
img: 'https://avatars1.githubusercontent.com/u/6166773?v=4',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Regrowth',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.7.10',
|
||||
downloads: 1000,
|
||||
trending: false,
|
||||
img: 'https://cdn.modrinth.com/data/ssUbhMkL/icon.png',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Birds',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.15.2',
|
||||
downloads: 9,
|
||||
trending: false,
|
||||
img: 'https://avatars.githubusercontent.com/u/83074853?v=4',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Dogs',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.15.2',
|
||||
downloads: 9,
|
||||
trending: false,
|
||||
img: 'https://cdn.modrinth.com/user/MpxzqsyW/eb0038489a55e7e7a188a5b50462f0b10dfc1613.jpeg',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: 'Cats',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.15.2',
|
||||
downloads: 9,
|
||||
trending: false,
|
||||
img: 'https://cdn.modrinth.com/data/ssUbhMkL/icon.png',
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: 'Rabbits',
|
||||
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
|
||||
version: '1.15.2',
|
||||
downloads: 9,
|
||||
trending: false,
|
||||
img: 'https://avatars1.githubusercontent.com/u/6166773?v=4',
|
||||
},
|
||||
]
|
||||
|
||||
this.instances = [...instances]
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const useNews = defineStore('news', {
|
||||
state: () => ({ news: [] }),
|
||||
actions: {
|
||||
fetchNews() {
|
||||
// Fetch from backend.
|
||||
const news = [
|
||||
{
|
||||
id: 1,
|
||||
headline: 'Caves & Cliffs Update: Part II Dev Q&A',
|
||||
blurb: 'Your questions, answered!',
|
||||
source: 'From Minecraft.Net',
|
||||
img: 'https://avatars1.githubusercontent.com/u/6166773?v=4',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
headline: 'Project of the WeeK: Gobblygook',
|
||||
blurb: 'Your questions, answered!',
|
||||
source: 'Modrinth Blog',
|
||||
img: 'https://avatars.githubusercontent.com/t/3923733?s=280&v=4',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
headline: 'Oreo makes a launcher',
|
||||
blurb: 'What did it take?',
|
||||
source: 'Modrinth Blog',
|
||||
img: 'https://avatars.githubusercontent.com/u/30800863?v=4',
|
||||
},
|
||||
]
|
||||
|
||||
this.news = [...news]
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,15 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #0f0f0f;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
@@ -1,9 +1,23 @@
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import alias from '@rollup/plugin-alias'
|
||||
import { resolve } from 'path'
|
||||
|
||||
const projectRootDir = resolve(__dirname)
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
plugins: [
|
||||
vue(),
|
||||
alias({
|
||||
entries: [
|
||||
{
|
||||
find: '@',
|
||||
replacement: resolve(projectRootDir, 'src'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
// prevent vite from obscuring rust errors
|
||||
@@ -15,13 +29,16 @@ export default defineConfig({
|
||||
},
|
||||
// to make use of `TAURI_DEBUG` and other env variables
|
||||
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
|
||||
envPrefix: ["VITE_", "TAURI_"],
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
build: {
|
||||
// Tauri supports es2021
|
||||
target: process.env.TAURI_PLATFORM == "windows" ? "chrome105" : "safari13",
|
||||
target: process.env.TAURI_PLATFORM == 'windows' ? 'chrome105' : 'safari13',
|
||||
// don't minify for debug builds
|
||||
minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
|
||||
minify: !process.env.TAURI_DEBUG ? 'esbuild' : false,
|
||||
// produce sourcemaps for debug builds
|
||||
sourcemap: !!process.env.TAURI_DEBUG,
|
||||
commonjsOptions: {
|
||||
esmExternals: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user