✨ New landing page
This commit is contained in:
10
app/components.d.ts
vendored
10
app/components.d.ts
vendored
@@ -13,8 +13,13 @@ export {}
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
NAvatar: typeof import('naive-ui')['NAvatar']
|
NAvatar: typeof import('naive-ui')['NAvatar']
|
||||||
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||||
|
NIcon: typeof import('naive-ui')['NIcon']
|
||||||
NMenu: typeof import('naive-ui')['NMenu']
|
NMenu: typeof import('naive-ui')['NMenu']
|
||||||
|
NPopover: typeof import('naive-ui')['NPopover']
|
||||||
|
NTag: typeof import('naive-ui')['NTag']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
}
|
}
|
||||||
@@ -23,8 +28,13 @@ declare module 'vue' {
|
|||||||
// For TSX support
|
// For TSX support
|
||||||
declare global {
|
declare global {
|
||||||
const NAvatar: typeof import('naive-ui')['NAvatar']
|
const NAvatar: typeof import('naive-ui')['NAvatar']
|
||||||
|
const NButton: typeof import('naive-ui')['NButton']
|
||||||
|
const NCard: typeof import('naive-ui')['NCard']
|
||||||
const NDropdown: typeof import('naive-ui')['NDropdown']
|
const NDropdown: typeof import('naive-ui')['NDropdown']
|
||||||
|
const NIcon: typeof import('naive-ui')['NIcon']
|
||||||
const NMenu: typeof import('naive-ui')['NMenu']
|
const NMenu: typeof import('naive-ui')['NMenu']
|
||||||
|
const NPopover: typeof import('naive-ui')['NPopover']
|
||||||
|
const NTag: typeof import('naive-ui')['NTag']
|
||||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
const RouterView: typeof import('vue-router')['RouterView']
|
const RouterView: typeof import('vue-router')['RouterView']
|
||||||
}
|
}
|
||||||
@@ -4,23 +4,35 @@
|
|||||||
class="navbar bg-transparent shadow-lg fixed top-0 left-0 right-0 backdrop-blur-2xl z-1000 h-[64px]"
|
class="navbar bg-transparent shadow-lg fixed top-0 left-0 right-0 backdrop-blur-2xl z-1000 h-[64px]"
|
||||||
>
|
>
|
||||||
<div class="container mx-auto flex items-center justify-between px-5">
|
<div class="container mx-auto flex items-center justify-between px-5">
|
||||||
<div class="flex gap-2 items-center">
|
<nuxt-link to="/">
|
||||||
<router-link to="/">
|
<nuxt-img src="/favicon.png" alt="Solsynth" class="w-8 h-8" />
|
||||||
<nuxt-img src="/favicon.png" alt="Solsynth" class="w-10 h-8" />
|
</nuxt-link>
|
||||||
</router-link>
|
|
||||||
|
|
||||||
<n-menu
|
<n-menu
|
||||||
|
v-if="breakpoints.isGreaterOrEqual('md')"
|
||||||
v-model:value="activeKey"
|
v-model:value="activeKey"
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
:options="menuOptions"
|
:options="menuOptions"
|
||||||
|
style="width: auto"
|
||||||
/>
|
/>
|
||||||
</div>
|
<n-popover v-else trigger="hover">
|
||||||
|
<template #trigger>
|
||||||
|
<n-button text>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :component="MenuOutlined" />
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<n-menu
|
||||||
|
v-model:value="activeKey"
|
||||||
|
mode="vertical"
|
||||||
|
:options="menuOptions"
|
||||||
|
class="w-64"
|
||||||
|
style="height: auto"
|
||||||
|
/>
|
||||||
|
</n-popover>
|
||||||
|
|
||||||
<n-dropdown :options="dropdownOptions" @select="handleDropdownSelect">
|
<naive-color-mode-switch />
|
||||||
<n-avatar :size="32">
|
|
||||||
<n-icon :component="PersonIcon" :size="20" />
|
|
||||||
</n-avatar>
|
|
||||||
</n-dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -33,43 +45,40 @@
|
|||||||
>
|
>
|
||||||
<aside>
|
<aside>
|
||||||
<nuxt-img src="/favicon.png" alt="Solsynth" class="w-12 h-12" />
|
<nuxt-img src="/favicon.png" alt="Solsynth" class="w-12 h-12" />
|
||||||
<p>
|
<div>
|
||||||
Solsynth
|
<h3 class="text-lg font-bold">Solsynth</h3>
|
||||||
<br />
|
|
||||||
Making software, hardware and experiences since 2024
|
Making software, hardware and experiences since 2024
|
||||||
</p>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
<nav>
|
<nav>
|
||||||
<h6 class="footer-title">Products</h6>
|
<h6 class="footer-title">Products</h6>
|
||||||
<router-link to="/products" class="link link-hover"
|
<a href="https://solian.app" target="_blank" class="link link-hover"
|
||||||
>Our Products</router-link
|
>Solar Network</a
|
||||||
>
|
>
|
||||||
<router-link to="/#about" class="link link-hover">About Us</router-link>
|
<nuxt-link to="/products" class="link link-hover">Catalog</nuxt-link>
|
||||||
</nav>
|
</nav>
|
||||||
<nav>
|
<nav>
|
||||||
<h6 class="footer-title">Company</h6>
|
<h6 class="footer-title">Company</h6>
|
||||||
|
<nuxt-link to="/about" class="link link-hover">About us</nuxt-link>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/Solsynth"
|
href="https://github.com/Solsynth"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="link link-hover"
|
class="link link-hover"
|
||||||
>GitHub</a
|
>GitHub</a
|
||||||
>
|
>
|
||||||
<router-link to="/#about" class="link link-hover">Team</router-link>
|
|
||||||
</nav>
|
</nav>
|
||||||
<nav>
|
<nav>
|
||||||
<h6 class="footer-title">Legal</h6>
|
<h6 class="footer-title">Legal</h6>
|
||||||
<router-link to="/terms/user-agreement" class="link link-hover"
|
<nuxt-link to="/terms/user-agreement" class="link link-hover"
|
||||||
>Terms of Service</router-link
|
>Terms of Service</nuxt-link
|
||||||
>
|
>
|
||||||
<router-link to="/terms/privacy-policy" class="link link-hover"
|
<nuxt-link to="/terms/privacy-policy" class="link link-hover"
|
||||||
>Privacy Policy</router-link
|
>Privacy Policy</nuxt-link
|
||||||
>
|
>
|
||||||
<router-link to="/terms/refund-policy" class="link link-hover"
|
<nuxt-link to="/terms/refund-policy" class="link link-hover"
|
||||||
>Refund Policy</router-link
|
>Refund Policy</nuxt-link
|
||||||
>
|
|
||||||
<router-link to="/terms" class="link link-hover"
|
|
||||||
>All Documents</router-link
|
|
||||||
>
|
>
|
||||||
|
<nuxt-link to="/terms" class="link link-hover">All Documents</nuxt-link>
|
||||||
</nav>
|
</nav>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,25 +86,27 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { MenuOption } from "naive-ui";
|
import type { MenuOption } from "naive-ui";
|
||||||
import { NIcon, NAvatar, NMenu, NDropdown } from "naive-ui";
|
import { NIcon, NAvatar, NMenu } from "naive-ui";
|
||||||
import { computed, h } from "vue";
|
import { computed, h } from "vue";
|
||||||
import { useRouter, useRoute, RouterLink } from "vue-router";
|
import { useRoute, RouterLink } from "vue-router";
|
||||||
import {
|
import {
|
||||||
ExploreOutlined,
|
ExploreOutlined,
|
||||||
DashboardOutlined,
|
CategoryOutlined,
|
||||||
LogInOutlined,
|
MenuOutlined,
|
||||||
PersonAddOutlined,
|
|
||||||
PersonOutlined,
|
|
||||||
} from "@vicons/material";
|
} from "@vicons/material";
|
||||||
|
import { breakpointsTailwind } from "@vueuse/core";
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const breakpoints = useBreakpoints(breakpointsTailwind);
|
||||||
|
|
||||||
const PersonIcon = PersonOutlined;
|
const { data: recentProducts } = await useAsyncData("recent-products", () =>
|
||||||
|
queryCollection("products").order("updatedDate", "DESC").limit(5).all()
|
||||||
|
);
|
||||||
|
|
||||||
const activeKey = computed(() => {
|
const activeKey = computed(() => {
|
||||||
// Map route paths to menu keys
|
// Map route paths to menu keys
|
||||||
if (route.path === "/") return "explore";
|
if (route.path === "/") return "explore";
|
||||||
|
if (route.path.startsWith("/products")) return "products";
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,32 +118,46 @@ function renderLabel(label: string, route: string) {
|
|||||||
return () => h(RouterLink, { to: route }, { default: () => label });
|
return () => h(RouterLink, { to: route }, { default: () => label });
|
||||||
}
|
}
|
||||||
|
|
||||||
const menuOptions: MenuOption[] = [
|
function renderExternalLabel(label: string, url: string) {
|
||||||
|
return () =>
|
||||||
|
h("a", { href: url, target: "_blank" }, { default: () => label });
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuOptions = computed<MenuOption[]>(() => {
|
||||||
|
const productChildren =
|
||||||
|
recentProducts.value?.map((product: any) => {
|
||||||
|
const id = product.stem.split("/").pop();
|
||||||
|
const hasPage = product.hasPage;
|
||||||
|
const url = hasPage ? `/products/${id}` : product.url;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: hasPage
|
||||||
|
? renderLabel(product.name, url)
|
||||||
|
: renderExternalLabel(product.name, url),
|
||||||
|
key: `product-${id}`,
|
||||||
|
icon: product.icon
|
||||||
|
? () =>
|
||||||
|
h(NAvatar, {
|
||||||
|
src: product.icon,
|
||||||
|
size: 24,
|
||||||
|
style: { backgroundColor: "transparent" },
|
||||||
|
})
|
||||||
|
: renderIcon(CategoryOutlined), // Fallback icon, ideally use product.icon if possible but requires NAvatar
|
||||||
|
};
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
label: renderLabel("Explore", "/"),
|
label: renderLabel("Explore", "/"),
|
||||||
key: "explore",
|
key: "explore",
|
||||||
icon: renderIcon(ExploreOutlined),
|
icon: renderIcon(ExploreOutlined),
|
||||||
},
|
},
|
||||||
];
|
|
||||||
|
|
||||||
const dropdownOptions = computed(() => {
|
|
||||||
// For now, show login/signup options
|
|
||||||
// TODO: Add user authentication state check
|
|
||||||
return [
|
|
||||||
{
|
{
|
||||||
label: "Login",
|
label: renderLabel("Products", "/products"),
|
||||||
key: "/auth/login",
|
key: "products",
|
||||||
icon: renderIcon(LogInOutlined),
|
icon: renderIcon(CategoryOutlined),
|
||||||
},
|
children: productChildren,
|
||||||
{
|
|
||||||
label: "Create Account",
|
|
||||||
key: "/auth/create-account",
|
|
||||||
icon: renderIcon(PersonAddOutlined),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleDropdownSelect(key: string) {
|
|
||||||
router.push(key);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
127
app/pages/about.vue
Normal file
127
app/pages/about.vue
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<template>
|
||||||
|
<main class="container mx-auto h-full px-8 flex flex-col gap-16 py-16">
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<div
|
||||||
|
class="text-center flex flex-col items-center justify-center animate-fade-in-up"
|
||||||
|
>
|
||||||
|
<h1 class="text-5xl font-extrabold mb-6">About Us</h1>
|
||||||
|
<p class="text-xl max-w-2xl opacity-80">
|
||||||
|
We are a collective of creators, dreamers, and builders.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mission Section -->
|
||||||
|
<section
|
||||||
|
class="grid grid-cols-1 md:grid-cols-2 gap-12 items-center animate-fade-in-up delay-100"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h2 class="text-3xl font-bold mb-4">Our Mission</h2>
|
||||||
|
<p class="text-lg opacity-90 leading-relaxed">
|
||||||
|
Our aim is not making a profit.
|
||||||
|
<i class="text-sm opacity-70">At least not yet.</i> <br /><br />
|
||||||
|
Instead, we hope we can spread the love to the world and make everyone
|
||||||
|
enjoy the fun of the Internet and technology. We believe in open
|
||||||
|
source, collaboration, and building things that bring joy.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<n-card class="max-w-sm w-full bg-opacity-50 backdrop-blur-sm">
|
||||||
|
<div class="flex flex-col items-center text-center p-4">
|
||||||
|
<n-icon size="48" class="mb-4 text-primary">
|
||||||
|
<heart-outlined />
|
||||||
|
</n-icon>
|
||||||
|
<h3 class="text-xl font-bold mb-2">Built with Love</h3>
|
||||||
|
<p class="opacity-80">
|
||||||
|
Every line of code is written with passion and care.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Team Section -->
|
||||||
|
<section class="animate-fade-in-up delay-200">
|
||||||
|
<h2 class="text-3xl font-bold mb-8 text-center">Meet the Team</h2>
|
||||||
|
<div class="flex flex-wrap justify-center gap-8">
|
||||||
|
<!-- Team Member Card -->
|
||||||
|
<n-card
|
||||||
|
class="max-w-xs w-full hover:shadow-lg transition-shadow duration-300"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col items-center text-center">
|
||||||
|
<n-avatar
|
||||||
|
src="https://fs.solian.app/api/files/200ee92546244ed1a6a02202f5ca9cc9"
|
||||||
|
:size="120"
|
||||||
|
class="mb-4 shadow-md"
|
||||||
|
/>
|
||||||
|
<h3 class="text-xl font-bold">LittleSheep</h3>
|
||||||
|
<div class="flex items-center gap-2 mt-1 mb-3">
|
||||||
|
<n-tag size="small" type="primary" round>Founder</n-tag>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
tag="a"
|
||||||
|
size="small"
|
||||||
|
href="https://id.solian.app/@littlesheep"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<n-icon size="18">
|
||||||
|
<info-outlined />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm opacity-75 mb-4">
|
||||||
|
Founder, CEO, CTO, Senior Developer, Marketing Engineer, Customer
|
||||||
|
Service Engineer, DevOps, Database Administrator, Product Manager,
|
||||||
|
UI/UX Designer, QA Engineer, Mobile Developer, Security Engineer,
|
||||||
|
Technical Writer, Project Manager, Community Manager, Software
|
||||||
|
Architect
|
||||||
|
</p>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<n-button
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
tag="a"
|
||||||
|
href="https://github.com/LittleSheep"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<template #icon
|
||||||
|
><n-icon><logo-github /></n-icon
|
||||||
|
></template>
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { InfoOutlined } from "@vicons/material";
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: "About Us - Solsynth",
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.animate-fade-in-up {
|
||||||
|
animation: fadeInUp 0.8s ease-out forwards;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-100 {
|
||||||
|
animation-delay: 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delay-200 {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,56 +1,75 @@
|
|||||||
<template>
|
<template>
|
||||||
<main class="container mx-auto h-full px-8 flex flex-col gap-16">
|
<main class="container mx-auto h-full px-8 flex flex-col gap-24 pb-24">
|
||||||
<div class="text-center py-56 flex flex-col items-center justify-center">
|
<!-- Hero Section -->
|
||||||
<nuxt-img src="/favicon.png" class="w-28 h-28 mb-4" />
|
<div
|
||||||
<h1 class="text-5xl font-extrabold mb-3">We <span id="who-are-we" /></h1>
|
class="text-center min-h-[80vh] flex flex-col items-center justify-center relative"
|
||||||
<p class="text-xl mb-8">
|
>
|
||||||
|
<!-- Background decoration -->
|
||||||
|
<div
|
||||||
|
class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px] bg-primary/20 rounded-full blur-[120px] -z-10 pointer-events-none"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<nuxt-img src="/favicon.png" class="w-32 h-32 mb-8 animate-float" />
|
||||||
|
<h1 class="text-6xl font-extrabold mb-6 tracking-tight">
|
||||||
|
We <span ref="typedElement" class="text-primary" />
|
||||||
|
</h1>
|
||||||
|
<p class="text-2xl mb-10 opacity-80 max-w-2xl">
|
||||||
We are a group of friends that make software, hardware and any stuff
|
We are a group of friends that make software, hardware and any stuff
|
||||||
that interesting.
|
that is interesting.
|
||||||
</p>
|
</p>
|
||||||
<n-space justify="center">
|
<n-space justify="center" size="large">
|
||||||
<n-button type="primary" size="large" round tag="a" href="#products"
|
<n-button
|
||||||
>Explore around</n-button
|
type="primary"
|
||||||
>
|
size="large"
|
||||||
<n-button type="default" size="large" round tag="a" href="#about"
|
round
|
||||||
>About us</n-button
|
tag="a"
|
||||||
|
href="#products"
|
||||||
|
class="px-8 text-lg font-bold shadow-lg shadow-primary/30 hover:shadow-primary/50 transition-shadow"
|
||||||
>
|
>
|
||||||
|
Explore Products
|
||||||
|
</n-button>
|
||||||
|
<n-button size="large" round tag="a" href="/about" class="px-8 text-lg">
|
||||||
|
About Us
|
||||||
|
</n-button>
|
||||||
</n-space>
|
</n-space>
|
||||||
|
|
||||||
|
<div class="absolute bottom-10 animate-bounce">
|
||||||
|
<n-icon
|
||||||
|
size="32"
|
||||||
|
class="opacity-50"
|
||||||
|
:component="ArrowDownwardOutlined"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div id="products" class="pb-56">
|
</div>
|
||||||
<client-only>
|
|
||||||
<n-grid cols="1 m:2 l:2" responsive="screen" x-gap="32" y-gap="16">
|
<!-- Products Section -->
|
||||||
<n-gi>
|
<div id="products" class="scroll-mt-24">
|
||||||
<div class="flex items-center justify-center">
|
<div class="text-center mb-16">
|
||||||
<n-carousel
|
<h2 class="text-4xl font-bold mb-4">Our Creations</h2>
|
||||||
show-arrow
|
<p class="text-xl opacity-70 max-w-2xl mx-auto">
|
||||||
autoplay
|
From social networks to cloud drives, we build tools that empower and
|
||||||
dot-type="line"
|
connect.
|
||||||
class="rounded-xl w-full max-h-[360px] aspect-video shrink"
|
</p>
|
||||||
>
|
</div>
|
||||||
<n-carousel-item
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
<n-card
|
||||||
v-for="product in products"
|
v-for="product in products"
|
||||||
:key="product.path"
|
:key="product.path"
|
||||||
class="rounded-xl w-full max-h-[360px] aspect-video relative"
|
class="product-card"
|
||||||
:style="`background-color: ${product.background ? 'transparent' : themeVar.baseColor}`"
|
content-style="padding: 0"
|
||||||
>
|
>
|
||||||
|
<div class="relative aspect-video overflow-hidden group">
|
||||||
<img
|
<img
|
||||||
:src="product.background"
|
:src="product.background"
|
||||||
class="absolute left-0 right-0 top-0 bottom-0 object-cover aspect-video"
|
class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
||||||
style="z-index: -1"
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
style="
|
class="absolute inset-0 bg-linear-to-t from-black/80 via-black/20 to-transparent opacity-90"
|
||||||
background: linear-gradient(
|
></div>
|
||||||
to top,
|
|
||||||
rgba(0, 0, 0, 0.7),
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
z-index: 1;
|
|
||||||
"
|
|
||||||
class="absolute left-0 right-0 top-1/2 bottom-0"
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
class="absolute left-0 right-0 top-0 px-4 pt-4 flex justify-end gap-2.5"
|
class="absolute top-4 right-4 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-300"
|
||||||
>
|
>
|
||||||
<n-button
|
<n-button
|
||||||
v-if="product.repo"
|
v-if="product.repo"
|
||||||
@@ -60,8 +79,9 @@
|
|||||||
tag="a"
|
tag="a"
|
||||||
:href="product.repo"
|
:href="product.repo"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
class="text-black"
|
||||||
>
|
>
|
||||||
<n-icon color="black"><code-round /></n-icon>
|
<n-icon><code-round /></n-icon>
|
||||||
</n-button>
|
</n-button>
|
||||||
<n-button
|
<n-button
|
||||||
v-if="product.url"
|
v-if="product.url"
|
||||||
@@ -71,149 +91,170 @@
|
|||||||
tag="a"
|
tag="a"
|
||||||
:href="product.url"
|
:href="product.url"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
class="text-black"
|
||||||
>
|
>
|
||||||
<n-icon color="black"><launch-round /></n-icon>
|
<n-icon><launch-round /></n-icon>
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
class="absolute bottom-0 px-6 py-8 w-full"
|
<div class="absolute bottom-0 left-0 right-0 p-6">
|
||||||
style="z-index: 2"
|
<div class="flex items-center gap-3 mb-2">
|
||||||
>
|
<nuxt-img
|
||||||
<nuxt-img :src="product.icon" class="w-12 h-12" />
|
:src="product.icon"
|
||||||
<p class="text-lg text-white line-height-1">
|
class="w-10 h-10 rounded-lg shadow-sm"
|
||||||
|
/>
|
||||||
|
<h3 class="text-xl font-bold text-white">
|
||||||
{{ product.name }}
|
{{ product.name }}
|
||||||
</p>
|
</h3>
|
||||||
<p class="text-white line-height-1">
|
</div>
|
||||||
|
<p class="text-gray-200 text-sm line-clamp-2">
|
||||||
{{ product.description }}
|
{{ product.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</n-carousel-item>
|
|
||||||
</n-carousel>
|
|
||||||
</div>
|
</div>
|
||||||
</n-gi>
|
</n-card>
|
||||||
<n-gi>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- About Teaser Section -->
|
||||||
|
<div class="py-16">
|
||||||
|
<n-card
|
||||||
|
class="bg-linear-to-r from-primary/10 to-secondary/10 border-0 overflow-hidden relative"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="flex justify-center text-right h-full py-8 px-4 flex-col"
|
class="absolute top-0 right-0 w-64 h-64 bg-primary/20 rounded-full blur-[80px] -translate-y-1/2 translate-x-1/2"
|
||||||
>
|
></div>
|
||||||
<h2 class="text-3xl font-bold mb-3">Our products</h2>
|
|
||||||
<p class="text-lg mb-1">
|
|
||||||
The made various of software, from social network to cloud
|
|
||||||
drive.
|
|
||||||
</p>
|
|
||||||
<p class="text-lg">
|
|
||||||
Take a look of them on the left on your own
|
|
||||||
<code>ヽ(>∀<☆)ノ</code>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</n-gi>
|
|
||||||
</n-grid>
|
|
||||||
</client-only>
|
|
||||||
</div>
|
|
||||||
<div id="about" class="pb-56">
|
|
||||||
<client-only>
|
|
||||||
<n-grid cols="1 m:2 l:2" responsive="screen" x-gap="32" y-gap="16">
|
|
||||||
<n-gi>
|
|
||||||
<div
|
<div
|
||||||
class="justify-center text-left h-full py-8 px-4 flex flex-col"
|
class="flex flex-col md:flex-row items-center gap-12 relative z-10 p-8"
|
||||||
>
|
>
|
||||||
<h2 class="text-3xl font-bold mb-3">About us</h2>
|
<div class="flex-1">
|
||||||
<p class="text-lg mb-1">
|
<h2 class="text-3xl font-bold mb-4">More Than Just Code</h2>
|
||||||
Our aim is not making a profit.
|
<p class="text-lg opacity-80 mb-6 leading-relaxed">
|
||||||
<i class="text-xs">At least not yet.</i>
|
We are a community-driven team focused on creating meaningful
|
||||||
|
experiences. Our mission goes beyond software—it's about
|
||||||
|
connection, innovation, and fun.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-lg">
|
<n-button type="primary" ghost size="large" tag="a" href="/about">
|
||||||
Instead we hope we can spread the love to the world and make
|
Read Our Story
|
||||||
everyone enjoy the fun of the Internet and the world.
|
<template #icon>
|
||||||
</p>
|
<n-icon :component="ChevronRightOutlined"></n-icon>
|
||||||
</div>
|
</template>
|
||||||
</n-gi>
|
|
||||||
<n-gi>
|
|
||||||
<div class="flex h-full justify-center flex-col text-right">
|
|
||||||
<h2 class="text-3xl font-bold mb-3">Team members</h2>
|
|
||||||
<p class="text-lg">
|
|
||||||
Say hi to our lovely members... uh, seems there is only me.
|
|
||||||
</p>
|
|
||||||
<div class="flex justify-end gap-4 my-4">
|
|
||||||
<div class="flex flex-col items-end text-right">
|
|
||||||
<n-avatar
|
|
||||||
src="https://fs.solian.app/api/files/200ee92546244ed1a6a02202f5ca9cc9"
|
|
||||||
:size="100"
|
|
||||||
class="mb-2"
|
|
||||||
/>
|
|
||||||
<div class="flex gap-1">
|
|
||||||
<p>LittleSheep</p>
|
|
||||||
<n-button
|
|
||||||
text
|
|
||||||
tag="a"
|
|
||||||
size="small"
|
|
||||||
href="https://id.solian.app/@littlesheep"
|
|
||||||
target="_blank"
|
|
||||||
class="mt-0.5"
|
|
||||||
>
|
|
||||||
<n-icon>
|
|
||||||
<info-outlined />
|
|
||||||
</n-icon>
|
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs opacity-75 max-w-sm">
|
<div class="flex-1 flex justify-center">
|
||||||
Founder, CEO, CTO, Senior Developer, Marketing Engineer,
|
<!-- Abstract representation or team collage could go here -->
|
||||||
Customer Service Engineer, DevOps, Database Administrator,
|
<div class="grid grid-cols-2 gap-4 opacity-80">
|
||||||
Product Manager, UI/UX Designer, QA Engineer, Mobile
|
<div
|
||||||
Developer, Security Engineer, Technical Writer, Project
|
class="w-32 h-32 rounded-2xl bg-primary/20 animate-pulse"
|
||||||
Manager, Community Manager, Software Architect
|
></div>
|
||||||
</p>
|
<div
|
||||||
|
class="w-32 h-32 rounded-2xl bg-secondary/20 animate-pulse delay-75"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="w-32 h-32 rounded-2xl bg-info/20 animate-pulse delay-150"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="w-32 h-32 rounded-2xl bg-success/20 animate-pulse delay-300"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</n-gi>
|
</n-card>
|
||||||
</n-grid>
|
|
||||||
</client-only>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { NSpace, NButton, NIcon, NCard } from "naive-ui";
|
||||||
import {
|
import {
|
||||||
NSpace,
|
LaunchRound,
|
||||||
NButton,
|
CodeRound,
|
||||||
NGrid,
|
ChevronRightOutlined,
|
||||||
NGi,
|
ArrowDownwardOutlined,
|
||||||
NCarousel,
|
} from "@vicons/material";
|
||||||
NCarouselItem,
|
|
||||||
NIcon,
|
|
||||||
NAvatar,
|
|
||||||
useThemeVars,
|
|
||||||
} from "naive-ui";
|
|
||||||
import { LaunchRound, CodeRound, InfoOutlined } from "@vicons/material";
|
|
||||||
import Typed from "typed.js";
|
import Typed from "typed.js";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const themeVar = useThemeVars();
|
const typedElement = ref(null);
|
||||||
|
const typed = shallowRef(null);
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: "Solsynth - Creating Experiences",
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (typedElement.value) {
|
||||||
|
if (typed.value) {
|
||||||
|
typed.value.destroy();
|
||||||
|
}
|
||||||
|
typed.value = new Typed(typedElement.value, {
|
||||||
|
strings: [
|
||||||
|
"make software",
|
||||||
|
"make hardware",
|
||||||
|
"craft experiences",
|
||||||
|
"write stories",
|
||||||
|
"are Solsynth",
|
||||||
|
],
|
||||||
|
typeSpeed: 50,
|
||||||
|
backDelay: 1500,
|
||||||
|
backSpeed: 30,
|
||||||
|
smartBackspace: true,
|
||||||
|
loop: true,
|
||||||
|
showCursor: true,
|
||||||
|
cursorChar: "|",
|
||||||
|
autoInsertCss: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (typed.value) {
|
||||||
|
typed.value.destroy();
|
||||||
|
typed.value = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const { data: products } = await useAsyncData(route.path, () => {
|
const { data: products } = await useAsyncData(route.path, () => {
|
||||||
return queryCollection("products").all();
|
return queryCollection("products").all();
|
||||||
});
|
});
|
||||||
|
|
||||||
useHead({
|
|
||||||
title: "Solsynth",
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
new Typed("#who-are-we", {
|
|
||||||
strings: [
|
|
||||||
"make software",
|
|
||||||
"make hardware",
|
|
||||||
"make experience",
|
|
||||||
"write stories",
|
|
||||||
"are Solsynth^3000",
|
|
||||||
],
|
|
||||||
typeSpeed: 40,
|
|
||||||
backDelay: 1000,
|
|
||||||
backSpeed: 40,
|
|
||||||
smartBackspace: true,
|
|
||||||
loop: true,
|
|
||||||
showCursor: false,
|
|
||||||
autoInsertCss: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.animate-float {
|
||||||
|
animation: float 6s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card {
|
||||||
|
height: 100%;
|
||||||
|
transform: translateY(0);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
overflow: hidden;
|
||||||
|
border: none;
|
||||||
|
background-color: rgba(
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
255,
|
||||||
|
0.5
|
||||||
|
); /* Example, adjust base color as needed */
|
||||||
|
backdrop-filter: blur(4px); /* For backdrop-blur-sm */
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-0.5rem); /* For -translate-y-2 */
|
||||||
|
box-shadow:
|
||||||
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
||||||
|
0 10px 10px -5px rgba(0, 0, 0, 0.04); /* For shadow-xl */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export default defineContentConfig({
|
|||||||
releasedDate: z.date().optional(),
|
releasedDate: z.date().optional(),
|
||||||
version: z.string().optional(),
|
version: z.string().optional(),
|
||||||
updatedDate: z.date().optional(),
|
updatedDate: z.date().optional(),
|
||||||
|
hasPage: z.boolean().optional(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
terms: defineCollection({
|
terms: defineCollection({
|
||||||
|
|||||||
@@ -7,5 +7,6 @@
|
|||||||
"repo": "https://github.com/littlesheep2code/groovy-box",
|
"repo": "https://github.com/littlesheep2code/groovy-box",
|
||||||
"releasedDate": "2025-08-14T08:00:00.000Z",
|
"releasedDate": "2025-08-14T08:00:00.000Z",
|
||||||
"version": "1.0.0.0",
|
"version": "1.0.0.0",
|
||||||
"updatedDate": "2025-08-14T08:00:00.000Z"
|
"updatedDate": "2025-08-14T08:00:00.000Z",
|
||||||
|
"hasPage": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,6 @@
|
|||||||
"repo": "https://github.com/Solsynth/Solian",
|
"repo": "https://github.com/Solsynth/Solian",
|
||||||
"releasedDate": "2024-01-27T08:00:00.000Z",
|
"releasedDate": "2024-01-27T08:00:00.000Z",
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"updatedDate": "2025-07-28T08:00:00.000Z"
|
"updatedDate": "2025-07-28T08:00:00.000Z",
|
||||||
|
"hasPage": true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user