Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 5 additions & 28 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ export default defineConfig({
{
icon: "github",
label: "GitHub (App)",
href: "https://github.com/Fancy-Mumble/FancyMumbleNext",
href: "https://github.com/Fancy-Mumble/FancyMumble",
},
{
icon: "github",
label: "GitHub (Server)",
href: "https://github.com/Fancy-Mumble/mumble-server",
label: "GitHub (Starling server)",
href: "https://github.com/Fancy-Mumble/starling",
},
],
editLink: {
Expand Down Expand Up @@ -168,33 +168,10 @@ export default defineConfig({
badge: { text: "Ops", variant: "note" },
items: [
{ label: "Docker quick start", link: "/server/docker/" },
{ label: "Setup wizard", link: "/server/wizard/" },
{ label: "First-run setup", link: "/server/wizard/" },
{ label: "Configuration reference", link: "/server/config/" },
{ label: "Ports & networking", link: "/server/network/" },
{
label: "Feature deep-dives",
collapsed: false,
items: [
{ label: "Persistent chat", link: "/server/features/persistent-chat/" },
{ label: "Push notifications", link: "/server/features/push/" },
{ label: "Screen sharing relay", link: "/server/features/webrtc-sfu/" },
{ label: "File server", link: "/server/features/file-server/" },
{ label: "Link previews", link: "/server/features/link-previews/" },
{ label: "Reactions & polls", link: "/server/features/reactions/" },
{ label: "Watch Together", link: "/server/features/watch-together/" },
{ label: "Whiteboard", link: "/server/features/whiteboard/" },
{ label: "Live documents", link: "/server/features/live-doc/" },
],
},
{
label: "Plugins",
collapsed: false,
items: [
{ label: "Plugin system overview", link: "/server/plugins/overview/" },
{ label: "Using plugins", link: "/server/plugins/using/" },
{ label: "Developing a plugin", link: "/server/plugins/developing/" },
],
},
{ label: "Feature availability", link: "/server/features/" },
{ label: "Customize & disable features", link: "/server/customize/" },
{ label: "Building from source", link: "/server/build/" },
{ label: "Upgrade & backup", link: "/server/upgrade/" },
Expand Down
Binary file added public/examples/avatars/anime-demon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/anime-girl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/anime-pastel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/car-enthusiast.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/comics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/dog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/flowers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/k-pop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/avatars/manga-reader.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/anime-demon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/anime-pastel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/anime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/cars.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/cats.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/comics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/dogs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/flowers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/k-pop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/banners/manga.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
135 changes: 135 additions & 0 deletions public/examples/community-scene.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Fancy Mumble sample community scene</title>
<style>
:root { color-scheme: dark; font-family: Inter, "Segoe UI", sans-serif; }
* { box-sizing: border-box; }
body { margin: 0; background: #10121c; color: #f5f6fb; }
.app { width: 1280px; height: 720px; overflow: hidden; margin: 0 auto; background: #151929; }
.titlebar { height: 44px; display: flex; align-items: center; gap: 10px; padding: 0 20px; background: #11141f; border-bottom: 1px solid #252b3e; font-size: 14px; font-weight: 700; }
.logo { display: grid; place-items: center; width: 25px; height: 25px; border-radius: 9px; background: linear-gradient(135deg, #6c96d6, #7152a3); font-size: 13px; }
.titlebar .section { margin-left: 23px; padding-left: 20px; border-left: 1px solid #34394c; color: #b9c5df; font-weight: 500; }
.window-actions { margin-left: auto; color: #77839c; letter-spacing: 16px; font-size: 18px; }
.columns { display: grid; grid-template-columns: 275px 665px 340px; height: 676px; }
aside { padding: 20px 14px; background: #1a2032; border-right: 1px solid #2b344b; }
.search { padding: 10px 13px; color: #8793aa; background: #242b3e; border: 1px solid #303a52; border-radius: 10px; font-size: 13px; }
.section-label { margin: 24px 8px 12px; color: #8996b2; font-size: 10px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase; }
.channel { padding: 12px; border: 1px solid #4f78b7; border-radius: 12px; background: #263755; font-size: 14px; font-weight: 700; }
.channel small { display: block; margin-top: 4px; color: #b5c8eb; font-size: 11px; font-weight: 400; }
.member { display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 8px; border: 0; border-radius: 9px; background: transparent; color: inherit; text-align: left; cursor: pointer; }
.member:hover, .member.is-selected { background: #293750; }
.member:focus-visible { outline: 2px solid #8ab8ff; outline-offset: 2px; }
.member img, .message img { width: 34px; height: 34px; flex: none; border-radius: 50%; object-fit: cover; }
.member span { font-size: 12px; font-weight: 650; }
.member small { display: block; margin-top: 3px; color: #8b9ab5; font-size: 10px; font-weight: 400; }
.online { width: 7px; height: 7px; margin-left: auto; border-radius: 50%; background: #5bd9a1; }
main { position: relative; background: linear-gradient(#171a2bd9, #171a2be0), url('/examples/sample-chat-background.png') center / cover; }
.chat-header { height: 76px; padding: 15px 25px; border-bottom: 1px solid #2a3349; }
.chat-header h1 { margin: 0 0 4px; font-size: 21px; }
.chat-header p { margin: 0; color: #9cacc5; font-size: 12px; }
.topic { margin: 20px 24px 15px; padding: 10px 14px; border: 1px solid #385d8c; border-radius: 10px; background: #1b2b45; color: #b8d0f5; font-size: 12px; }
.date { margin: 0 24px 12px; color: #8390aa; font-size: 11px; text-align: center; }
.messages { padding: 0 24px; }
.message { display: flex; gap: 12px; margin-bottom: 16px; }
.message-head { display: flex; align-items: baseline; gap: 9px; }
.message strong { font-size: 13px; }
.message time { color: #7d8ba5; font-size: 10px; }
.message p { margin: 4px 0 0; color: #dce3f1; font-size: 13px; line-height: 1.45; }
.tag { padding: 2px 6px; border-radius: 5px; background: #33415d; color: #c3d1ec; font-size: 9px; font-weight: 700; text-transform: uppercase; }
.reactions { display: flex; gap: 5px; margin-top: 7px; }
.reactions span { padding: 4px 8px; border: 1px solid #3c4b6a; border-radius: 7px; background: #263149; color: #cbd8f5; font-size: 11px; }
.composer { position: absolute; right: 15px; bottom: 15px; left: 15px; display: flex; align-items: center; gap: 12px; height: 48px; padding: 0 15px; border: 1px solid #354363; border-radius: 13px; background: #26324f; color: #98a6c0; font-size: 13px; }
.composer .send { display: grid; place-items: center; width: 29px; height: 29px; margin-left: auto; border-radius: 50%; background: #3a77c4; color: white; font-size: 16px; }
.right { padding: 20px 18px; background: #1a1f31; border-left: 1px solid #2b344b; }
.right-heading { display: flex; justify-content: space-between; align-items: center; margin: 1px 0 16px; font-size: 14px; font-weight: 750; }
.right-heading span { color: #8793af; font-size: 18px; }
.profile { overflow: hidden; border: 1px solid #3a4765; border-radius: 14px; background: #20283c; }
.banner { height: 102px; background: url('/examples/banners/anime.png') center 50% / cover; }
.profile-body { padding: 0 15px 18px; }
.profile-avatar { width: 68px; height: 68px; margin-top: -30px; border: 4px solid #20283c; border-radius: 50%; object-fit: cover; }
.profile h2 { margin: 5px 0 4px; font-size: 18px; }
.profile .handle { color: #a7b7d0; font-size: 11px; }
.profile .role { display: inline-block; margin: 13px 0 8px; padding: 4px 8px; border: 1px solid #745cb5; border-radius: 6px; background: #46395f; color: #dac8ff; font-size: 10px; font-weight: 750; }
.profile p { margin: 3px 0 0; color: #dae3f2; font-size: 12px; line-height: 1.5; }
.profile .status { padding-top: 14px; color: #9eb4d8; font-size: 11px; }
.hint { margin: 16px 3px 0; color: #8794b0; font-size: 11px; line-height: 1.5; }
</style>
</head>
<body>
<div class="app">
<div class="titlebar"><span class="logo">F</span> Fancy Mumble <span class="section">Community voice</span><span class="window-actions">− □ ×</span></div>
<div class="columns">
<aside>
<div class="search">⌕ &nbsp; Search channels and members</div>
<div class="section-label">Channels</div>
<div class="channel"># &nbsp; lounge <small>General conversation · 5 members</small></div>
<div class="section-label">In this channel</div>
<button class="member is-selected" type="button" data-person="rin" aria-pressed="true"><img src="/examples/avatars/anime-girl.png" alt="" /><div><span>Rin</span><small>Drawing tonight</small></div><i class="online"></i></button>
<button class="member" type="button" data-person="torque" aria-pressed="false"><img src="/examples/avatars/car-enthusiast.png" alt="" /><div><span>Torque</span><small>Car club</small></div><i class="online"></i></button>
<button class="member" type="button" data-person="hana" aria-pressed="false"><img src="/examples/avatars/k-pop.png" alt="" /><div><span>Hana</span><small>Playlist curator</small></div><i class="online"></i></button>
<button class="member" type="button" data-person="flora" aria-pressed="false"><img src="/examples/avatars/flowers.png" alt="" /><div><span>Flora</span><small>Garden updates</small></div><i class="online"></i></button>
<button class="member" type="button" data-person="scout" aria-pressed="false"><img src="/examples/avatars/dog.png" alt="" /><div><span>Scout</span><small>Walk break</small></div><i class="online"></i></button>
</aside>
<main>
<div class="chat-header"><h1># lounge</h1><p>Five members · Share what you're working on</p></div>
<div class="topic">✦ &nbsp; Welcome to the community lounge. Say hello and share your interests.</div>
<div class="date">Today</div>
<div class="messages">
<div class="message"><img src="/examples/avatars/car-enthusiast.png" alt="" /><div><div class="message-head"><strong>Torque</strong><span class="tag">Car club</span><time>19:42</time></div><p>Just finished the night drive. That coastal road was incredible.</p><div class="reactions"><span>🏁 3</span><span>✨ 2</span></div></div></div>
<div class="message"><img src="/examples/avatars/anime-girl.png" alt="" /><div><div class="message-head"><strong>Rin</strong><span class="tag">Artist</span><time>19:44</time></div><p>That sounds like a perfect reference for my next illustration!</p></div></div>
<div class="message"><img src="/examples/avatars/k-pop.png" alt="" /><div><div class="message-head"><strong>Hana</strong><span class="tag">Music</span><time>19:46</time></div><p>I made a playlist for tonight's sketch session. 🎵</p></div></div>
<div class="message"><img src="/examples/avatars/flowers.png" alt="" /><div><div class="message-head"><strong>Flora</strong><span class="tag">Gardener</span><time>19:49</time></div><p>I'll bring the flower references. My roses are finally blooming.</p><div class="reactions"><span>🌸 4</span></div></div></div>
</div>
<div class="composer">+ &nbsp; Write a message… <span class="send">➤</span></div>
</main>
<div class="right">
<div class="right-heading">Member profile <span>×</span></div>
<div class="profile">
<div class="banner" data-banner role="img" aria-label="Rin's vivid anime banner"></div>
<div class="profile-body">
<img class="profile-avatar" data-profile-avatar src="/examples/avatars/anime-girl.png" alt="Rin's avatar" />
<h2 data-profile-name>Rin</h2>
<div class="handle" data-profile-handle>@rin · Online</div>
<div class="role" data-profile-role>Artist</div>
<p data-profile-bio>Illustrating imaginary places, collecting color palettes, and meeting friends in voice chat.</p>
<div class="status" data-profile-status>✦ &nbsp; Sketchbook open · Listening to Hana's playlist</div>
</div>
</div>
<p class="hint">Select a member to see their avatar, banner, bio, and status.</p>
</div>
</div>
</div>
<script>
const profiles = {
rin: { name: 'Rin', avatar: '/examples/avatars/anime-girl.png', banner: '/examples/banners/anime.png', role: 'Artist', bio: 'Illustrating imaginary places, collecting color palettes, and meeting friends in voice chat.', status: 'Sketchbook open · Listening to Hana’s playlist' },
torque: { name: 'Torque', avatar: '/examples/avatars/car-enthusiast.png', banner: '/examples/banners/cars.png', role: 'Car club', bio: 'Weekend drives, winding roads, and photos of every interesting car I find.', status: 'Back from the coastal drive' },
hana: { name: 'Hana', avatar: '/examples/avatars/k-pop.png', banner: '/examples/banners/k-pop.png', role: 'Music', bio: 'Making playlists for every mood and sharing new stage performances with friends.', status: 'Tonight’s playlist is live' },
flora: { name: 'Flora', avatar: '/examples/avatars/flowers.png', banner: '/examples/banners/flowers.png', role: 'Gardener', bio: 'Growing roses and sharing the best colors from the garden.', status: 'Roses are blooming' },
scout: { name: 'Scout', avatar: '/examples/avatars/dog.png', banner: '/examples/banners/dogs.png', role: 'Dog lover', bio: 'Always ready for a walk, a photo, or a friendly voice chat.', status: 'Taking a walk break' },
};
const buttons = document.querySelectorAll('[data-person]');
buttons.forEach((button) => button.addEventListener('click', () => {
const profile = profiles[button.dataset.person];
if (!profile) return;
buttons.forEach((other) => {
other.classList.toggle('is-selected', other === button);
other.setAttribute('aria-pressed', String(other === button));
});
const banner = document.querySelector('[data-banner]');
banner.style.backgroundImage = `url("${profile.banner}")`;
banner.setAttribute('aria-label', `${profile.name}'s banner`);
const avatar = document.querySelector('[data-profile-avatar]');
avatar.src = profile.avatar;
avatar.alt = `${profile.name}'s avatar`;
document.querySelector('[data-profile-name]').textContent = profile.name;
document.querySelector('[data-profile-handle]').textContent = `@${profile.name.toLowerCase()} · Online`;
document.querySelector('[data-profile-role]').textContent = profile.role;
document.querySelector('[data-profile-bio]').textContent = profile.bio;
document.querySelector('[data-profile-status]').textContent = `✦ ${profile.status}`;
}));
</script>
</body>
</html>
Binary file added public/examples/sample-avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/sample-chat-background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/examples/sample-profile-banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/mainpage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/screenshot-getting-started-connect-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/screenshot-getting-started-connect-2.png
Binary file modified public/screenshot-getting-started-install-2.png
Binary file added public/screenshot-users-chat-community.png
40 changes: 40 additions & 0 deletions src/components/ChatBackgroundExample.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<figure class="example">
<div class="chat-preview" aria-label="Illustrative chat preview using the sample background with a dark overlay">
<img class="wallpaper" src="/examples/sample-chat-background.png" alt="" loading="lazy" />
<div class="dim" aria-hidden="true"></div>
<div class="chat-content">
<div class="channel"># lounge</div>
<div class="message"><strong>Sam</strong><span>Ready to join the call?</span></div>
<div class="message"><strong>Alex</strong><span>Yep, I can see the lake behind our chat.</span></div>
<div class="composer">Write a message…</div>
</div>
</div>
<figcaption>Illustrative preview with the sample wallpaper, a dark overlay, and readable messages.</figcaption>
</figure>

<style>
.example { margin: 1.5rem 0; }
.chat-preview {
position: relative;
isolation: isolate;
display: flex;
min-height: 350px;
max-width: 720px;
overflow: hidden;
border: 1px solid #43506f;
border-radius: 16px;
background: #11182b;
color: #f3f6ff;
box-shadow: 0 12px 28px #080d1d40;
}
.wallpaper, .dim { position: absolute; inset: 0; width: 100%; height: 100%; }
.wallpaper { object-fit: cover; }
.dim { background: #07112688; }
.chat-content { position: relative; display: flex; flex: 1; flex-direction: column; gap: .65rem; padding: 1rem; }
.channel { font-weight: 700; border-bottom: 1px solid #d7e4ff44; padding-bottom: .65rem; }
.message { display: grid; gap: .15rem; width: fit-content; max-width: 90%; padding: .55rem .8rem; border-radius: 10px; background: #141e35dd; box-shadow: 0 3px 8px #0005; }
.message strong { color: #a7c7ff; font-size: .85rem; }
.message span { font-size: .9rem; }
.composer { margin-top: auto; padding: .6rem .8rem; border: 1px solid #d7e4ff55; border-radius: 10px; background: #121a2edd; color: #c8d1e5; font-size: .85rem; }
figcaption { margin-top: .55rem; color: var(--sl-color-text-accent); font-size: .82rem; }
</style>
Loading
Loading