Compare commits

...

5 Commits

  1. 4
      src/App.vue
  2. 38
      src/components/TheWelcome.vue
  3. 166
      src/components/ui/BubbleContainer.vue
  4. 310
      src/views/AboutView.vue

4
src/App.vue

@ -9,8 +9,8 @@ import HelloWorld from './components/HelloWorld.vue' @@ -9,8 +9,8 @@ import HelloWorld from './components/HelloWorld.vue'
<HelloWorld msg="toonpets coming soon" />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
<RouterLink to="/">home</RouterLink>
<RouterLink to="/about">about</RouterLink>
</nav>
</div>
</header>

38
src/components/TheWelcome.vue

@ -12,10 +12,10 @@ import SupportIcon from './icons/IconSupport.vue' @@ -12,10 +12,10 @@ import SupportIcon from './icons/IconSupport.vue'
<template #icon>
<DocumentationIcon />
</template>
<template #heading>The Concept</template>
<template #heading>the concept</template>
Toon Pets is a virtual pet game for smartphones, built with Godot 4. Players care for a virtual
pet that lives inside a spherical enclosure on their device. The pet evolves based on what food
toon pets is a virtual pet game for smartphones, built with godot 4. players care for a virtual
pet that lives inside a spherical enclosure on their device. the pet evolves based on what food
it eats, developing a unique personality shaped by how it's been cared for.
</WelcomeItem>
@ -23,11 +23,11 @@ import SupportIcon from './icons/IconSupport.vue' @@ -23,11 +23,11 @@ import SupportIcon from './icons/IconSupport.vue'
<template #icon>
<EcosystemIcon />
</template>
<template #heading>The Sphere</template>
<template #heading>the sphere</template>
The game takes place inside a spherical enclosure the pet's private world contained within
your smartphone. The pet walks along the interior surface in a closed loop, creating a cozy,
intimate space. The sphere's appearance changes based on the pet's evolution, and customization
the game takes place inside a spherical enclosure the pet's private world contained within
your smartphone. the pet walks along the interior surface in a closed loop, creating a cozy,
intimate space. the sphere's appearance changes based on the pet's evolution, and customization
emerges through partnership: the pet curates options, and you choose from what they offer.
</WelcomeItem>
@ -35,11 +35,11 @@ import SupportIcon from './icons/IconSupport.vue' @@ -35,11 +35,11 @@ import SupportIcon from './icons/IconSupport.vue'
<template #icon>
<ToolingIcon />
</template>
<template #heading>Evolution</template>
<template #heading>evolution</template>
Feed your pet meat, fruit, or sweets to guide their evolution across three stages, resulting in
17 possible forms. Each evolution unlocks new weapon types for combat (up to 4 of 6 total) and
changes the sphere's visual environment. No single player can access everything working
feed your pet meat, fruit, or sweets to guide their evolution across three stages, resulting in
17 possible forms. each evolution unlocks new weapon types for combat (up to 4 of 6 total) and
changes the sphere's visual environment. no single player can access everything working
together with others fills in the gaps.
</WelcomeItem>
@ -47,11 +47,11 @@ import SupportIcon from './icons/IconSupport.vue' @@ -47,11 +47,11 @@ import SupportIcon from './icons/IconSupport.vue'
<template #icon>
<CommunityIcon />
</template>
<template #heading>Multiplayer & Social</template>
<template #heading>multiplayer & social</template>
Connect with nearby players automatically to battle enemies together in turn-based combat. Link
with friends so your pets remember each other across sessions. Send your pet to visit a friend's
sphere they'll return with stories, items, and a stronger bond. Two pets can even co-habitate
connect with nearby players automatically to battle enemies together in turn-based combat. link
with friends so your pets remember each other across sessions. send your pet to visit a friend's
sphere they'll return with stories, items, and a stronger bond. two pets can even co-habitate
temporarily, playing and napping together on your screen.
</WelcomeItem>
@ -59,11 +59,11 @@ import SupportIcon from './icons/IconSupport.vue' @@ -59,11 +59,11 @@ import SupportIcon from './icons/IconSupport.vue'
<template #icon>
<SupportIcon />
</template>
<template #heading>Wabi-Sabi Philosophy</template>
<template #heading>wabi-sabi philosophy</template>
Toon Pets embraces imperfection and transience. Your pet's "suboptimal" evolution path isn't
worse it's yours, shaped by your choices. Visits end, moments are fleeting, and no player
collects everything. The game finds beauty in incompleteness, with lived-in spaces that feel
toon pets embraces imperfection and transience. your pet's "suboptimal" evolution path isn't
worse it's yours, shaped by your choices. visits end, moments are fleeting, and no player
collects everything. the game finds beauty in incompleteness, with lived-in spaces that feel
grown rather than constructed.
</WelcomeItem>
</template>

166
src/components/ui/BubbleContainer.vue

