This commit is contained in:
Ricocc
2025-11-06 01:12:02 +08:00
commit 2b8d1d0f1d
313 changed files with 14981 additions and 0 deletions

16
src/pages/404.astro Normal file
View File

@@ -0,0 +1,16 @@
---
import PageLayout from "@/layouts/PageLayout.astro";
import PageHeader from "@/components/elements/PageHeader.astro";
import Button from "@/components/ui/Button.astro";
---
<PageLayout title="Page Not Found">
<section class="site-container m-auto min-h-[50vh] flex flex-col items-center justify-center">
<PageHeader
title="404 - Page Not Found"
description="Button to go back to home page"
/>
<div class="mt-0 flex justify-center">
<Button url="/">Go Home Page</Button>
</section>
</PageLayout>

357
src/pages/about.astro Normal file
View File

@@ -0,0 +1,357 @@
---
import {
ArrowUpRight,
Code,
Globe,
Mail,
Monitor,
Palette,
Smartphone,
Zap,
} from "@lucide/astro";
import { siteConfig } from "@/config/site.js";
import experiences from "@/collections/experiences.json";
import social from "@/collections/social.json";
import AboutExperience from "@/components/elements/AboutExperience.astro";
import Button from "@/components/ui/Button.astro";
import Matter from "@/components/ui/Matter.astro";
import Layout from "@/layouts/Layout.astro";
import Toc from "@/components/widgets/Toc.astro";
// Manually define page table of contents structure
const headings = [
{ depth: 2, slug: "about-me", text: "About Me" },
{ depth: 2, slug: "expertise", text: "Expertise" },
{ depth: 2, slug: "tool-stack", text: "Tool Stack" },
{ depth: 2, slug: "experience", text: "Experience" },
{ depth: 2, slug: "lets-connect", text: "Let's Connect" },
];
const filtered = headings.filter(h => h.depth <= 3);
---
<Layout title="About Me">
<!-- Mobile TOC -->
<div class="block lg:hidden px-7 pt-6">
<Toc headings={filtered} />
</div>
<!-- Main container -->
<div class="relative site-container mx-auto my-8">
<div class="flex flex-col lg:flex-row gap-8 lg:gap-12 xl:gap-16">
<!-- Left TOC - Fixed on desktop -->
<aside class="relative hidden lg:block lg:w-40 xl:w-50 flex-shrink-0">
<div class="toc-sticky-wrapper">
<Toc headings={filtered} />
</div>
</aside>
<!-- Right main content - Adaptive width -->
<main class="relative flex-1 min-w-0 w-full lg:max-w-none">
<div
class="w-full"
data-aos="fade-up-xs"
data-aos-duration="500"
data-aos-once="true"
>
<h2
id="about-me"
class="text-2xl font-brand tracking-tight sm:text-3xl lg:text-4xl"
>
About Me
</h2>
<div class="w-full border-b-1 border-dashed border-b-gray-200 dark:border-b-neutral-700 mt-4 mb-8"></div>
</div>
<div
class="flex items-center gap-3 mb-6"
data-aos="fade-up-xs"
data-aos-delay="100"
data-aos-duration="500"
data-aos-once="true"
>
<img src="/assets/avatar.png" alt="Ricoui" class="w-14 h-14 rounded-full">
<div class="flex items-center gap-3">
<a href="https://www.ricoui.com/" target="_blank" class="font-brand text-[24px] text-neutral-700 dark:text-neutral-100">Rico</a>
<span class="text-[0.75em] text-neutral-400">|</span>
<a href="https://x.com/ricouii" class="flex items-center gap-1 text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200 text-sm" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="w-4.5 h-4.5 fill-current">
<path d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z" />
</svg>
@ricouii
</a>
</div>
</div>
<p
class="text-3xl mt-2 mb-2 font-brand italic text-left text-primary-strong dark:text-primary-light"
data-aos="fade-up-xs"
data-aos-delay="200"
data-aos-duration="500"
data-aos-once="true"
>"Beautiful design. Clean code. That's the goal."</p>
<!-- <div class="w-full border-b-1 border-dashed border-b-gray-200 dark:border-b-neutral-700 mt-4 mb-8"></div> -->
<div
class="social"
data-aos="fade-up-xs"
data-aos-delay="300"
data-aos-duration="600"
data-aos-once="true"
>
<div class="social-list flex flex-wrap gap-2 items-center justify-start mt-6 mb-8">
{social
.filter(item => item.isShow !== false)
.map((item, index) => (
<a
href={item.url}
target="_blank"
rel="noopener noreferrer"
class="social-item relative group overflow-hidden rounded-xl transition-all duration-300 hover:-translate-y-2 hover:rotate-[-6deg] hover:shadow-lg"
data-aos="fade-up-xs"
data-aos-delay={400 + (index * 50)}
data-aos-duration="400"
data-aos-once="true"
>
<img
src={item.image}
alt={item.name}
class="w-[96px] h-[96px] rounded-xl object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div class="absolute bottom-[10px] left-[12px] z-10">
<div class="social-name font-semibold text-[10px] text-white drop-shadow-md">
{item.name}
</div>
<div class="social-username text-[9px] text-white/85 drop-shadow-sm">
@{item.username}
</div>
</div>
{/* Hover overlay */}
{/* <div class="absolute inset-0 bg-gradient-to-t from-black/40 via-black/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-xl"></div> */}
</a>
))
}
</div>
</div>
<div class="w-full border-b-1 border-dashed border-b-gray-200 dark:border-b-neutral-700 mt-4 mb-8"></div>
<p
class="text-xl font-medium text-left text-neutral-800 dark:text-neutral-100"
data-aos="fade-up-xs"
data-aos-delay="100"
data-aos-duration="500"
data-aos-once="true"
>
I'm Rico, a Senior Web & Product Designer.
</p>
<p
class="text-neutral-700 pb-4 pt-4 leading-[1.8] dark:text-neutral-200"
data-aos="fade-up-xs"
data-aos-delay="200"
data-aos-duration="500"
data-aos-once="true"
>
With 8+ years of experience in UX/UI, I not only enjoy creative design and content creation, but coding is also one of my great interests. I often transform my rich and quirky ideas and creativity into design outcomes and tangible projects.
</p>
<p
class="text-neutral-700 leading-[1.8] dark:text-neutral-200"
data-aos="fade-up-xs"
data-aos-delay="300"
data-aos-duration="500"
data-aos-once="true"
>
Great design isn't just a pretty interface—it helps people reach their goals naturally, fuels sustainable growth, and keeps systems solid as you scale. I connect design and development, bringing strategy, usability, and execution together to turn visuals into real, measurable results.
</p>
<div
class="mt-8 mb-16 flex item-center justify-start gap-3"
data-aos="fade-up-xs"
data-aos-delay="400"
data-aos-duration="500"
data-aos-once="true"
>
<Button url="mailto:hello@rico.com" > <Mail size={16} /> hello@ricoui.com</Button>
<Button url={siteConfig.resume} type="fill"> Resume <ArrowUpRight size={16} /> </Button>
</div>
<!-- <img src="/assets/about.jpg" class="relative z-30 w-full my-10 rounded-xl" /> -->
<div class="w-full border-b-1 border-dashed border-b-neutral-200 dark:border-b-neutral-700 mt-4 mb-8"></div>
<section>
<h2
id="expertise"
class="mt-8 mb-2 text-[28px] text-neutral-800 dark:text-neutral-200 font-brand"
data-aos="fade-up-xs"
data-aos-duration="500"
data-aos-once="true"
>Expertise</h2>
<div
class="list flex flex-wrap gap-3 mt-4 mb-12 w-full items-center justify-start"
data-aos="fade-up-xs"
data-aos-delay="100"
data-aos-duration="600"
data-aos-once="true"
>
<!-- Product Design -->
<div class="item flex justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 px-5 py-4 rounded-xl bg-gradient-to-b from-[f7f8f0] to-[#f1f2f9] dark:from-gray-900 dark:to-gray-800 dark:text-neutral-200 ">
<div class="flex justify-center items-center flex-grow-0 flex-shrink-0 gap-2">
<Palette size={22} />
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-neutral-700 dark:text-neutral-200">
Product Design
</div>
</div>
</div>
<!-- Website Design -->
<div class="item flex justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 px-5 py-4 rounded-xl bg-gradient-to-b from-[f7f8f0] to-[#f1f2f9] dark:from-gray-900 dark:to-gray-800">
<div class="flex justify-center items-center flex-grow-0 flex-shrink-0 gap-2">
<Globe size={22} />
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-neutral-700 dark:text-neutral-200">
Website Design
</div>
</div>
</div>
<!-- Brand Design -->
<div class="item flex justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 px-5 py-4 rounded-xl bg-gradient-to-b from-[f7f8f0] to-[#f1f2f9] dark:from-gray-900 dark:to-gray-800">
<div class="flex justify-center items-center flex-grow-0 flex-shrink-0 gap-2">
<Zap size={22} />
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-neutral-700 dark:text-neutral-200">
Brand Design
</div>
</div>
</div>
<!-- Prototyping -->
<div class="item flex justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 px-5 py-4 rounded-xl bg-gradient-to-b from-[f7f8f0] to-[#f1f2f9] dark:from-gray-900 dark:to-gray-800">
<div class="flex justify-center items-center flex-grow-0 flex-shrink-0 gap-2">
<Monitor size={22} />
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-neutral-700 dark:text-neutral-200">
Prototyping
</div>
</div>
</div>
<!-- Development -->
<div class="item flex justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 px-5 py-4 rounded-xl bg-gradient-to-b from-[f7f8f0] to-[#f1f2f9] dark:from-gray-900 dark:to-gray-800">
<div class="flex justify-center items-center flex-grow-0 flex-shrink-0 gap-2">
<Code size={22} />
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-neutral-700 dark:text-neutral-200">
Development
</div>
</div>
</div>
<!-- UI/UX Design -->
<div class="item flex justify-start items-start flex-grow-0 flex-shrink-0 overflow-hidden gap-2 px-5 py-4 rounded-xl bg-gradient-to-b from-[f7f8f0] to-[#f1f2f9] dark:from-gray-900 dark:to-gray-800">
<div class="flex justify-center items-center flex-grow-0 flex-shrink-0 gap-2">
<Smartphone size={22} />
<div class="flex-grow-0 flex-shrink-0 text-base font-medium text-left text-neutral-700 dark:text-neutral-200">
UI/UX Design
</div>
</div>
</div>
</div>
</section>
<div class="w-full border-b-1 border-dashed border-b-gray-200 dark:border-b-neutral-700 mt-4 mb-8"></div>
<section>
<h2
id="tool-stack"
class="mt-12 mb-4 text-[28px] text-neutral-800 dark:text-neutral-200 font-brand"
data-aos="fade-up-xs"
data-aos-duration="500"
data-aos-once="true"
>Tool Stack</h2>
<div
class="tool-stack-box relative bg-white border-accent/25 dark:bg-gray-900 rounded-xl overflow-hidden w-full h-[500px]"
data-aos="fade-up-sm"
data-aos-delay="100"
data-aos-duration="600"
data-aos-once="true"
>
<Matter />
<!-- Fallback content if Matter.js doesn't load -->
<div class="absolute inset-0 flex items-center justify-center text-white opacity-50">
</div>
</div>
</section>
<div class="w-full border-b-1 border-dashed border-b-gray-200 dark:border-b-neutral-700 mt-12 mb-12"></div>
<section class="experience">
<h2
id="experience"
class="mt-12 mb-4 text-[28px] text-neutral-800 dark:text-neutral-200 font-brand"
data-aos="fade-up-xs"
data-aos-duration="500"
data-aos-once="true"
>
Experience
</h2>
<div
class="px-5 py-10"
data-aos="fade-up-xs"
data-aos-delay="100"
data-aos-duration="600"
data-aos-once="true"
>
{
experiences.map((experience, index) => {
return (
<div
class="pb-10 border-l border-dashed border-gray-200 last:border-l-0 dark:border-neutral-500"
data-aos="fade-up-xs"
data-aos-delay={200 + (index * 100)}
data-aos-duration="500"
data-aos-once="true"
>
<AboutExperience
dates={experience.dates}
role={experience.role}
company={experience.company}
description={experience.description}
logo={experience.logo}
/>
</div>
)
})
}
</div>
</section>
<div class="w-full border-b-1 border-dashed border-b-gray-200 dark:border-b-neutral-700 mt-4 mb-8"></div>
<section>
<h2
id="lets-connect"
class="mt-12 mb-4 text-[28px] text-neutral-800 dark:text-neutral-200 font-brand"
data-aos="fade-up-xs"
data-aos-duration="500"
data-aos-once="true"
>Let's Connect</h2>
<p
class="text-sm leading-6 text-neutral-600 dark:text-neutral-300"
data-aos="fade-up-xs"
data-aos-delay="100"
data-aos-duration="500"
data-aos-once="true"
>
If you want to stay up to date with my work be sure to <a
href={siteConfig.social.twitter}
target="_blank"
class="text-indigo-500 underline">follow me on twitter</a
>, or you can send me an <a href="mailto:hello@ricouic.om" class="text-indigo-500 underline"
>email</a
> and I'll be sure to get back to you.
</p>
</section>
</main>
</div>
</div>
</Layout>
<style>
.toc-sticky-wrapper {
position: sticky;
top: 8rem;
}
</style>

