Allow for logos to be used as instance names
This commit is contained in:
1 parent
a1f19e86c6
commit
522e3a5717
10 files changed
+38
-10
No files matched your search
@@ -332,6 +332,7 @@ pub struct InstanceSummary {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub icon_url: Option<String>,
|
pub icon_url: Option<String>,
|
||||||
pub banner_url: Option<String>,
|
pub banner_url: Option<String>,
|
||||||
|
pub logo_url: Option<String>,
|
||||||
pub mc_version: String,
|
pub mc_version: String,
|
||||||
pub loader: Loader,
|
pub loader: Loader,
|
||||||
pub loader_version: Option<String>,
|
pub loader_version: Option<String>,
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ const manifest: Manifest = {
|
|||||||
custom_css: '',
|
custom_css: '',
|
||||||
},
|
},
|
||||||
instances: [
|
instances: [
|
||||||
{ id: 'survival-smp', name: 'Survival SMP', description: 'Our main survival world — season 4. Claims, shops & weekend events.', icon_url: null, banner_url: null, mc_version: '1.21.1', loader: 'fabric', loader_version: '0.16.9', revision: 3, server: { name: 'SCOPENET SMP', address: 'play.scopenet.gg', port: 25565, auto_join: true, inject: true }, memory: { min_mb: 2048, max_mb: 6144 }, jvm_args: '', featured: true, source_label: 'Modrinth · Fabulously Optimized 6.2', file_count: 48, total_size: 184_000_000 },
|
{ id: 'survival-smp', name: 'Survival SMP', description: 'Our main survival world — season 4. Claims, shops & weekend events.', icon_url: null, banner_url: null, logo_url: null, mc_version: '1.21.1', loader: 'fabric', loader_version: '0.16.9', revision: 3, server: { name: 'SCOPENET SMP', address: 'play.scopenet.gg', port: 25565, auto_join: true, inject: true }, memory: { min_mb: 2048, max_mb: 6144 }, jvm_args: '', featured: true, source_label: 'Modrinth · Fabulously Optimized 6.2', file_count: 48, total_size: 184_000_000 },
|
||||||
{ id: 'creative', name: 'Creative Build', description: 'Plots, WorldEdit and weekly build contests.', icon_url: null, banner_url: null, mc_version: '1.20.1', loader: 'vanilla', loader_version: null, revision: 1, server: { name: 'Creative', address: 'creative.scopenet.gg', port: 25565, auto_join: false, inject: true }, memory: { min_mb: 1024, max_mb: 4096 }, jvm_args: '', featured: false, source_label: 'Minecraft 1.20.1', file_count: 0, total_size: 0 },
|
{ id: 'creative', name: 'Creative Build', description: 'Plots, WorldEdit and weekly build contests.', icon_url: null, banner_url: null, logo_url: null, mc_version: '1.20.1', loader: 'vanilla', loader_version: null, revision: 1, server: { name: 'Creative', address: 'creative.scopenet.gg', port: 25565, auto_join: false, inject: true }, memory: { min_mb: 1024, max_mb: 4096 }, jvm_args: '', featured: false, source_label: 'Minecraft 1.20.1', file_count: 0, total_size: 0 },
|
||||||
{ id: 'modded', name: 'Create: Above & Beyond', description: 'Factory building with Create and friends.', icon_url: null, banner_url: null, mc_version: '1.20.1', loader: 'forge', loader_version: '1.20.1-47.3.0', revision: 2, server: null, memory: { min_mb: 4096, max_mb: 8192 }, jvm_args: '', featured: false, source_label: 'CurseForge · Create: Above & Beyond 1.4', file_count: 212, total_size: 612_000_000 },
|
{ id: 'modded', name: 'Create: Above & Beyond', description: 'Factory building with Create and friends.', icon_url: null, banner_url: null, logo_url: null, mc_version: '1.20.1', loader: 'forge', loader_version: '1.20.1-47.3.0', revision: 2, server: null, memory: { min_mb: 4096, max_mb: 8192 }, jvm_args: '', featured: false, source_label: 'CurseForge · Create: Above & Beyond 1.4', file_count: 212, total_size: 612_000_000 },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export interface Instance {
|
|||||||
description: string;
|
description: string;
|
||||||
icon_url: string | null;
|
icon_url: string | null;
|
||||||
banner_url: string | null;
|
banner_url: string | null;
|
||||||
|
logo_url: string | null;
|
||||||
mc_version: string;
|
mc_version: string;
|
||||||
loader: Loader;
|
loader: Loader;
|
||||||
loader_version: string | null;
|
loader_version: string | null;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import ServerStatus from '../components/ServerStatus.svelte';
|
import ServerStatus from '../components/ServerStatus.svelte';
|
||||||
import NewsFeed from '../components/NewsFeed.svelte';
|
import NewsFeed from '../components/NewsFeed.svelte';
|
||||||
import Console from '../components/Console.svelte';
|
import Console from '../components/Console.svelte';
|
||||||
import { activeAccount, app, instances, selectedInstance } from '../lib/store.svelte';
|
import { abs, activeAccount, app, instances, selectedInstance } from '../lib/store.svelte';
|
||||||
import { loaderName, shortLoaderVersion } from '../lib/format';
|
import { loaderName, shortLoaderVersion } from '../lib/format';
|
||||||
import { openUrl } from '../lib/tauri';
|
import { openUrl } from '../lib/tauri';
|
||||||
|
|
||||||
@@ -26,7 +26,13 @@
|
|||||||
<span class="chip">{loaderName[inst.loader]} {shortLoaderVersion(inst.mc_version, inst.loader_version)}</span>
|
<span class="chip">{loaderName[inst.loader]} {shortLoaderVersion(inst.mc_version, inst.loader_version)}</span>
|
||||||
{#if inst.file_count}<span class="chip"><Package size={12} /> {inst.file_count} mods & files</span>{/if}
|
{#if inst.file_count}<span class="chip"><Package size={12} /> {inst.file_count} mods & files</span>{/if}
|
||||||
</div>
|
</div>
|
||||||
<h1>{inst.name}</h1>
|
{#if inst.logo_url}
|
||||||
|
<div class="logo-wrap">
|
||||||
|
<img class="inst-logo" src={abs(inst.logo_url)} alt={inst.name} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<h1>{inst.name}</h1>
|
||||||
|
{/if}
|
||||||
<p class="desc">{inst.description || b.tagline}</p>
|
<p class="desc">{inst.description || b.tagline}</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -67,6 +73,8 @@
|
|||||||
.greet { font-size: 0.88rem; }
|
.greet { font-size: 0.88rem; }
|
||||||
.greet strong { color: var(--text); font-weight: 560; }
|
.greet strong { color: var(--text); font-weight: 560; }
|
||||||
.chips { display: flex; gap: 0.45rem; flex-wrap: wrap; }
|
.chips { display: flex; gap: 0.45rem; flex-wrap: wrap; }
|
||||||
|
.logo-wrap { max-width: 100%; display: flex; align-items: flex-end; min-height: 3rem; margin: 0.25rem 0; }
|
||||||
|
.inst-logo { max-height: clamp(3.8rem, 8vw, 6.2rem); max-width: min(100%, 30rem); object-fit: contain; object-position: left bottom; filter: drop-shadow(0 4px 16px rgba(0, 0, 0, 0.5)); }
|
||||||
h1 { font-size: clamp(2.2rem, 4.4vw, 3.2rem); line-height: 1.05; font-weight: 700; letter-spacing: -0.025em; }
|
h1 { font-size: clamp(2.2rem, 4.4vw, 3.2rem); line-height: 1.05; font-weight: 700; letter-spacing: -0.025em; }
|
||||||
.desc { font-size: 0.95rem; line-height: 1.6; color: var(--muted); max-width: 32rem; }
|
.desc { font-size: 0.95rem; line-height: 1.6; color: var(--muted); max-width: 32rem; }
|
||||||
.actions { grid-column: 1; grid-row: 2; display: flex; flex-direction: column; gap: 0.8rem; animation: fade 0.3s ease both; }
|
.actions { grid-column: 1; grid-row: 2; display: flex; flex-direction: column; gap: 0.8rem; animation: fade 0.3s ease both; }
|
||||||
|
|||||||
@@ -215,6 +215,10 @@ const MIGRATIONS: &[&str] = &[
|
|||||||
WHEN NEW.uuid <> ''
|
WHEN NEW.uuid <> ''
|
||||||
BEGIN INSERT OR IGNORE INTO reserved_usernames VALUES (NEW.username, NEW.uuid); END;
|
BEGIN INSERT OR IGNORE INTO reserved_usernames VALUES (NEW.username, NEW.uuid); END;
|
||||||
"#,
|
"#,
|
||||||
|
// 5: instance logo url.
|
||||||
|
r#"
|
||||||
|
ALTER TABLE instances ADD COLUMN logo_url TEXT;
|
||||||
|
"#,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub async fn connect(data_dir: &Path) -> Result<SqlitePool> {
|
pub async fn connect(data_dir: &Path) -> Result<SqlitePool> {
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ pub struct InstanceInput {
|
|||||||
description: String,
|
description: String,
|
||||||
icon_url: Option<String>,
|
icon_url: Option<String>,
|
||||||
banner_url: Option<String>,
|
banner_url: Option<String>,
|
||||||
|
logo_url: Option<String>,
|
||||||
mc_version: String,
|
mc_version: String,
|
||||||
loader: Loader,
|
loader: Loader,
|
||||||
loader_version: Option<String>,
|
loader_version: Option<String>,
|
||||||
@@ -403,15 +404,16 @@ pub async fn create_instance(
|
|||||||
let now = crate::db::now();
|
let now = crate::db::now();
|
||||||
let mem = input.memory.unwrap_or_default();
|
let mem = input.memory.unwrap_or_default();
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
"INSERT INTO instances (id, name, description, icon_url, banner_url, mc_version, loader, loader_version, source_kind, source_label,
|
"INSERT INTO instances (id, name, description, icon_url, banner_url, logo_url, mc_version, loader, loader_version, source_kind, source_label,
|
||||||
visibility, allowed_groups, memory_min, memory_max, jvm_args, server, featured, enabled, sort, created_at, updated_at)
|
visibility, allowed_groups, memory_min, memory_max, jvm_args, server, featured, enabled, sort, created_at, updated_at)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'vanilla', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'vanilla', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
)
|
)
|
||||||
.bind(&id)
|
.bind(&id)
|
||||||
.bind(&input.name)
|
.bind(&input.name)
|
||||||
.bind(&input.description)
|
.bind(&input.description)
|
||||||
.bind(&input.icon_url)
|
.bind(&input.icon_url)
|
||||||
.bind(&input.banner_url)
|
.bind(&input.banner_url)
|
||||||
|
.bind(&input.logo_url)
|
||||||
.bind(&input.mc_version)
|
.bind(&input.mc_version)
|
||||||
.bind(input.loader.as_str())
|
.bind(input.loader.as_str())
|
||||||
.bind(&input.loader_version)
|
.bind(&input.loader_version)
|
||||||
@@ -461,7 +463,7 @@ pub async fn update_instance(
|
|||||||
// admin explicitly changes them here.
|
// admin explicitly changes them here.
|
||||||
let label = if existing.source_kind == "vanilla" { format!("Minecraft {}", input.mc_version) } else { existing.source_label.clone() };
|
let label = if existing.source_kind == "vanilla" { format!("Minecraft {}", input.mc_version) } else { existing.source_label.clone() };
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
"UPDATE instances SET name = ?, description = ?, icon_url = ?, banner_url = ?, mc_version = ?, loader = ?, loader_version = ?,
|
"UPDATE instances SET name = ?, description = ?, icon_url = ?, banner_url = ?, logo_url = ?, mc_version = ?, loader = ?, loader_version = ?,
|
||||||
source_label = ?, visibility = ?, allowed_groups = ?, memory_min = ?, memory_max = ?, jvm_args = ?, server = ?, featured = ?,
|
source_label = ?, visibility = ?, allowed_groups = ?, memory_min = ?, memory_max = ?, jvm_args = ?, server = ?, featured = ?,
|
||||||
enabled = ?, sort = ?, revision = revision + 1, updated_at = ? WHERE id = ?",
|
enabled = ?, sort = ?, revision = revision + 1, updated_at = ? WHERE id = ?",
|
||||||
)
|
)
|
||||||
@@ -469,6 +471,7 @@ pub async fn update_instance(
|
|||||||
.bind(&input.description)
|
.bind(&input.description)
|
||||||
.bind(input.icon_url.filter(|s| !s.is_empty()))
|
.bind(input.icon_url.filter(|s| !s.is_empty()))
|
||||||
.bind(input.banner_url.filter(|s| !s.is_empty()))
|
.bind(input.banner_url.filter(|s| !s.is_empty()))
|
||||||
|
.bind(input.logo_url.filter(|s| !s.is_empty()))
|
||||||
.bind(&input.mc_version)
|
.bind(&input.mc_version)
|
||||||
.bind(input.loader.as_str())
|
.bind(input.loader.as_str())
|
||||||
.bind(&input.loader_version)
|
.bind(&input.loader_version)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ pub struct InstanceRow {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub icon_url: Option<String>,
|
pub icon_url: Option<String>,
|
||||||
pub banner_url: Option<String>,
|
pub banner_url: Option<String>,
|
||||||
|
pub logo_url: Option<String>,
|
||||||
pub mc_version: String,
|
pub mc_version: String,
|
||||||
pub loader: String,
|
pub loader: String,
|
||||||
pub loader_version: Option<String>,
|
pub loader_version: Option<String>,
|
||||||
@@ -92,6 +93,7 @@ pub struct AdminInstance {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub icon_url: Option<String>,
|
pub icon_url: Option<String>,
|
||||||
pub banner_url: Option<String>,
|
pub banner_url: Option<String>,
|
||||||
|
pub logo_url: Option<String>,
|
||||||
pub mc_version: String,
|
pub mc_version: String,
|
||||||
pub loader: Loader,
|
pub loader: Loader,
|
||||||
pub loader_version: Option<String>,
|
pub loader_version: Option<String>,
|
||||||
@@ -123,6 +125,7 @@ impl InstanceRow {
|
|||||||
description: self.description.clone(),
|
description: self.description.clone(),
|
||||||
icon_url: self.icon_url.clone(),
|
icon_url: self.icon_url.clone(),
|
||||||
banner_url: self.banner_url.clone(),
|
banner_url: self.banner_url.clone(),
|
||||||
|
logo_url: self.logo_url.clone(),
|
||||||
mc_version: self.mc_version.clone(),
|
mc_version: self.mc_version.clone(),
|
||||||
loader: Loader::parse(&self.loader).unwrap_or_default(),
|
loader: Loader::parse(&self.loader).unwrap_or_default(),
|
||||||
loader_version: self.loader_version.clone(),
|
loader_version: self.loader_version.clone(),
|
||||||
@@ -154,6 +157,7 @@ impl InstanceRow {
|
|||||||
description: a.description,
|
description: a.description,
|
||||||
icon_url: a.icon_url,
|
icon_url: a.icon_url,
|
||||||
banner_url: a.banner_url,
|
banner_url: a.banner_url,
|
||||||
|
logo_url: a.logo_url,
|
||||||
mc_version: a.mc_version,
|
mc_version: a.mc_version,
|
||||||
loader: a.loader,
|
loader: a.loader,
|
||||||
loader_version: a.loader_version,
|
loader_version: a.loader_version,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import { Play, Settings } from '@lucide/svelte';
|
import { Play, Settings } from '@lucide/svelte';
|
||||||
import type { Branding } from '../lib/types';
|
import type { Branding } from '../lib/types';
|
||||||
|
|
||||||
let { b, instanceName = 'Survival SMP' }: { b: Branding; instanceName?: string } = $props();
|
let { b, instanceName = 'Survival SMP', instanceLogo = null }: { b: Branding; instanceName?: string; instanceLogo?: string | null } = $props();
|
||||||
|
|
||||||
const fontFamily = $derived(`'${b.font} Variable', '${b.font}', 'Inter Variable', sans-serif`);
|
const fontFamily = $derived(`'${b.font} Variable', '${b.font}', 'Inter Variable', sans-serif`);
|
||||||
const media = $derived(b.background.kind !== 'gradient' && b.background.url ? b.background.url : null);
|
const media = $derived(b.background.kind !== 'gradient' && b.background.url ? b.background.url : null);
|
||||||
@@ -53,7 +53,11 @@
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="hero">
|
<div class="hero">
|
||||||
<div class="chips"><span>1.21.1</span><span>Fabric</span></div>
|
<div class="chips"><span>1.21.1</span><span>Fabric</span></div>
|
||||||
<h1>{instanceName}</h1>
|
{#if instanceLogo}
|
||||||
|
<img class="hero-logo" src={instanceLogo} alt={instanceName} />
|
||||||
|
{:else}
|
||||||
|
<h1>{instanceName}</h1>
|
||||||
|
{/if}
|
||||||
<p>{b.tagline}</p>
|
<p>{b.tagline}</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="play"><Play size={9} fill="currentColor" /> Play</span>
|
<span class="play"><Play size={9} fill="currentColor" /> Play</span>
|
||||||
@@ -103,6 +107,7 @@
|
|||||||
.avatar { width: 55%; aspect-ratio: 1; border-radius: 25%; background: #3fb97c; }
|
.avatar { width: 55%; aspect-ratio: 1; border-radius: 25%; background: #3fb97c; }
|
||||||
.main { position: absolute; left: 6.2%; top: 5.6%; right: 0; bottom: 0; padding: 4% 4%; z-index: 1; display: flex; gap: 6%; }
|
.main { position: absolute; left: 6.2%; top: 5.6%; right: 0; bottom: 0; padding: 4% 4%; z-index: 1; display: flex; gap: 6%; }
|
||||||
.hero { flex: 1; align-self: flex-end; display: flex; flex-direction: column; gap: 0.6em; }
|
.hero { flex: 1; align-self: flex-end; display: flex; flex-direction: column; gap: 0.6em; }
|
||||||
|
.hero-logo { max-height: 2.8em; max-width: 80%; object-fit: contain; object-position: left bottom; }
|
||||||
.hero h1 { font-size: 3.1em; line-height: 1.05; margin: 0; letter-spacing: -0.025em; font-weight: 700; }
|
.hero h1 { font-size: 3.1em; line-height: 1.05; margin: 0; letter-spacing: -0.025em; font-weight: 700; }
|
||||||
.hero p { color: var(--mut); font-size: 0.95em; margin: 0; }
|
.hero p { color: var(--mut); font-size: 0.95em; margin: 0; }
|
||||||
.chips { display: flex; gap: 0.4em; }
|
.chips { display: flex; gap: 0.4em; }
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface Instance {
|
|||||||
description: string;
|
description: string;
|
||||||
icon_url: string | null;
|
icon_url: string | null;
|
||||||
banner_url: string | null;
|
banner_url: string | null;
|
||||||
|
logo_url: string | null;
|
||||||
mc_version: string;
|
mc_version: string;
|
||||||
loader: string;
|
loader: string;
|
||||||
loader_version: string | null;
|
loader_version: string | null;
|
||||||
|
|||||||
@@ -251,6 +251,7 @@
|
|||||||
<label class="field">Name<input bind:value={form.name} /></label>
|
<label class="field">Name<input bind:value={form.name} /></label>
|
||||||
<label class="field">Description<textarea bind:value={form.description} rows="3" placeholder="What makes this instance special?"></textarea></label>
|
<label class="field">Description<textarea bind:value={form.description} rows="3" placeholder="What makes this instance special?"></textarea></label>
|
||||||
<ImageInput bind:value={form.icon_url} label="Icon" help="Square image, shown in the launcher sidebar." />
|
<ImageInput bind:value={form.icon_url} label="Icon" help="Square image, shown in the launcher sidebar." />
|
||||||
|
<ImageInput bind:value={form.logo_url} label="Logo (optional)" help="Wide logo or wordmark image used in place of the instance title text." />
|
||||||
<ImageInput bind:value={form.banner_url} label="Banner / background" help="Wide image shown behind this instance. Overrides the launcher background." />
|
<ImageInput bind:value={form.banner_url} label="Banner / background" help="Wide image shown behind this instance. Overrides the launcher background." />
|
||||||
</section>
|
</section>
|
||||||
<section class="card col">
|
<section class="card col">
|
||||||
|
|||||||
Reference in new issue
Block a user