@ -0,0 +1,166 @@ @@ -0,0 +1,166 @@
<script setup lang="ts">
interface Props {
padding?: 'sm' | 'md' | 'lg' | 'xl'
variant?: 'default' | 'subtle' | 'prominent'
}
withDefaults(defineProps<Props>(), {
padding: 'md',
variant: 'default'
})
</script>
<template>
<div :class="['bubble-container', `bubble-container--${padding}`, `bubble-container--${variant}`]">
<slot />
</div>
</template>
<style scoped>
.bubble-container {
/* Base structure */
position: relative;
border-radius: 1.25rem;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
/* Light mode base */
background: radial-gradient(
circle at 30% 30%,
rgba(255, 255, 255, 0.25),
rgba(255, 255, 255, 0.08)
);
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.4),
inset 0 -1px 0 rgba(0, 0, 0, 0.05);
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
.bubble-container {
background: radial-gradient(
circle at 30% 30%,
rgba(255, 255, 255, 0.12),
rgba(255, 255, 255, 0.03)
);
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.15),
inset 0 -1px 0 rgba(0, 0, 0, 0.2);
}
}
/* Padding variants */
.bubble-container--sm {
padding: 0.75rem;
}
.bubble-container--md {
padding: 1.25rem;
}
.bubble-container--lg {
padding: 2rem;
}
.bubble-container--xl {
padding: 3rem;
}
/* Style variants */
.bubble-container--subtle {
/* Light mode subtle */
background: radial-gradient(
circle at 30% 30%,
rgba(255, 255, 255, 0.15),
rgba(255, 255, 255, 0.05)
);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow:
0 4px 16px rgba(0, 0, 0, 0.05),
inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
@media (prefers-color-scheme: dark) {
.bubble-container--subtle {
background: radial-gradient(
circle at 30% 30%,
rgba(255, 255, 255, 0.08),
rgba(255, 255, 255, 0.02)
);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 4px 16px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
}
.bubble-container--prominent {
/* Light mode prominent */
background: radial-gradient(
circle at 30% 30%,
rgba(255, 255, 255, 0.35),
rgba(255, 255, 255, 0.12)
);
border: 1px solid rgba(255, 255, 255, 0.4);
box-shadow:
0 12px 48px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.5),
inset 0 -1px 0 rgba(0, 0, 0, 0.08);
}
@media (prefers-color-scheme: dark) {
.bubble-container--prominent {
background: radial-gradient(
circle at 30% 30%,
rgba(255, 255, 255, 0.18),
rgba(255, 255, 255, 0.05)
);
border: 1px solid rgba(255, 255, 255, 0.25);
box-shadow:
0 12px 48px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.2),
inset 0 -1px 0 rgba(0, 0, 0, 0.3);
}
}
/* Hover effects */
.bubble-container {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.bubble-container:hover {
transform: translateY(-2px);
box-shadow:
0 12px 40px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.5),
inset 0 -1px 0 rgba(0, 0, 0, 0.08);
}
@media (prefers-color-scheme: dark) {
.bubble-container:hover {
box-shadow:
0 12px 40px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.2),
inset 0 -1px 0 rgba(0, 0, 0, 0.25);
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.bubble-container {
border-radius: 1rem;
}
.bubble-container--lg {
padding: 1.5rem;
}
.bubble-container--xl {
padding: 2rem;
}
}
</style>

310
src/views/AboutView.vue