111
src/pages/blog/[slug].astro Normal file
View File

@@ -0,0 +1,111 @@
---
import { getCollection } from "astro:content";
import PostLayout from "@/layouts/PostLayout.astro";
import Toc from '@/components/widgets/Toc.astro';
export async function getStaticPaths() {
const postEntries = await getCollection("post");
return postEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
}
const { entry } = Astro.props;
const { Content, headings } = await entry.render();
const filtered = headings.filter(h => h.depth <= 2);
---
<PostLayout title={entry.data.title} description={entry.data.description}>
<!-- Reading progress bar -->
<div id="reading-progress" class="reading-progress" style="transform: scaleX(0);"></div>
<div class="post article">
<main class="relative site-container mx-auto my-8 md:my-12">
<!-- Article header -->
<header class="article-header">
<!-- Tags -->
<div class="article-tags">
{entry.data.tags && entry.data.tags.length > 0 ? (
entry.data.tags.map(tag => (
<span class="article-tag letter-spacing-wide text-xs">{tag}</span>
))
) : (
<span class="article-tag text-xs">Article</span>
)}
</div>
<!-- Title -->
<h1 class="article-title font-brand">
{entry.data.title}
</h1>
<!-- Metadata -->
<div class="article-meta text-sm text-neutral-500 dark:text-neutral-400">
<time datetime={entry.data.publishDate.toISOString()}>
{entry.data.publishDate.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</time>
{entry.data.read && (
<>
<span class="article-meta-divider"></span>
<span>{entry.data.read} min read</span>
</>
)}
</div>
</header>
<!-- Content area -->
<div class="relative flex flex-col lg:flex-row gap-8 lg:gap-12 xl:gap-16">
<!-- Left TOC - Fixed on desktop -->
<aside class="relative hidden lg:block lg:w-40 xl:w-50 flex-shrink-0">
<div class="toc-sticky-wrapper">
<Toc headings={filtered} />
</div>
</aside>
<!-- Article content -->
<div class="relative flex-1 min-w-0 w-full lg:max-w-none">
<article class="article-wrapper">
<div class="article-content">
<Content />
</div>
</article>
</div>
</div>
</main>
</div>
</PostLayout>
<style>
.toc-sticky-wrapper {
position: sticky;
top: 8rem;
}
</style>
<script>
// Reading progress bar
function updateReadingProgress() {
const progressBar = document.getElementById('reading-progress');
if (!progressBar) return;
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
const scrollTop = window.scrollY;
const scrollPercentage = (scrollTop / (documentHeight - windowHeight)) * 100;
progressBar.style.transform = `scaleX(${Math.min(scrollPercentage / 100, 1)})`;
}
// Event listener
window.addEventListener('scroll', updateReadingProgress, { passive: true });
// Initialize
document.addEventListener('DOMContentLoaded', updateReadingProgress);
updateReadingProgress();
</script>

View File

@@ -0,0 +1,32 @@
---
import Layout from "@/layouts/Layout.astro";
import PageHeader from "@/components/elements/PageHeader.astro";
import BlogSection from "@/components/sections/BlogSection.astro";
// 使用与分页页面相同的每页文章数量
const POSTS_PER_PAGE = 3;
// 博客首页显示第一页内容
const currentPage = 1;
---
<Layout title="Blog">
<section class="relative z-20 container mx-auto my-12 px-7 lg:px-0">
<PageHeader
title="My Blog"
description="Explore my thoughts on design and development, the convergence of thinking and innovation. Feel free to follow the updates!"
/>
</section>
<section class="relative z-20 mx-auto my-12 lg:px-0">
<div class="mt-12">
<BlogSection
title=""
listPage={true}
pagination={{
enable: true,
currentPage: currentPage
}}
postsPerPage={POSTS_PER_PAGE}
/>
</div>
</section>
</Layout>

View File

@@ -0,0 +1,54 @@
---
import Layout from "@/layouts/Layout.astro";
import PageHeader from "@/components/elements/PageHeader.astro";
import BlogSection from "@/components/sections/BlogSection.astro";
import { getCollection } from "astro:content";
// 定义每页显示的文章数量
export const POSTS_PER_PAGE = 6;
// 生成分页路径
export async function getStaticPaths() {
const allPosts = await getCollection("post");
// 使用顶层定义的POSTS_PER_PAGE常量
const totalPages = Math.ceil(allPosts.length / POSTS_PER_PAGE);
return Array.from({ length: totalPages }, (_, i) => {
const page = i + 1;
return {
params: { page: page.toString() },
props: { page }
};
});
}
// 添加类型注解
interface Props {
page: string;
}
const { page }: Props = Astro.props;
const currentPage = parseInt(page);
---
<Layout title={`Blog - Page ${currentPage}`}>
<section class="relative z-20 container mx-auto my-12 px-7 lg:px-0">
<PageHeader
title="Blog"
description="Explore my thoughts on design and development, the convergence of thinking and innovation. Feel free to follow the updates!"
/>
</section>
<section class="relative z-20 mx-auto my-12 px-7 lg:px-0">
<div class="mt-12">
<BlogSection
title="All Articles"
listPage={true}
pagination={{
enable: true,
currentPage: currentPage
}}
postsPerPage={POSTS_PER_PAGE}
/>
</div>
</section>
</Layout>

132
src/pages/index.astro Normal file
View File

@@ -0,0 +1,132 @@
---
import Button from "../components/ui/Button.astro";
import { siteConfig } from "@/config/site";
import HeroCard from "@/components/home/HeroCard.astro";
import Layout from "@/layouts/Layout.astro";
import FeaturedWork from "../components/sections/FeaturedWork.astro";
import BlogSection from "@/components/sections/BlogSection.astro";
import SocialCard from "@/components/cards/SocialCard.astro";
import AnimatedText from "@/components/ui/AnimatedText.astro";
import Explore from "@/components/sections/Explore.astro";
---
<Layout
title="Rico Portfolio Site 2025"
description="Welcome to Rico's portfolio site! Explore my work as a web/UI designer with 8+ years of experience in creating captivating visuals and interactive experiences."
keywords="Rico, Portfolio, Web Design, UI Design, Frontend Development, Creative Designer"
>
<div
class="relative site-container z-20 w-full mx-auto mt-16 px-7 md:mt-18 lg:mt-20 xl:px-0"
>
<div class="relative w-full px-4 flex flex-col items-center justify-between md:flex-row mb-16 ">
<div class="relative w-full md:max-w-[420px] md:w-1/2 text-center sm:text-left sm:-mt-8">
<!-- Title - AnimatedText animation -->
<h1 class="mb-4">
<AnimatedText
content="Hi, I'm Rico"
delay={0.1}
duration={0.5}
stagger={0.08}
class="text-5xl text-pri leading-tight md:text-4xl lg:text-6xl font-brand "
/>
</h1>
<!-- First description - AnimatedText animation -->
<div class="mb-2">
<AnimatedText
content="I'm a web/UI designer with 8+ years of experience. I love blending design and code to create captivating visuals and interactive experiences."
delay={0.3}
duration={0.5}
stagger={0.015}
class="text-base text-neutral-700 dark:text-neutral-300"
/>
</div>
<!-- Second description - AnimatedText animation -->
<div class="mb-4">
<AnimatedText
content="I believe great design should be both delightful and solve real-world challenges."
delay={0.5}
duration={0.5}
stagger={0.015}
class="text-base text-neutral-700 dark:text-neutral-300"
/>
</div>
<!-- Button - AOS animation -->
<div
class=""
data-aos="fade-up-sm"
data-aos-delay="900"
data-aos-duration="500"
data-aos-once="true"
>
<Button url={siteConfig.social.twitter} type="fill" className="m-auto mt-4 text-center sm:text-left sm:m-0 sm:mt-6 max-w-[200px]">
Follow me on 𝕏
</Button>
</div>
<!-- Social Cards - AOS animation -->
<div
class="social mt-8 mb-8"
data-aos="fade-up-sm"
data-aos-delay="1000"
data-aos-duration="600"
data-aos-once="true"
>
<SocialCard displaySocialIds={[1, 2, 3,4]}/>
</div>
</div>
<!-- HeroCard - AOS animation -->
<div
class="relative justify-end w-full mt-16 md:flex md:pl-10 md:w-1/2 md:mt-0 md:translate-y-4 xl:translate-y-0"
data-aos="fade-left-sm"
data-aos-delay="300"
data-aos-duration="800"
data-aos-once="true"
>
<HeroCard
imageUrl="/assets/home/gradientshub.jpg"
title="Gradientshub"
link="https://gradientshub.com"
/>
</div>
</div>
</div>
<section
class="mt-26 mb-12"
data-aos="fade-up-sm"
data-aos-delay="100"
data-aos-duration="600"
data-aos-once="true"
>
<Explore title="Explore ↓" />
</section>
<section
class="mt-26 mb-12"
data-aos="fade-up-sm"
data-aos-delay="100"
data-aos-duration="600"
data-aos-once="true"
>
<FeaturedWork title="Featured Work ↓" description="I create innovative and purposeful designs that not only capture attention but also drive meaningful results." limit={5} />
</section>
<section
class="mt-26 mb-12"
data-aos="fade-up-sm"
data-aos-delay="100"
data-aos-duration="600"
data-aos-once="true"
>
<BlogSection
title="Latest Articles ↓"
description="These are my notes and articles on design, development and life thinking."
showViewAllButton={true}
/>
</section>
</Layout>

19
src/pages/rss.xml.js Normal file
View File

@@ -0,0 +1,19 @@
import rss from "@astrojs/rss";
import { getCollection } from "astro:content";
export async function GET(context) {
const blog = await getCollection('post');
return rss({
title: 'Rico Portfolio Template Astro',
description: 'Astro Blog Template by Rico UI',
site: context.site,
items: blog.map((post) => ({
title: post.data.title,
pubDate: post.data.pubDate,
description: post.data.description,
// ...post.data,
link: `/blog/${post.slug}/`,
stylesheet: '/rss/pretty-feed-v3.xsl',
})),
});
}

View File

@@ -0,0 +1,64 @@
---
import { Image } from "astro:assets";
import PostLayout from "@/layouts/PostLayout.astro";
import PageHeader from "@/components/elements/PageHeader.astro";
import ActionBar from "@/components/widgets/ActionBar.astro";
import SeparatorLine from "@/components/elements/SeparatorLine.astro";
const workTitle = "3D Valentines Assets";
const workDescription = "Design Resources & Tools";
const workTags = ["3D", "Resources", "Tools"];
// 手动导入图片
import Img01 from "../../assets/work/free-3d-valentines-assets/01.jpg";
import Img02 from "../../assets/work/free-3d-valentines-assets/02.jpg";
import Img03 from "../../assets/work/free-3d-valentines-assets/03.jpg";
import Img04 from "../../assets/work/free-3d-valentines-assets/04.jpg";
const images = [Img01, Img02, Img03, Img04];
import logoUrl from "../../assets/work/free-3d-valentines-assets/logo.png";
---
<PostLayout
title={workTitle}
description="Free 3D Valentine's Day assets for designers and developers. High-quality 3D models and designs for your projects."
keywords="3D, Valentine's Day, Design Resources, 3D Models, Free Assets, Design Tools"
>
<div class="work article">
<main class="work-wrapper">
<PageHeader
title={workTitle}
tags={workTags}
className="mb-6 md:mb-8"
>
</PageHeader>
</section>
<div class="site-container m-auto">
<SeparatorLine />
</div>
<section class="article-content">
<div class="site-container mx-auto my-8 md:my-16 ">
<div>
<p>
An exquisite collection of 3D Valentine's Day materials, providing creative inspiration for designers and developers. This free 3D resource pack includes various high-quality models and designs that can be used for your Valentine's Day themed projects.
</p>
<p>These 3D resources feature modern design styles with rich details and textures. Whether used for website design, application interfaces, social media content, or other creative projects, these resources can help you create unique Valentine's Day experiences.</p>
<p>All resources are free to use and suitable for both personal and commercial projects. Feel free to download and use these beautiful 3D Valentine's Day materials in your designs.</p>
</div>
{images.map((img, index) => (
<picture class="picture mt-8 md:mt-12 mb-8 md:mb-12 rounded-2xl overflow-hidden">
<Image src={img} alt={`3D Valentine's Day asset ${index + 1}`} class="w-full h-full object-cover" loading="lazy" decoding="async" quality={100}/>
</picture>
))}
</div>
</section>
</main>
</div>
<ActionBar
logo={logoUrl}
tags={workTags}
url="https://valentine.uiuxdeck.com/"
github="https://github.com/ricocc/free-3d-valentines-assets"
visitLabel="Visit Site"
/>
</PostLayout>

View File

@@ -0,0 +1,67 @@
---
import { Image } from "astro:assets";
import PostLayout from "@/layouts/PostLayout.astro";
import PageHeader from "@/components/elements/PageHeader.astro";
import ActionBar from "@/components/widgets/ActionBar.astro";
import SeparatorLine from "@/components/elements/SeparatorLine.astro";
//自动导入 Image 组件和图像
// const allImages = await Astro.glob('../../assets/work/ricoblog2024/*.{jpg,png,webp}');
// 手动导入图片
import P_01 from "../../assets/work/ricoblog2024/P_01.jpg";
import P_02 from "../../assets/work/ricoblog2024/P_02.jpg";
import P_03 from "../../assets/work/ricoblog2024/P_03.jpg";
import P_04 from "../../assets/work/ricoblog2024/P_04.jpg";
import P_05 from "../../assets/work/ricoblog2024/P_05.jpg";
import P_06 from "../../assets/work/ricoblog2024/P_06.jpg";
import P_07 from "../../assets/work/ricoblog2024/P_07.jpg";
const images = [P_01, P_02, P_03, P_04, P_05, P_06, P_07];
import logoUrl from "../../assets/work/ricoblog2024/logo.png";
---
<PostLayout
title="Rico Designer Blog 2024"
description = 'A personal blog site designed and developed by RicoDesigner in 2024, showcasing his design philosophy and portfolio.',
keywords = 'Rico Designer, Blog, Portfolio, Open Source, Web Design, Astro.js, Figma',
>
<div class="work article">
<main class="work-wrapper">
<PageHeader
title="Rico Designer Blog 2024"
tags={["Designer","Portfolio","Open Source"]}
className="mb-6 md:mb-8"
>
</PageHeader>
</section>
<div class="site-container m-auto">
<SeparatorLine />
</div>
<section class="article-content">
<div class="site-container mx-auto my-8 md:my-16 ">
<div>
<p>
我每一年都会计划制作一个人网站,在其中运用自己当时喜欢的技术、热爱的风格和即时的想法。从设计细节中去看到我的审美、思想、设计的看法等一切的动态变化。 这真的十分有趣。
</p>
<p>本次的网站开发,从突然有了想法,确定设计风格、选择技术栈,到整个网站框架大概制作完毕,其实只花了大约一周时间。会不会有人好奇我思考原型和设计稿、开发的过程呢?</p>
<p>实际上设计的部分,一页都没有画,想法已经在脑海里了,只是用了 Figma 直接制作需要的元素素材。然后在开发的时候,一边写代码一边调整设计。</p>
<p>技术栈选择: Figma + Astro 💡Astro.js 推荐! 设计师也可以很快学会的前端框架!)</p>
</div>
{images.map((img, index) => (
<picture class="picture mt-8 md:mt-12 mb-8 md:mb-12 rounded-2xl overflow-hidden">
<Image src={img} alt={`Rico Blog 2024 设计图 ${index + 1}`} class="w-full h-full object-cover" loading="lazy" decoding="async" quality={100}/>
</picture>
))}
<!-- {images.map((img, index) => (
<picture class="picture mt-8 md:mt-12 mb-8 md:mb-12 rounded-2xl overflow-hidden">
<Image src={img.default} alt={`Image ${index + 1}`} class="w-full h-full object-cover" loading="lazy" decoding="async" quality={100}/>
</picture>
))} -->
</div>
</section>
</main>
</div>
<ActionBar logo={logoUrl} tags={["Designer", "Blog"]} url="https://ricoui.com/" github="https://github.com/ricocc/ricoblog2024" visitLabel="Visit Site" />
</PostLayout>

16
src/pages/works.astro Normal file
View File

@@ -0,0 +1,16 @@
---
import WorksSection from "@/components/sections/WorksSection.astro";
import PageLayout from "@/layouts/PageLayout.astro";
import PageHeader from "@/components/elements/PageHeader.astro";
---
<PageLayout title="My Works">
<section class="site-container m-auto">
<PageHeader
title="Works"
description="Here are some of my recent projects. I'm always working on something new, so check back often!"
/>
<WorksSection />
</section>
</PageLayout>