You've already forked AstralRinth
forked from didirus/AstralRinth
Start search page + Add i18n & generation base
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -10,4 +10,5 @@ WixTools
|
|||||||
theseus_cli/launcher
|
theseus_cli/launcher
|
||||||
theseus_cli/foo
|
theseus_cli/foo
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.pnpm-debug.log
|
.pnpm-debug.log
|
||||||
|
generated/
|
||||||
130
theseus_gui/locales/en.json
Normal file
130
theseus_gui/locales/en.json
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
{
|
||||||
|
"pages": {
|
||||||
|
"description": "Description",
|
||||||
|
"gallery": "Gallery",
|
||||||
|
"changelog": "Changelog",
|
||||||
|
"versions": "Versions",
|
||||||
|
"settings": "Settings",
|
||||||
|
"reports": "Reports",
|
||||||
|
"moderation": "Moderation",
|
||||||
|
"notifications": "Notifications",
|
||||||
|
"about": "About",
|
||||||
|
"following": "Following",
|
||||||
|
"all": "All"
|
||||||
|
},
|
||||||
|
"generic": {
|
||||||
|
"labels": {
|
||||||
|
"license": "License",
|
||||||
|
"project_id": "Project ID",
|
||||||
|
"project_status": "Project status"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"edit": "Edit",
|
||||||
|
"follow": "Follow",
|
||||||
|
"unfollow": "Unfollow",
|
||||||
|
"report": "Report",
|
||||||
|
"new_project": "New project",
|
||||||
|
"download": "Download",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"discard": "Discard changes"
|
||||||
|
},
|
||||||
|
"external": {
|
||||||
|
"github_profile": "GitHub profile",
|
||||||
|
"discord": "Discord",
|
||||||
|
"github": "GitHub",
|
||||||
|
"issues": "Issues",
|
||||||
|
"source": "Source",
|
||||||
|
"wiki": "Wiki",
|
||||||
|
"patreon": "Patreon",
|
||||||
|
"paypal": "PayPal",
|
||||||
|
"buy_me_a_coffee": "Buy Me a Coffee",
|
||||||
|
"github_sponsors": "GitHub Sponsors",
|
||||||
|
"donate": "Donate",
|
||||||
|
"kofi": "Ko-Fi"
|
||||||
|
},
|
||||||
|
"environments": {
|
||||||
|
"label": "Environment",
|
||||||
|
"server_side": "Server side",
|
||||||
|
"client_side": "Client side",
|
||||||
|
"values": {
|
||||||
|
"required": "Required",
|
||||||
|
"unsupported": "Unsupported",
|
||||||
|
"optional": "Optional",
|
||||||
|
"unknown": "Unknown"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"byline": "by <u>{author}</u>"
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"types": {
|
||||||
|
"mod": {
|
||||||
|
"singular": "Mod",
|
||||||
|
"plural": "Mods",
|
||||||
|
"search": "Search mods..."
|
||||||
|
},
|
||||||
|
"modpack": {
|
||||||
|
"singular": "Modpack",
|
||||||
|
"plural": "Modpacks",
|
||||||
|
"search": "Search modpacks..."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sidebar_headings": {
|
||||||
|
"external_resources": "External resources",
|
||||||
|
"featured_versions": "Featured versions",
|
||||||
|
"project_members": "Project members",
|
||||||
|
"technical_information": "Technical information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"approved": "Approved",
|
||||||
|
"rejected": "Rejected",
|
||||||
|
"draft": "Draft",
|
||||||
|
"unlisted": "Unlisted",
|
||||||
|
"processing": "Under review",
|
||||||
|
"unknown": "Unknown"
|
||||||
|
},
|
||||||
|
"release_channels": {
|
||||||
|
"release": "Release",
|
||||||
|
"beta": "Beta",
|
||||||
|
"alpha": "Alpha"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"developer": "Developer",
|
||||||
|
"admin": "Admin",
|
||||||
|
"moderator": "Moderator"
|
||||||
|
},
|
||||||
|
"stats": {
|
||||||
|
"joined": "Joined {ago}",
|
||||||
|
"notified": "Notified {ago}",
|
||||||
|
"downloads": "{downloads, plural, one {<b>1</b> download} other {<b>#</b> downloads}}",
|
||||||
|
"followers_of_projects": "{followers, plural, one {<b>1</b> follower of projects} other {<b>#</b> followers of projects}}",
|
||||||
|
"followers": "{followers, plural, one {<b>1</b> follower} other {<b>#</b> followers}}",
|
||||||
|
"user_id": "User ID: {id}",
|
||||||
|
"created": "Created {ago}",
|
||||||
|
"updated": "Updated {ago}"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"technology": "Technology",
|
||||||
|
"adventure": "Adventure",
|
||||||
|
"magic": "Magic",
|
||||||
|
"utility": "Utility",
|
||||||
|
"decoration": "Decoration",
|
||||||
|
"library": "Library",
|
||||||
|
"cursed": "Cursed",
|
||||||
|
"worldgen": "World generation",
|
||||||
|
"storage": "Storage",
|
||||||
|
"food": "Food",
|
||||||
|
"equipment": "Equipment",
|
||||||
|
"miscellaneous": "Miscellaneous",
|
||||||
|
"optimization": "Optimization",
|
||||||
|
"fabric": "Fabric",
|
||||||
|
"quilt": "Quilt",
|
||||||
|
"forge": "Forge",
|
||||||
|
"server": "Server",
|
||||||
|
"client": "Client",
|
||||||
|
"good": "Good",
|
||||||
|
"trash": "Trash",
|
||||||
|
"misc": "Miscellaneous"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,9 @@
|
|||||||
"build:web": "svelte-kit build",
|
"build:web": "svelte-kit build",
|
||||||
"test": "cargo ../test --manifest-path ./src-tauri/Cargo.toml",
|
"test": "cargo ../test --manifest-path ./src-tauri/Cargo.toml",
|
||||||
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. src",
|
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. src",
|
||||||
"check": "cargo check --manifest-path src-tauri/Cargo.toml && svelte-check --tsconfig ./tsconfig.json"
|
"check": "cargo check --manifest-path src-tauri/Cargo.toml && svelte-check --tsconfig ./tsconfig.json",
|
||||||
|
"generate": "node ./scripts/generate.js",
|
||||||
|
"postinstall": "pnpm generate"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-static": "next",
|
"@sveltejs/adapter-static": "next",
|
||||||
@@ -20,22 +22,25 @@
|
|||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-svelte3": "^3.2.1",
|
"eslint-plugin-svelte3": "^3.2.1",
|
||||||
"kill-port-process": "^3.0.1",
|
"kill-port-process": "^3.0.1",
|
||||||
|
"node-fetch": "^3.2.4",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"prettier-plugin-svelte": "^2.5.0",
|
"prettier-plugin-svelte": "^2.5.0",
|
||||||
"svelte": "^3.46.0",
|
"svelte": "^3.48.0",
|
||||||
"svelte-check": "^2.2.6",
|
"svelte-check": "^2.2.6",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"typescript": "~4.5.4"
|
"typescript": "~4.5.4"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.17.10",
|
||||||
"@fontsource/inter": "^4.5.4",
|
"@fontsource/inter": "^4.5.4",
|
||||||
"@iconify-json/carbon": "^1.1.1",
|
"@iconify-json/carbon": "^1.1.1",
|
||||||
"@iconify-json/heroicons-outline": "^1.1.1",
|
"@iconify-json/heroicons-outline": "^1.1.1",
|
||||||
"@iconify-json/heroicons-solid": "^1.1.1",
|
"@iconify-json/heroicons-solid": "^1.1.1",
|
||||||
"@iconify-json/lucide": "^1.1.5",
|
"@iconify-json/lucide": "^1.1.5",
|
||||||
"@tauri-apps/api": "^1.0.0-rc.1",
|
"@tauri-apps/api": "^1.0.0-rc.1",
|
||||||
"omorphia": "0.0.17",
|
"omorphia": "0.0.19",
|
||||||
|
"svelte-intl-precompile": "^0.9.2",
|
||||||
"svrollbar": "^0.10.4",
|
"svrollbar": "^0.10.4",
|
||||||
"unplugin-icons": "^0.13.2"
|
"unplugin-icons": "^0.13.2"
|
||||||
}
|
}
|
||||||
|
|||||||
645
theseus_gui/pnpm-lock.yaml
generated
645
theseus_gui/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
56
theseus_gui/scripts/generate.js
Normal file
56
theseus_gui/scripts/generate.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
|
|
||||||
|
const API_URL =
|
||||||
|
process.env.VITE_API_URL || process.env?.NODE_ENV === 'development'
|
||||||
|
? 'https://staging-api.modrinth.com/v2/'
|
||||||
|
: 'https://api.modrinth.com/v2/';
|
||||||
|
const GENERATED_PATH = './generated/';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
/* GAME VERSIONS */
|
||||||
|
|
||||||
|
// Fetch data
|
||||||
|
let gameVersions = await (await fetch(API_URL + 'tag/game_version')).json();
|
||||||
|
|
||||||
|
// Write JSON file
|
||||||
|
await fs.writeFile(GENERATED_PATH + 'gameVersions.json', JSON.stringify(gameVersions));
|
||||||
|
|
||||||
|
console.log('Generated gameVersions.json');
|
||||||
|
|
||||||
|
/* TAGS */
|
||||||
|
|
||||||
|
// Fetch data
|
||||||
|
let [categories, loaders, licenses, donationPlatforms] = await Promise.all([
|
||||||
|
await (await fetch(API_URL + 'tag/category')).json(),
|
||||||
|
await (await fetch(API_URL + 'tag/loader')).json(),
|
||||||
|
await (await fetch(API_URL + 'tag/license')).json(),
|
||||||
|
await (await fetch(API_URL + 'tag/donation_platform')).json(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create single object with icons
|
||||||
|
let tagIcons = {
|
||||||
|
...categories.reduce((a, v) => ({ ...a, [v.name]: v.icon }), {}),
|
||||||
|
...loaders.reduce((a, v) => ({ ...a, [v.name]: v.icon }), {}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add icon class
|
||||||
|
tagIcons = Object.fromEntries(Object.entries(tagIcons).map(([k, v]) => [k, v.replace('<svg', '<svg class="icon"')]));
|
||||||
|
|
||||||
|
// Delete icons from original arrays
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
categories = categories.map(({ icon, ...rest }) => rest);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
loaders = loaders.map(({ icon, ...rest }) => rest);
|
||||||
|
|
||||||
|
// Set project types
|
||||||
|
const projectTypes = ['mod', 'modpack'];
|
||||||
|
|
||||||
|
// Write JSON file
|
||||||
|
await fs.writeFile(
|
||||||
|
GENERATED_PATH + 'tags.json',
|
||||||
|
JSON.stringify({ categories, loaders, projectTypes, licenses, donationPlatforms, tagIcons })
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('Generated tags.json');
|
||||||
|
})();
|
||||||
129
theseus_gui/src/components/ProjectCard.svelte
Normal file
129
theseus_gui/src/components/ProjectCard.svelte
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { t } from 'svelte-intl-precompile';
|
||||||
|
import IconHeart from 'virtual:icons/lucide/heart';
|
||||||
|
import IconDownload from 'virtual:icons/heroicons-outline/download';
|
||||||
|
import IconCalendar from 'virtual:icons/lucide/calendar';
|
||||||
|
import { ago, simplify } from 'omorphia/utils';
|
||||||
|
import { Avatar, Button } from 'omorphia';
|
||||||
|
import { tagIcons } from '$generated/tags.json';
|
||||||
|
|
||||||
|
export let project;
|
||||||
|
|
||||||
|
// @ts-ignore: Author is only available in the result
|
||||||
|
let author = project.author ?? '';
|
||||||
|
|
||||||
|
// @ts-ignore: ID is in different locations in the result and project
|
||||||
|
let id = project.id ?? project.project_id;
|
||||||
|
|
||||||
|
// @ts-ignore: Updated is in different locations in the result and project
|
||||||
|
let updated = project.date_modified ?? project.updated;
|
||||||
|
|
||||||
|
const href = `/${project.project_type}/${project.slug || id}`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="card project-card">
|
||||||
|
<a {href} tabindex="-1">
|
||||||
|
<Avatar src={project.icon_url} size="md" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="project-card__info">
|
||||||
|
<div class="project-card__info__top">
|
||||||
|
<div class="project-card__info__top__text">
|
||||||
|
<span
|
||||||
|
><a class="project-card__info__top__text__title" {href}>{project.title}</a>
|
||||||
|
{#if author}
|
||||||
|
<a href="/user/{author}" class="project-card__info__top__text__author"
|
||||||
|
>{@html $t('generic.byline', { values: { author } })}</a
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<p class="summary">
|
||||||
|
{project.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="button-group">
|
||||||
|
<Button color="primary"><IconDownload />Install</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tag-group">
|
||||||
|
{#each project.categories as category}
|
||||||
|
<div class="tag">
|
||||||
|
{@html tagIcons[category] || '?'}
|
||||||
|
{$t(`tags.${category}`)}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<span class="stat">
|
||||||
|
<IconDownload />
|
||||||
|
<b>{simplify(project.downloads)}</b>
|
||||||
|
</span>
|
||||||
|
<span class="tag">
|
||||||
|
<IconCalendar />
|
||||||
|
{@html $t('stats.updated', { values: { ago: ago(updated) } })}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if !$$slots.actions}{:else}
|
||||||
|
<slot name="actions" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.project-card {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding: 10px;
|
||||||
|
grid-gap: 1rem;
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
grid-gap: 0.25rem;
|
||||||
|
line-height: 100%;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&__top {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__author {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: calc(100vw - 224px - 24px - 16px - 64px - 130px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.button-group) {
|
||||||
|
margin-left: auto;
|
||||||
|
height: 33px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-group {
|
||||||
|
.stat {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<div class="vertical-nav">
|
<div class="vertical-nav">
|
||||||
{#each items as item (item.href)}
|
{#each items as item (item.href)}
|
||||||
<a class="nav-item" href="/{item.href}" class:active={path[level] === item.href}>
|
<a class="nav-item" href="/{item.href}" class:active={path[level] === item.href} sveltekit:prefetch>
|
||||||
<svelte:component this={item.icon} />
|
<svelte:component this={item.icon} />
|
||||||
{item.label}
|
{item.label}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
grid-gap: 8px;
|
grid-gap: 8px;
|
||||||
|
|
||||||
:global(button) {
|
:global(button) {
|
||||||
width: 34px;
|
width: 32px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,91 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import IconChevronLeft from 'virtual:icons/lucide/chevron-left';
|
import IconChevronLeft from 'virtual:icons/lucide/chevron-left';
|
||||||
import IconChevronRight from 'virtual:icons/lucide/chevron-right';
|
import IconChevronRight from 'virtual:icons/lucide/chevron-right';
|
||||||
import IconCaretRight from 'virtual:icons/carbon/caret-right';
|
import IconCaretRight from 'virtual:icons/carbon/caret-right';
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
let path: string[];
|
let path: string[];
|
||||||
$: path = $page.url.pathname
|
$: path = $page.url.pathname.substring(1).split('/');
|
||||||
.substring(1)
|
|
||||||
.split('/')
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="status-bar">
|
<div class="status-bar">
|
||||||
<div class="page-nav">
|
<div class="page-nav">
|
||||||
<button title="Back" on:click={() => window.history.back()}>
|
<button title="Back" on:click={() => window.history.back()}>
|
||||||
<IconChevronLeft />
|
<IconChevronLeft />
|
||||||
</button>
|
</button>
|
||||||
<button title="Forward" on:click={() => window.history.forward()}>
|
<button title="Forward" on:click={() => window.history.forward()}>
|
||||||
<IconChevronRight />
|
<IconChevronRight />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="breadcrumbs">
|
<div class="breadcrumbs">
|
||||||
{#each path as crumb, index}
|
{#each path as crumb, index}
|
||||||
{#if index !== 0}
|
{#if index !== 0}
|
||||||
<IconCaretRight />
|
<IconCaretRight />
|
||||||
{/if}
|
{/if}
|
||||||
<a class="breadcrumbs__crumb" href={crumb}>{crumb || 'home'}</a>
|
<a class="breadcrumbs__crumb" href={crumb}>{crumb || 'home'}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="statuses">
|
<div class="statuses">
|
||||||
<div>Updating 12 mods...</div>
|
<div>Updating 12 mods...</div>
|
||||||
<div>236 mods installed</div>
|
<div>236 mods installed</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.status-bar {
|
.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);
|
||||||
|
|
||||||
|
.page-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
|
||||||
|
button {
|
||||||
display: flex;
|
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 {
|
.breadcrumbs {
|
||||||
display: flex;
|
display: flex;
|
||||||
grid-gap: 0.25rem;
|
grid-gap: 0.25rem;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
&__crumb:hover {
|
/* Hide scrollbar */
|
||||||
text-decoration: underline;
|
&::-webkit-scrollbar {
|
||||||
}
|
display: none; /* Chrome, Safari and Opera */
|
||||||
|
}
|
||||||
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
|
||||||
:global(.icon) {
|
&__crumb:hover {
|
||||||
color: var(--color-text-lightest)
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.icon) {
|
||||||
|
color: var(--color-text-lightest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.statuses {
|
.statuses {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
display: flex;
|
align-items: flex-end;
|
||||||
grid-gap: 1rem;
|
justify-content: flex-end;
|
||||||
color: var(--color-text-lightest);
|
display: flex;
|
||||||
|
grid-gap: 1rem;
|
||||||
|
color: var(--color-text-lightest);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
<script context="module" lang="ts">
|
||||||
|
import { init, waitLocale } from 'svelte-intl-precompile'
|
||||||
|
import { registerAll } from '$locales'
|
||||||
|
|
||||||
|
registerAll()
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').Load} */
|
||||||
|
export async function load({fetch, session, stuff}) {
|
||||||
|
init({
|
||||||
|
fallbackLocale: 'en',
|
||||||
|
initialLocale: session.acceptedLanguage,
|
||||||
|
})
|
||||||
|
await waitLocale()
|
||||||
|
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '@fontsource/inter'
|
import '@fontsource/inter'
|
||||||
import 'omorphia/styles.postcss'
|
import 'omorphia/styles.postcss'
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<TitledSection title="Override global settings" toggleable=true>
|
<TitledSection title="Override global settings" toggleable={true}>
|
||||||
<GlobalSettings />
|
<GlobalSettings />
|
||||||
</TitledSection>
|
</TitledSection>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
12
theseus_gui/src/routes/search/__layout.svelte
Normal file
12
theseus_gui/src/routes/search/__layout.svelte
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<div class="layout-search">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.layout-search {
|
||||||
|
display: flex;
|
||||||
|
padding: 16px;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
90
theseus_gui/src/routes/search/index.svelte
Normal file
90
theseus_gui/src/routes/search/index.svelte
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
/** @type {import('./index').Load} */
|
||||||
|
export async function load({ fetch }) {
|
||||||
|
const response = await fetch(`https://api.modrinth.com/v2/search?query=&limit=10&offset=0&index=relevance`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
projects: response.ok && (await response.json()).hits
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import IconSearch from 'virtual:icons/heroicons-outline/search';
|
||||||
|
import IconSortDescending from 'virtual:icons/heroicons-outline/sort-descending';
|
||||||
|
import IconBox from 'virtual:icons/lucide/box';
|
||||||
|
import IconGlobe from 'virtual:icons/lucide/globe';
|
||||||
|
import IconCpu from 'virtual:icons/lucide/cpu';
|
||||||
|
import IconTruck from 'virtual:icons/lucide/truck';
|
||||||
|
import IconFileText from 'virtual:icons/lucide/file-text';
|
||||||
|
|
||||||
|
import { TextInput, Button } from 'omorphia';
|
||||||
|
import ProjectCard from '$components/ProjectCard.svelte';
|
||||||
|
|
||||||
|
export let projects;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<div class="controls__row">
|
||||||
|
<TextInput placeholder="Search..." icon={IconSearch} />
|
||||||
|
<Button color="tertiary"><IconSortDescending />Sort by relevance</Button>
|
||||||
|
</div>
|
||||||
|
<div class="controls__row controls__row--overflow">
|
||||||
|
<Button color="secondary"><IconBox />Minecraft versions</Button>
|
||||||
|
<Button color="secondary"><IconGlobe />Categories</Button>
|
||||||
|
<Button color="secondary"><IconCpu />Environment</Button>
|
||||||
|
<Button color="secondary"><IconTruck />Mod loaders</Button>
|
||||||
|
<Button color="secondary"><IconFileText />License</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="results">
|
||||||
|
{#each projects as project}
|
||||||
|
<ProjectCard {project} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
&--overflow {
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 0px -4px;
|
||||||
|
padding: 0 6px;
|
||||||
|
width: calc(100% + 3px);
|
||||||
|
mask-image: linear-gradient(to right, transparent, hsla(0, 0%, 0%, 1) 1% 99%, transparent);
|
||||||
|
|
||||||
|
/* Hide scrollbar */
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.text-input) {
|
||||||
|
flex: 1 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.text-input > input) {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.results {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
@import 'components.postcss';
|
@import 'components.postcss';
|
||||||
|
|
||||||
|
.base {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar--size-md {
|
||||||
|
--size: 64px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-dark {
|
.theme-dark {
|
||||||
--status-bg: hsl(216, 5%, 29%);
|
--status-bg: hsl(216, 5%, 29%);
|
||||||
--sidebar-bg: hsl(216, 10%, 3%);
|
--sidebar-bg: hsl(216, 10%, 3%);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import adapter from '@sveltejs/adapter-static';
|
import adapter from '@sveltejs/adapter-static';
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { preprocess, plugins } from 'omorphia/config/svelte.config'
|
import { preprocess, plugins } from 'omorphia/config/svelte.config'
|
||||||
|
import precompileIntl from "svelte-intl-precompile/sveltekit-plugin";
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
@@ -12,6 +13,7 @@ const config = {
|
|||||||
vite: {
|
vite: {
|
||||||
plugins: [
|
plugins: [
|
||||||
...plugins,
|
...plugins,
|
||||||
|
precompileIntl('locales'),
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
@@ -21,9 +23,15 @@ const config = {
|
|||||||
$lib: path.resolve('./src/lib'),
|
$lib: path.resolve('./src/lib'),
|
||||||
$stores: path.resolve('./src/stores'),
|
$stores: path.resolve('./src/stores'),
|
||||||
$styles: path.resolve('./src/styles'),
|
$styles: path.resolve('./src/styles'),
|
||||||
$generated: path.resolve('./src/generated'),
|
$generated: path.resolve('./generated'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
fs: {
|
||||||
|
// Allow serving files from one level up to the project root
|
||||||
|
allow: ['..', './generated/*.json'],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"$lib/*": ["src/lib/*"],
|
"$lib/*": ["src/lib/*"],
|
||||||
"$stores/*": ["src/stores/*"],
|
"$stores/*": ["src/stores/*"],
|
||||||
"$styles/*": ["src/styles/*"],
|
"$styles/*": ["src/styles/*"],
|
||||||
"$generated/*": ["src/generated/*"],
|
"$generated/*": ["generated/*"],
|
||||||
"$lib":["src/lib"],
|
"$lib":["src/lib"],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user