@ -1,15 +1,315 @@ @@ -1,15 +1,315 @@
<script setup lang="ts">
import BubbleContainer from '../components/ui/BubbleContainer.vue'
</script>
<template>
<div class="about">
<h1>This is an about page</h1>
<div class="about-content">
<h1 class="page-title">Component Library</h1>
<p class="page-subtitle">Experimenting with reusable UI components</p>
<div class="component-showcase">
<section class="showcase-section">
<h2>Bubble Container</h2>
<p class="section-description">
A versatile container component with glassmorphism design, featuring transparency,
rounded borders, and automatic light/dark mode support.
</p>
<div class="examples-grid">
<div class="example">
<h3>Default</h3>
<BubbleContainer>
<h4>Standard Container</h4>
<p>This is the default bubble container with medium padding and standard transparency.</p>
<div class="demo-content">
<span class="demo-tag">Feature 1</span>
<span class="demo-tag">Feature 2</span>
</div>
</BubbleContainer>
</div>
<div class="example">
<h3>Subtle Variant</h3>
<BubbleContainer variant="subtle" padding="lg">
<h4>Subtle Style</h4>
<p>Less prominent with reduced opacity and softer shadows for background elements.</p>
<div class="demo-list">
<div class="demo-item"> Reduced opacity</div>
<div class="demo-item"> Softer shadows</div>
<div class="demo-item"> Large padding</div>
</div>
</BubbleContainer>
</div>
<div class="example">
<h3>Prominent Variant</h3>
<BubbleContainer variant="prominent" padding="xl">
<h4>Prominent Style</h4>
<p>Enhanced visibility with stronger borders and more pronounced shadows.</p>
<div class="demo-stats">
<div class="stat">
<div class="stat-number">95%</div>
<div class="stat-label">Transparency</div>
</div>
<div class="stat">
<div class="stat-number">10px</div>
<div class="stat-label">Blur Effect</div>
</div>
</div>
</BubbleContainer>
</div>
<div class="example">
<h3>Small Padding</h3>
<BubbleContainer padding="sm">
<h4>Compact Content</h4>
<p>Perfect for smaller UI elements and tight layouts.</p>
</BubbleContainer>
</div>
<div class="example full-width">
<h3>Nested Containers</h3>
<BubbleContainer padding="lg">
<h4>Parent Container</h4>
<p>Containers can be nested for complex layouts:</p>
<div class="nested-demo">
<BubbleContainer variant="subtle" padding="md">
<strong>Nested Child</strong>
<p>This creates interesting depth effects with multiple layers of transparency.</p>
</BubbleContainer>
</div>
</BubbleContainer>
</div>
</div>
</section>
<section class="showcase-section">
<BubbleContainer variant="prominent" padding="lg">
<h2>Usage Notes</h2>
<div class="usage-grid">
<div class="usage-item">
<h4>Responsive Design</h4>
<p>Automatically adjusts border radius and padding on mobile devices.</p>
</div>
<div class="usage-item">
<h4>Theme Support</h4>
<p>Seamlessly switches between light and dark modes using CSS media queries.</p>
</div>
<div class="usage-item">
<h4>Performance</h4>
<p>Uses backdrop-filter for efficient blur effects with hardware acceleration.</p>
</div>
<div class="usage-item">
<h4>Accessibility</h4>
<p>Maintains proper contrast ratios in both light and dark themes.</p>
</div>
</div>
</BubbleContainer>
</section>
</div>
</div>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
<style scoped>
.about {
min-height: 100vh;
padding: 2rem 0;
}
.about-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
.page-title {
font-size: 3rem;
font-weight: 600;
text-align: center;
margin-bottom: 1rem;
background: linear-gradient(135deg, var(--color-heading), var(--color-text));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.page-subtitle {
font-size: 1.25rem;
text-align: center;
color: var(--color-text);
opacity: 0.8;
margin-bottom: 3rem;
}
.component-showcase {
display: flex;
flex-direction: column;
gap: 3rem;
}
.showcase-section {
display: flex;
flex-direction: column;
gap: 2rem;
}
.showcase-section > h2 {
font-size: 2rem;
font-weight: 500;
color: var(--color-heading);
margin-bottom: 0.5rem;
}
.section-description {
font-size: 1.1rem;
line-height: 1.6;
color: var(--color-text);
opacity: 0.9;
margin-bottom: 1rem;
}
.examples-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
align-items: start;
}
.example {
display: flex;
flex-direction: column;
gap: 1rem;
}
.example.full-width {
grid-column: 1 / -1;
}
.example > h3 {
font-size: 1.25rem;
font-weight: 500;
color: var(--color-heading);
margin-bottom: 0.5rem;
}
.example h4 {
font-size: 1.1rem;
font-weight: 500;
color: var(--color-heading);
margin-bottom: 0.75rem;
}
.example p {
line-height: 1.6;
margin-bottom: 1rem;
}
.demo-content {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.demo-tag {
background: rgba(var(--vt-c-indigo), 0.1);
color: var(--color-heading);
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.875rem;
border: 1px solid rgba(var(--vt-c-indigo), 0.2);
}
.demo-list {
display: flex;
align-items: center;
flex-direction: column;
gap: 0.5rem;
}
.demo-item {
font-size: 0.9rem;
opacity: 0.9;
}
.demo-stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-top: 1rem;
}
.stat {
text-align: center;
}
.stat-number {
font-size: 1.5rem;
font-weight: 600;
color: var(--color-heading);
}
.stat-label {
font-size: 0.875rem;
opacity: 0.8;
}
.nested-demo {
margin-top: 1rem;
}
.usage-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-top: 1rem;
}
.usage-item h4 {
font-size: 1rem;
font-weight: 500;
color: var(--color-heading);
margin-bottom: 0.5rem;
}
.usage-item p {
font-size: 0.9rem;
line-height: 1.5;
margin: 0;
opacity: 0.9;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.about-content {
padding: 0 0.5rem;
}
.page-title {
font-size: 2.5rem;
}
.examples-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.demo-stats {
grid-template-columns: 1fr;
}
.usage-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.page-title {
font-size: 2rem;
}
.page-subtitle {
font-size: 1.1rem;
}
}
</style>
Loading…
Cancel
Save