feat: 完成分类页开发
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/home/home",
|
||||
"pages/category/category",
|
||||
"pages/age/age",
|
||||
"pages/favorites/favorites",
|
||||
"pages/profile/profile"
|
||||
@@ -79,6 +80,12 @@
|
||||
"selectedIconPath": "assets/tabBar/home-active.png",
|
||||
"text": "发现"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/category/category",
|
||||
"iconPath": "assets/tabBar/category.png",
|
||||
"selectedIconPath": "assets/tabBar/category-active.png",
|
||||
"text": "分类"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/age/age",
|
||||
"iconPath": "assets/tabBar/age.png",
|
||||
|
||||
|
Before Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
@@ -19,10 +19,34 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
padding: 0 @page-padding-x;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.nav-bar__brand {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-bar__logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-bar__brand-name {
|
||||
font-size: @fs-nav-title;
|
||||
font-weight: @fw-nav-title;
|
||||
color: @color-nav-title;
|
||||
letter-spacing: @ls-nav-title;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.nav-bar__back {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { NAV_INNER_PX } from '../../utils/navMetrics';
|
||||
|
||||
const HOME_TAB_URL = '/pages/home/home';
|
||||
const HOME_ROUTE = 'pages/home/home';
|
||||
|
||||
const TAB_BAR_ROUTES = new Set([
|
||||
'pages/home/home',
|
||||
HOME_ROUTE,
|
||||
'pages/category/category',
|
||||
'pages/age/age',
|
||||
'pages/favorites/favorites',
|
||||
'pages/profile/profile',
|
||||
@@ -17,7 +20,9 @@ Component({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
navBlockHeight: 0,
|
||||
leftActionType: 'none',
|
||||
leftActionType: 'none' as 'none' | 'back' | 'home' | 'brand',
|
||||
/** 仅首页(Tab 根页)在 logo 旁展示「涂鸦丫」;其余主 Tab 只展示 logo */
|
||||
showBrandName: false,
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
@@ -40,15 +45,19 @@ Component({
|
||||
const currentRoute = pages[pages.length - 1]?.route || '';
|
||||
const isTabBarPage = TAB_BAR_ROUTES.has(currentRoute);
|
||||
|
||||
let leftActionType: 'none' | 'back' | 'home' = 'none';
|
||||
let leftActionType: 'none' | 'back' | 'home' | 'brand' = 'none';
|
||||
const showBrandName = currentRoute === HOME_ROUTE;
|
||||
|
||||
if (pages.length > 1) {
|
||||
leftActionType = 'back';
|
||||
} else if (!isTabBarPage) {
|
||||
leftActionType = 'home';
|
||||
} else {
|
||||
// 五个主 Tab 根页:仅展示品牌区(左 logo;首页另见 showBrandName)
|
||||
leftActionType = 'brand';
|
||||
}
|
||||
|
||||
this.setData({ leftActionType });
|
||||
this.setData({ leftActionType, showBrandName });
|
||||
},
|
||||
|
||||
handleLeftAction() {
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
class="nav-bar"
|
||||
style="padding-top: {{statusBarHeight}}px; {{background ? 'background:' + background + ';' : ''}}">
|
||||
<view class="nav-bar__inner">
|
||||
<view wx:if="{{leftActionType === 'brand'}}" class="nav-bar__brand">
|
||||
<image
|
||||
class="nav-bar__logo"
|
||||
src="/assets/imgs/doodle-logo.png"
|
||||
mode="aspectFill" />
|
||||
<text wx:if="{{showBrandName}}" class="nav-bar__brand-name"
|
||||
>涂鸦丫</text
|
||||
>
|
||||
</view>
|
||||
<view
|
||||
wx:else
|
||||
class="nav-bar__back {{leftActionType === 'none' ? 'nav-bar__back--hidden' : ''}}"
|
||||
bindtap="handleLeftAction">
|
||||
<text
|
||||
@@ -12,7 +22,6 @@
|
||||
wx:elif="{{leftActionType === 'home'}}"
|
||||
class="toy-icon toy-icon-home-o nav-bar__back-icon"></text>
|
||||
</view>
|
||||
<slot name="left"></slot>
|
||||
<text class="nav-bar__title">{{title}}</text>
|
||||
<view class="nav-bar__right">
|
||||
<slot name="right"></slot>
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
export type CategoryItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
icon: string;
|
||||
img?: string;
|
||||
ageBand: string;
|
||||
difficulty: string;
|
||||
path: string;
|
||||
available: boolean;
|
||||
likes: number;
|
||||
downloads: number;
|
||||
date: string;
|
||||
};
|
||||
|
||||
export type CategoryGroup = {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
items: CategoryItem[];
|
||||
};
|
||||
|
||||
export type CategoryDataset = {
|
||||
searchPlaceholder: string;
|
||||
categories: CategoryGroup[];
|
||||
};
|
||||
|
||||
const DIFFICULTY_MAP: Record<string, string> = {
|
||||
beginner: '入门',
|
||||
basic: '基础',
|
||||
intermediate: '进阶',
|
||||
advanced: '挑战',
|
||||
};
|
||||
|
||||
function d(key: string): string {
|
||||
return DIFFICULTY_MAP[key] ?? key;
|
||||
}
|
||||
|
||||
function age(min: number, max: number): string {
|
||||
return `${min}-${max}岁`;
|
||||
}
|
||||
|
||||
const TODAY = '2026-4-22';
|
||||
|
||||
/** 基于 id 生成稳定的伪随机统计数 */
|
||||
function statsFromId(id: string): { likes: number; downloads: number } {
|
||||
let h = 0;
|
||||
for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) | 0;
|
||||
const likes = 100 + Math.abs(h % 900);
|
||||
const downloads = 20 + Math.abs((h >>> 4) % 200);
|
||||
return { likes, downloads };
|
||||
}
|
||||
|
||||
type ItemInput = Omit<CategoryItem, 'likes' | 'downloads' | 'date'>;
|
||||
|
||||
function item(input: ItemInput): CategoryItem {
|
||||
const { likes, downloads } = statsFromId(input.id);
|
||||
return { ...input, likes, downloads, date: TODAY };
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export const CATEGORY_DATA: CategoryDataset = {
|
||||
searchPlaceholder: '搜索练习纸...',
|
||||
categories: [
|
||||
{
|
||||
id: 'math', name: '数感启蒙', icon: '📐',
|
||||
items: [
|
||||
item({ id: 'number-find', title: '找数字,涂一涂', subtitle: '在数字方阵中找出目标数字并涂色', icon: '🔍', img: '/assets/entrancePicture/math/number-find.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=number-find', available: true }),
|
||||
item({ id: 'number-write', title: '看数字,写一写', subtitle: '按笔画顺序练习书写数字', icon: '✏️', img: '/assets/entrancePicture/math/number-write.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=number-write', available: true }),
|
||||
item({ id: 'number-coloring', title: '按数字,涂颜色', subtitle: '按指定数字给对应圆圈涂色', icon: '🎨', img: '/assets/entrancePicture/math/number-coloring.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=number-coloring', available: true }),
|
||||
item({ id: 'counting-matching', title: '数一数,连一连', subtitle: '连线配对数字和对应数量图形', icon: '🔗', img: '/assets/entrancePicture/math/count-match.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=counting-matching', available: true }),
|
||||
item({ id: 'number-object-match', title: '数物连线', subtitle: '连线相同数量的物品和数字', icon: '🔗', img: '/assets/entrancePicture/math/number-object-match.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=number-object-match', available: true }),
|
||||
item({ id: 'number-object-fill', title: '数物填写', subtitle: '数物品数量,填写对应数字', icon: '✏️', img: '/assets/entrancePicture/math/number-object-fill.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=number-object-fill', available: true }),
|
||||
item({ id: 'counting-select', title: '数一数,选一选', subtitle: '数出物品数量,圈出正确答案', icon: '✓', img: '/assets/entrancePicture/math/counting-select.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=counting-select', available: true }),
|
||||
item({ id: 'counting-fill', title: '数一数,填一填', subtitle: '数出物品数量,填写数字', icon: '✏️', img: '/assets/entrancePicture/math/counting-fill.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=counting-fill', available: true }),
|
||||
item({ id: 'compare', title: '数一数,比大小', subtitle: '比较数量,填入 ><=', icon: '⚖️', img: '/assets/entrancePicture/math/compare.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=compare', available: true }),
|
||||
item({ id: 'number-sort', title: '数字排序', subtitle: '写出正确的数字顺序', icon: '🔢', img: '/assets/entrancePicture/math/number-sort.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=number-sort', available: true }),
|
||||
item({ id: 'missing-number', title: '填上缺少的数字', subtitle: '在数列中找出并填写缺失数字', icon: '❓', img: '/assets/entrancePicture/math/missing-number.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=missing-number', available: true }),
|
||||
item({ id: 'number-decompose', title: '10以内数的分与合', subtitle: '把数字分一分,合一合', icon: '🔢', img: '/assets/entrancePicture/math/number-decompose.png', ageBand: age(4, 6), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=number-decompose', available: true }),
|
||||
item({ id: 'number-decompose-20', title: '20以内数的分与合', subtitle: '把数字分一分,合一合', icon: '🔢', img: '/assets/entrancePicture/math/number-decompose-20.png', ageBand: age(5, 7), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=number-decompose-20', available: true }),
|
||||
item({ id: 'one-digit-addition', title: '一位数加法', subtitle: '通过圆点学习一位数加法运算', icon: '➕', img: '/assets/entrancePicture/math/one-digit-addition.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=one-digit-addition', available: true }),
|
||||
item({ id: 'addition-5', title: '5以内加法', subtitle: '图形化展示 5 以内加法', icon: '➕', img: '/assets/entrancePicture/math/addition-5.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/mathPages/mathDraw/mathDraw?id=addition-5', available: true }),
|
||||
item({ id: 'addition-10', title: '10以内加法', subtitle: '图形化展示 10 以内加法', icon: '➕', img: '/assets/entrancePicture/math/addition-10.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=addition-10', available: true }),
|
||||
item({ id: 'subtraction-10', title: '10以内减法', subtitle: '图形化展示 10 以内减法', icon: '➖', img: '/assets/entrancePicture/math/subtraction-10.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=subtraction-10', available: true }),
|
||||
item({ id: 'addition-subtraction-10', title: '10以内加减法', subtitle: '加减法混合运算', icon: '±', img: '/assets/entrancePicture/math/addition-subtraction-10.png', ageBand: age(5, 7), difficulty: d('basic'), path: '/mathPages/mathDraw/mathDraw?id=addition-subtraction-10', available: true }),
|
||||
item({ id: 'make-ten', title: '凑十法练习', subtitle: '20 以内进位加法', icon: '➕', img: '/assets/entrancePicture/math/make-ten.png', ageBand: age(5, 7), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=make-ten', available: true }),
|
||||
item({ id: 'break-ten', title: '破十法练习', subtitle: '20 以内退位减法', icon: '➖', img: '/assets/entrancePicture/math/break-ten.png', ageBand: age(5, 7), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=break-ten', available: true }),
|
||||
item({ id: 'flat-ten', title: '平十法练习', subtitle: '20 以内退位减法', icon: '➖', img: '/assets/entrancePicture/math/flat-ten.png', ageBand: age(5, 7), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=flat-ten', available: true }),
|
||||
item({ id: 'borrow-ten', title: '借十法练习', subtitle: '20 以上退位减法', icon: '➖', img: '/assets/entrancePicture/math/borrow-ten.png', ageBand: age(6, 8), difficulty: d('advanced'), path: '/mathPages/mathDraw/mathDraw?id=borrow-ten', available: true }),
|
||||
item({ id: 'practice-addition', title: '加法运算', subtitle: '10/20/50/100 以内加法', icon: '➕', img: '/assets/entrancePicture/math/practice-addition.png', ageBand: age(5, 8), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=practice-addition', available: true }),
|
||||
item({ id: 'practice-subtraction', title: '减法运算', subtitle: '10/20/50/100 以内减法', icon: '➖', img: '/assets/entrancePicture/math/practice-subtraction.png', ageBand: age(5, 8), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=practice-subtraction', available: true }),
|
||||
item({ id: 'practice-mixed', title: '混合运算', subtitle: '10/20/50/100 以内加减法混合', icon: '±', img: '/assets/entrancePicture/math/practice-mixed.png', ageBand: age(5, 8), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=practice-mixed', available: true }),
|
||||
item({ id: 'multiplication-table', title: '九九乘法表', subtitle: '学习九九乘法口诀', icon: '✖️', img: '/assets/entrancePicture/math/multiplication-table.png', ageBand: age(6, 8), difficulty: d('intermediate'), path: '/mathPages/mathDraw/mathDraw?id=multiplication-table', available: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'pinyin', name: '汉语拼音', icon: '🔤',
|
||||
items: [
|
||||
item({ id: 'pinyin-initials', title: '声母描红', subtitle: '23个声母认读与书写练习', icon: '🔤', ageBand: age(5, 7), difficulty: d('basic'), path: '', available: false }),
|
||||
item({ id: 'pinyin-finals', title: '韵母描红', subtitle: '24个韵母认读与书写练习', icon: '🔤', ageBand: age(5, 7), difficulty: d('basic'), path: '', available: false }),
|
||||
item({ id: 'pinyin-overall', title: '整体认读音节', subtitle: '16个整体认读音节练习', icon: '🔤', ageBand: age(5, 7), difficulty: d('intermediate'), path: '', available: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'puzzle', name: '益智游戏', icon: '🧩',
|
||||
items: [
|
||||
item({ id: 'color-shape-match', title: '根据颜色画图形', subtitle: '根据颜色画出对应图形', icon: '🎯', img: '/assets/entrancePicture/focus/color-shape-match.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/focusPages/focusDraw/focusDraw?id=color-shape-match', available: true }),
|
||||
item({ id: 'shape-symbol', title: '图形符号配对', subtitle: '根据图形画对应符号', icon: '🔗', img: '/assets/entrancePicture/focus/shape-symbol.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/focusPages/focusDraw/focusDraw?id=shape-symbol', available: true }),
|
||||
item({ id: 'shape-recognition', title: '识别形状', subtitle: '识别形状,涂一涂', icon: '🔍', img: '/assets/entrancePicture/focus/shape-recognition.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/focusPages/focusDraw/focusDraw?id=shape-recognition', available: true }),
|
||||
item({ id: 'position-coloring', title: '方位涂涂乐', subtitle: '观察位置,在方格中涂色', icon: '📍', img: '/assets/entrancePicture/focus/position-coloring.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/focusPages/focusDraw/focusDraw?id=position-coloring', available: true }),
|
||||
item({ id: 'color-pattern', title: '颜色找规律', subtitle: '观察颜色规律,在空白图形中涂色', icon: '🎨', img: '/assets/entrancePicture/focus/color-pattern.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/focusPages/focusDraw/focusDraw?id=color-pattern', available: true }),
|
||||
item({ id: 'match-connect', title: '连连看', subtitle: '根据物品连一连', icon: '🔗', img: '/assets/entrancePicture/focus/match-connect.png', ageBand: age(3, 6), difficulty: d('beginner'), path: '/focusPages/focusDraw/focusDraw?id=match-connect', available: true }),
|
||||
item({ id: 'line-recognition', title: '线条识别', subtitle: '认识不同线条,画出颜色对应的线条', icon: '📏', img: '/assets/entrancePicture/focus/line-recognition.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/focusPages/focusDraw/focusDraw?id=line-recognition', available: true }),
|
||||
item({ id: 'grid-reasoning', title: '方格推理', subtitle: '推理出合并方格并连线', icon: '🧩', img: '/assets/entrancePicture/focus/grid-reasoning.png', ageBand: age(5, 7), difficulty: d('intermediate'), path: '/focusPages/focusDraw/focusDraw?id=grid-reasoning', available: true }),
|
||||
item({ id: 'code-connect', title: '译码连线', subtitle: '按数字顺序将数字对应颜色连线', icon: '🔢', img: '/assets/entrancePicture/focus/code-connect.png', ageBand: age(5, 7), difficulty: d('intermediate'), path: '/focusPages/focusDraw/focusDraw?id=code-connect', available: true }),
|
||||
item({ id: 'dot-connect', title: '数字点连线', subtitle: '按数字顺序连点成图', icon: '🔗', img: '/assets/entrancePicture/focus/dot-connect.png', ageBand: age(3, 6), difficulty: d('beginner'), path: '/focusPages/focusDraw/focusDraw?id=dot-connect', available: true }),
|
||||
item({ id: 'grid-drawing-3x3', title: '格子仿画 3×3', subtitle: '简单有趣,培养专注力', icon: '🎨', img: '/assets/entrancePicture/focus/grid-drawing-3x3.png', ageBand: age(3, 5), difficulty: d('beginner'), path: '/focusPages/focusDraw/focusDraw?id=grid-drawing-3x3', available: true }),
|
||||
item({ id: 'grid-drawing-5x5', title: '格子仿画 5×5', subtitle: '创意挑战,提升观察力', icon: '🎨', img: '/assets/entrancePicture/focus/grid-drawing-5x5.png', ageBand: age(4, 6), difficulty: d('basic'), path: '/focusPages/focusDraw/focusDraw?id=grid-drawing-5x5', available: true }),
|
||||
item({ id: 'grid-drawing-7x7', title: '格子仿画 7×7', subtitle: '大师挑战,锻炼耐心', icon: '🎨', img: '/assets/entrancePicture/focus/grid-drawing-7x7.png', ageBand: age(5, 8), difficulty: d('intermediate'), path: '/focusPages/focusDraw/focusDraw?id=grid-drawing-7x7', available: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'chinese', name: '趣味识字', icon: '✏️',
|
||||
items: [
|
||||
item({ id: 'word-recognition', title: '识字卡', subtitle: '输入或选字生成涂色识字卡', icon: '📖', ageBand: age(3, 6), difficulty: d('beginner'), path: '/pages/index/index', available: true }),
|
||||
item({ id: 'copybook', title: '练字帖', subtitle: '选字生成田字格笔顺练字帖', icon: '✏️', ageBand: age(4, 7), difficulty: d('basic'), path: '/pages/copyBook/copyBook', available: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'english', name: '英语启蒙', icon: '🔤',
|
||||
items: [
|
||||
item({ id: 'letter-tracing-single', title: '看图描红', subtitle: '单字母配图、例句与六行四线三格描红', icon: '🔠', img: '/assets/entrancePicture/english/letter-tracing-single.jpg', ageBand: age(4, 7), difficulty: d('beginner'), path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-single', available: true }),
|
||||
item({ id: 'letter-tracing-upper-lower', title: '字母总览', subtitle: 'Uppercase / Lowercase 分区总览', icon: '🔡', img: '/assets/entrancePicture/english/letter-tracing-upper-lower.jpg', ageBand: age(4, 7), difficulty: d('beginner'), path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-upper-lower', available: true }),
|
||||
item({ id: 'letter-tracing-case-pairing', title: '大小写练习', subtitle: '半组字母左大写右小写,逐行对照描红', icon: '✏️', img: '/assets/entrancePicture/english/letter-tracing-case-pairing.jpg', ageBand: age(4, 7), difficulty: d('beginner'), path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-case-pairing', available: true }),
|
||||
item({ id: 'letter-tracing-two-column', title: '两列练习', subtitle: '左 A–M、右 N–Z,大小写配对描红', icon: '🔤', img: '/assets/entrancePicture/english/letter-tracing-two-column.jpg', ageBand: age(4, 7), difficulty: d('beginner'), path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-two-column', available: true }),
|
||||
item({ id: 'letter-tracing-half', title: '单字母逐行', subtitle: '13 字母半表逐字练习', icon: '📝', img: '/assets/entrancePicture/english/letter-tracing-half.jpg', ageBand: age(4, 7), difficulty: d('basic'), path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-half', available: true }),
|
||||
item({ id: 'letter-tracing-three', title: '三字母精练', subtitle: '每页 3 个字母,大写 + 小写深度书写', icon: '🔤', img: '/assets/entrancePicture/english/letter-tracing-three.jpg', ageBand: age(4, 7), difficulty: d('basic'), path: '/englishPages/letterTracing/letterTracing?id=letter-tracing-three', available: true }),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'craft', name: '创意手工', icon: '🌈',
|
||||
items: [
|
||||
item({ id: 'craft-coloring', title: '涂色卡', subtitle: '动物、交通、节日主题涂色', icon: '🎨', ageBand: age(3, 6), difficulty: d('beginner'), path: '', available: false }),
|
||||
item({ id: 'craft-origami', title: '折纸模板', subtitle: '打印后即可折叠的趣味模板', icon: '🪭', ageBand: age(4, 7), difficulty: d('basic'), path: '', available: false }),
|
||||
item({ id: 'craft-stickers', title: '贴纸打印', subtitle: '奖励贴纸与装饰贴纸', icon: '⭐', ageBand: age(3, 8), difficulty: d('beginner'), path: '', available: false }),
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"navigationStyle": "custom",
|
||||
"navigationBarTitleText": "分类",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarBackgroundColor": "#FEF6E7",
|
||||
"backgroundColor": "#FEF6E7",
|
||||
"enablePullDownRefresh": false,
|
||||
"usingComponents": {
|
||||
"nav-bar": "../../components3.0/nav-bar/nav-bar",
|
||||
"van-icon": "@vant/weapp/icon/index",
|
||||
"toy-icon": "/toy/icon/icon"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
@import '../../style/theme.less';
|
||||
@import '../../style/tags.less';
|
||||
|
||||
.cat-page {
|
||||
height: 100vh;
|
||||
background: @bg-page;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
color: @text-secondary;
|
||||
}
|
||||
|
||||
.cat-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cat-search-wrap {
|
||||
padding: @section-gap-xs @page-padding-x 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cat-search {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
background: #e5dcc9;
|
||||
border-radius: 999rpx;
|
||||
padding: 20rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cat-search__icon {
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.cat-search__input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: @text-title;
|
||||
min-height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.cat-search__placeholder {
|
||||
font-size: 28rpx;
|
||||
color: rgba(50, 46, 37, 0.45);
|
||||
}
|
||||
|
||||
.cat-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
margin-top: @section-gap-xs;
|
||||
}
|
||||
|
||||
.cat-sidebar {
|
||||
width: 180rpx;
|
||||
flex-shrink: 0;
|
||||
background: @bg-header;
|
||||
border-top-right-radius: @radius-lg;
|
||||
padding: 16rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cat-sidebar__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
padding: 24rpx 12rpx;
|
||||
margin: 4rpx 12rpx;
|
||||
border-radius: 999rpx;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.cat-sidebar__item--active {
|
||||
background: @brand;
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 215, 9, 0.35);
|
||||
}
|
||||
|
||||
.cat-sidebar__icon {
|
||||
font-size: 36rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.cat-sidebar__name {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: @text-secondary;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cat-sidebar__item--active .cat-sidebar__name {
|
||||
color: @text-selected-btn;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cat-content {
|
||||
flex: 1;
|
||||
background: @bg-page;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cat-content__inner {
|
||||
padding: 8rpx 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.cat-content__footer {
|
||||
height: 48rpx;
|
||||
}
|
||||
|
||||
.cat-card {
|
||||
background: @bg-white;
|
||||
border-radius: 24rpx;
|
||||
padding: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(50, 46, 37, 0.06);
|
||||
transition: box-shadow 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cat-card__thumb {
|
||||
width: 160rpx;
|
||||
height: 180rpx;
|
||||
flex-shrink: 0;
|
||||
border-radius: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border: 1rpx solid #bbb;
|
||||
}
|
||||
|
||||
.cat-card__thumb-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cat-card__thumb-icon {
|
||||
font-size: 56rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.cat-card__body {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
gap: 8rpx;
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
.cat-card__header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.cat-card__title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: @text-title;
|
||||
line-height: 1.35;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.cat-card__coming {
|
||||
flex-shrink: 0;
|
||||
padding: 4rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(50, 46, 37, 0.08);
|
||||
font-size: 20rpx;
|
||||
color: @text-gray;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.cat-card__subtitle {
|
||||
font-size: 24rpx;
|
||||
color: @text-gray;
|
||||
line-height: 1.4;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cat-card__tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.cat-card__footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.cat-card__stats {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.cat-card__stat {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
font-size: 20rpx;
|
||||
color: #7c766a;
|
||||
line-height: 20rpx;
|
||||
}
|
||||
|
||||
.cat-card__date {
|
||||
font-size: 20rpx;
|
||||
color: #7c766a;
|
||||
line-height: 20rpx;
|
||||
}
|
||||
|
||||
.cat-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.cat-empty__icon {
|
||||
font-size: 80rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.cat-empty__text {
|
||||
font-size: 28rpx;
|
||||
color: @text-gray;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import { CATEGORY_DATA, type CategoryItem } from './category.data';
|
||||
|
||||
type CategoryTab = {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
};
|
||||
|
||||
type DisplayItem = CategoryItem & {
|
||||
thumbBg: string;
|
||||
};
|
||||
|
||||
const CATEGORY_BG: Record<string, string> = {
|
||||
math: '#fff3c4',
|
||||
pinyin: '#d8f0d0',
|
||||
puzzle: '#f5e6dc',
|
||||
chinese: '#d8f0d0',
|
||||
english: '#e8f4ff',
|
||||
craft: '#fce4ec',
|
||||
};
|
||||
|
||||
const ALL_TAB: CategoryTab = { id: 'all', name: '全部', icon: '📋' };
|
||||
|
||||
const SIDEBAR_TABS: CategoryTab[] = [
|
||||
ALL_TAB,
|
||||
...CATEGORY_DATA.categories.map((c) => ({
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
icon: c.icon,
|
||||
})),
|
||||
];
|
||||
|
||||
function buildAllItems(): DisplayItem[] {
|
||||
const items: DisplayItem[] = [];
|
||||
for (const group of CATEGORY_DATA.categories) {
|
||||
for (const item of group.items) {
|
||||
items.push({
|
||||
...item,
|
||||
thumbBg: CATEGORY_BG[group.id] ?? '#f0e7d6',
|
||||
});
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
function getItemsByCategory(categoryId: string): DisplayItem[] {
|
||||
if (categoryId === 'all') return buildAllItems();
|
||||
const group = CATEGORY_DATA.categories.find((c) => c.id === categoryId);
|
||||
if (!group) return [];
|
||||
return group.items.map((item) => ({
|
||||
...item,
|
||||
thumbBg: CATEGORY_BG[group.id] ?? '#f0e7d6',
|
||||
}));
|
||||
}
|
||||
|
||||
function filterByKeyword(items: DisplayItem[], keyword: string): DisplayItem[] {
|
||||
if (!keyword) return items;
|
||||
const kw = keyword.toLowerCase();
|
||||
return items.filter(
|
||||
(item) =>
|
||||
item.title.toLowerCase().includes(kw) ||
|
||||
item.subtitle.toLowerCase().includes(kw),
|
||||
);
|
||||
}
|
||||
|
||||
const TAB_BAR_PATHS = new Set([
|
||||
'/pages/home/home',
|
||||
'/pages/category/category',
|
||||
'/pages/age/age',
|
||||
'/pages/favorites/favorites',
|
||||
'/pages/profile/profile',
|
||||
]);
|
||||
|
||||
Page({
|
||||
data: {
|
||||
searchPlaceholder: CATEGORY_DATA.searchPlaceholder,
|
||||
searchKeyword: '',
|
||||
sidebarTabs: SIDEBAR_TABS,
|
||||
activeCategoryId: 'all',
|
||||
displayItems: buildAllItems() as DisplayItem[],
|
||||
scrollIntoViewId: '',
|
||||
},
|
||||
|
||||
onTapCategory(e: WechatMiniprogram.TouchEvent) {
|
||||
const id = e.currentTarget.dataset.id as string;
|
||||
if (!id || id === this.data.activeCategoryId) return;
|
||||
|
||||
const items = getItemsByCategory(id);
|
||||
const filtered = filterByKeyword(items, this.data.searchKeyword);
|
||||
|
||||
this.setData({
|
||||
activeCategoryId: id,
|
||||
displayItems: filtered,
|
||||
scrollIntoViewId: '',
|
||||
});
|
||||
},
|
||||
|
||||
onSearchInput(e: WechatMiniprogram.Input) {
|
||||
const keyword = (e.detail.value ?? '').trim();
|
||||
const items = getItemsByCategory(this.data.activeCategoryId);
|
||||
const filtered = filterByKeyword(items, keyword);
|
||||
|
||||
this.setData({
|
||||
searchKeyword: keyword,
|
||||
displayItems: filtered,
|
||||
});
|
||||
},
|
||||
|
||||
onClearSearch() {
|
||||
const items = getItemsByCategory(this.data.activeCategoryId);
|
||||
this.setData({
|
||||
searchKeyword: '',
|
||||
displayItems: items,
|
||||
});
|
||||
},
|
||||
|
||||
onTapItem(e: WechatMiniprogram.TouchEvent) {
|
||||
const path = e.currentTarget.dataset.path as string;
|
||||
const title = e.currentTarget.dataset.title as string;
|
||||
const available = e.currentTarget.dataset.available;
|
||||
|
||||
if (!available || !path) {
|
||||
wx.showToast({
|
||||
title: title ? `${title} 即将上线` : '即将上线',
|
||||
icon: 'none',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (TAB_BAR_PATHS.has(path)) {
|
||||
wx.switchTab({ url: path });
|
||||
return;
|
||||
}
|
||||
|
||||
wx.navigateTo({ url: path });
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '涂鸦丫 - 全部练习分类',
|
||||
path: '/pages/category/category',
|
||||
};
|
||||
},
|
||||
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '涂鸦丫 - 全部练习分类',
|
||||
query: '',
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
<view class="cat-page">
|
||||
<nav-bar title="分类" />
|
||||
|
||||
<view class="cat-body">
|
||||
<view class="cat-search-wrap">
|
||||
<view class="cat-search">
|
||||
<van-icon
|
||||
name="search"
|
||||
size="36rpx"
|
||||
color="rgba(50, 46, 37, 0.45)"
|
||||
class="cat-search__icon" />
|
||||
<input
|
||||
class="cat-search__input"
|
||||
placeholder="{{searchPlaceholder}}"
|
||||
placeholder-class="cat-search__placeholder"
|
||||
value="{{searchKeyword}}"
|
||||
bindinput="onSearchInput"
|
||||
confirm-type="search" />
|
||||
<van-icon
|
||||
wx:if="{{searchKeyword}}"
|
||||
name="clear"
|
||||
size="32rpx"
|
||||
color="rgba(50, 46, 37, 0.35)"
|
||||
bindtap="onClearSearch" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="cat-main">
|
||||
<scroll-view
|
||||
class="cat-sidebar"
|
||||
scroll-y
|
||||
enhanced
|
||||
show-scrollbar="{{false}}">
|
||||
<view
|
||||
wx:for="{{sidebarTabs}}"
|
||||
wx:key="id"
|
||||
class="cat-sidebar__item {{activeCategoryId === item.id ? 'cat-sidebar__item--active' : ''}}"
|
||||
data-id="{{item.id}}"
|
||||
bindtap="onTapCategory">
|
||||
<!-- <text class="cat-sidebar__icon">{{item.icon}}</text> -->
|
||||
<text class="cat-sidebar__name">{{item.name}}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<scroll-view
|
||||
class="cat-content"
|
||||
scroll-y
|
||||
enhanced
|
||||
show-scrollbar="{{false}}"
|
||||
scroll-into-view="{{scrollIntoViewId}}">
|
||||
<view class="cat-content__inner">
|
||||
<view
|
||||
wx:for="{{displayItems}}"
|
||||
wx:key="id"
|
||||
class="cat-card"
|
||||
data-path="{{item.path}}"
|
||||
data-title="{{item.title}}"
|
||||
data-available="{{item.available}}"
|
||||
bindtap="onTapItem">
|
||||
<view
|
||||
class="cat-card__thumb"
|
||||
style="background-color: {{item.thumbBg}}">
|
||||
<image
|
||||
wx:if="{{item.img}}"
|
||||
class="cat-card__thumb-img"
|
||||
src="{{item.img}}"
|
||||
mode="aspectFill" />
|
||||
<text wx:else class="cat-card__thumb-icon"
|
||||
>{{item.icon}}</text
|
||||
>
|
||||
</view>
|
||||
<view class="cat-card__body">
|
||||
<view class="cat-card__header">
|
||||
<text class="cat-card__title"
|
||||
>{{item.title}}</text
|
||||
>
|
||||
</view>
|
||||
<text class="cat-card__subtitle"
|
||||
>{{item.subtitle}}</text
|
||||
>
|
||||
<view class="cat-card__tags">
|
||||
<text class="tag tag--age"
|
||||
>{{item.ageBand}}</text
|
||||
>
|
||||
<text class="tag tag--diff"
|
||||
>{{item.difficulty}}</text
|
||||
>
|
||||
</view>
|
||||
<view class="cat-card__footer">
|
||||
<view class="cat-card__stats">
|
||||
<view class="cat-card__stat">
|
||||
<toy-icon
|
||||
name="heart-o"
|
||||
size="20rpx"
|
||||
color="#7c766a" />
|
||||
<text>{{item.likes}}</text>
|
||||
</view>
|
||||
<view class="cat-card__stat">
|
||||
<toy-icon
|
||||
name="download"
|
||||
size="20rpx"
|
||||
color="#7c766a" />
|
||||
<text>{{item.downloads}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="cat-card__date"
|
||||
>{{item.date}}</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
wx:if="{{displayItems.length === 0}}"
|
||||
class="cat-empty">
|
||||
<text class="cat-empty__icon">🔍</text>
|
||||
<text class="cat-empty__text">没有找到匹配的内容</text>
|
||||
</view>
|
||||
|
||||
<view class="cat-content__footer"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -46,6 +46,7 @@ export type HomeDisplayDataset = {
|
||||
const HOME_CATEGORY_TABS = [
|
||||
{ id: 'all', name: '全部' },
|
||||
{ id: 'math', name: '数感启蒙' },
|
||||
{ id: 'pinyin', name: '汉语拼音' },
|
||||
{ id: 'puzzle', name: '益智游戏' },
|
||||
{ id: 'chinese', name: '趣味识字' },
|
||||
{ id: 'english', name: '英语启蒙' },
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"backgroundColor": "#FEF6E7",
|
||||
"enablePullDownRefresh": false,
|
||||
"usingComponents": {
|
||||
"nav-bar": "/components3.0/nav-bar/nav-bar",
|
||||
"category-tabs": "/components3.0/category-tabs/category-tabs",
|
||||
"van-icon": "@vant/weapp/icon/index"
|
||||
}
|
||||
|
||||
@@ -11,43 +11,6 @@
|
||||
color: @text-secondary;
|
||||
}
|
||||
|
||||
.home-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: fade(@bg-header, 85%);
|
||||
backdrop-filter: blur(40rpx);
|
||||
-webkit-backdrop-filter: blur(40rpx);
|
||||
box-shadow: 0 2rpx 12rpx rgba(50, 46, 37, 0.05);
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.home-nav__inner {
|
||||
height: @nav-inner-height;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.home-nav__logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.home-nav__name {
|
||||
font-size: @fs-nav-title;
|
||||
font-weight: @fw-nav-title;
|
||||
color: @color-nav-title;
|
||||
letter-spacing: @ls-nav-title;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.home-body {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -106,8 +106,6 @@ console.log('HOME_SECTIONS', HOME_SECTIONS);
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: win.statusBarHeight,
|
||||
navBlockHeight: win.statusBarHeight + NAV_INNER_PX,
|
||||
searchPlaceholder: HOME_DATA.searchPlaceholder,
|
||||
tabs: HOME_TABS,
|
||||
activeTab: 'all',
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
<view class="home-page">
|
||||
<view class="home-nav" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="home-nav__inner">
|
||||
<image
|
||||
src="/assets/imgs/doodle-logo.png"
|
||||
mode="aspectFill"
|
||||
class="home-nav__logo" />
|
||||
<text class="home-nav__name">涂鸦丫</text>
|
||||
</view>
|
||||
</view>
|
||||
<nav-bar title="" />
|
||||
|
||||
<view class="home-body" style="padding-top: {{navBlockHeight}}px;">
|
||||
<view class="home-body">
|
||||
<view class="home-search-wrap">
|
||||
<view class="home-search">
|
||||
<van-icon
|
||||
|
||||
@@ -24,12 +24,19 @@
|
||||
"miniprogram": {
|
||||
"list": [
|
||||
{
|
||||
"name": "mathIndex",
|
||||
"pathName": "mathPages/mathDraw/mathDraw",
|
||||
"name": "pages/category/category",
|
||||
"pathName": "pages/category/category",
|
||||
"query": "",
|
||||
"scene": null,
|
||||
"launchMode": "default"
|
||||
},
|
||||
{
|
||||
"name": "mathIndex",
|
||||
"pathName": "mathPages/mathDraw/mathDraw",
|
||||
"query": "",
|
||||
"launchMode": "default",
|
||||
"scene": null
|
||||
},
|
||||
{
|
||||
"name": "focusDraw",
|
||||
"pathName": "focusPages/focusDraw/focusDraw",
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Design System Strategy: Doodle Mini
|
||||
|
||||
## 1. Overview & Creative North Star: "The Sun-Drenched Studio"
|
||||
The creative direction for this design system is **"The Sun-Drenched Studio."** We are moving away from the cold, clinical "educational app" look and toward a space that feels like a physical, tactile craft room bathed in morning light.
|
||||
|
||||
Instead of a rigid, boxed-in grid, we embrace **Organic Asymmetry**. Elements should feel like they were placed on a table by hand, not snapped to a pixel-perfect wireframe. We break the "template" look by using exaggerated corner radii, overlapping "paper" layers, and a hierarchy that prioritizes warmth and play over traditional data density.
|
||||
|
||||
## 2. Colors: Tonal Radiance
|
||||
The palette is anchored by `primary` (#6c5a00) and `primary_container` (#ffd709), creating a "Yaya Yellow" experience that is vibrant yet sophisticated.
|
||||
|
||||
* **The "No-Line" Rule:** Under no circumstances should 1px solid borders be used to separate content. We define boundaries exclusively through background shifts. Use `surface_container_low` (#f8f0e0) for main content areas and `surface` (#fef6e7) for the global backdrop.
|
||||
* **Surface Hierarchy & Nesting:** Treat the UI as stacked sheets of heavy-weight construction paper.
|
||||
* **Level 0:** `background` (#fef6e7) – The desk surface.
|
||||
* **Level 1:** `surface_container` (#f0e7d6) – The worksheet base.
|
||||
* **Level 2:** `surface_container_lowest` (#ffffff) – Active drawing cards or "Paper" modals.
|
||||
* **The Glass & Gradient Rule:** For navigation bars or floating tool palettes, use Glassmorphism. Apply `surface_container_low` at 80% opacity with a `20px` backdrop blur. This ensures the "sunny" background bleeds through, maintaining the "Sun-Drenched" atmosphere.
|
||||
* **Signature Textures:** Main CTAs should not be flat. Apply a subtle linear gradient from `primary_fixed` (#ffd709) to `primary_fixed_dim` (#efc900) at a 145-degree angle to give buttons a "pillowy" 3D volume.
|
||||
|
||||
## 3. Typography: The Friendly Guide
|
||||
We use **Plus Jakarta Sans** exclusively. Its geometric yet soft terminals provide a modern, legible, and approachable voice.
|
||||
|
||||
* **Display & Headlines:** Use `display-lg` (3.5rem) for "Doodle Mini" brand moments. Headlines (`headline-md`) should use a tighter letter-spacing (-0.02em) to feel "hugged" and friendly.
|
||||
* **Body & Labels:** Use `body-lg` for all instructional text. In a children's context, readability is paramount; ensure a line height of at least 1.6x the font size.
|
||||
* **Hierarchy as Personality:** Use `on_secondary_container` (#6d3b00) for sub-headers to provide a warm, "chocolatey" contrast against the yellow, moving away from harsh blacks.
|
||||
|
||||
## 4. Elevation & Depth: Tonal Layering
|
||||
Depth in this system is a result of light and shadow, not lines and strokes.
|
||||
|
||||
* **The Layering Principle:** To lift a component, place a `surface_container_highest` (#e5dcc9) element inside a `surface_container_low` (#f8f0e0) environment. This creates a "recessed" or "elevated" feel through color value alone.
|
||||
* **Ambient Shadows:** Use shadows sparingly. When an object "floats" (like a floating action button), use a shadow color derived from `on_surface` (#322e25) at 6% opacity, with a blur of `32px` and a Y-offset of `8px`. It should look like a soft glow, not a drop shadow.
|
||||
* **The "Ghost Border" Fallback:** If a separator is required for accessibility in input fields, use `outline_variant` (#b3ac9f) at **15% opacity**. It should be felt, not seen.
|
||||
|
||||
## 5. Components: Tactile & Safe
|
||||
Every component must feel "squishy" and safe to touch.
|
||||
|
||||
* **Buttons:**
|
||||
* **Primary:** Uses `primary_container` (#ffd709) with a `full` (9999px) radius.
|
||||
* **States:** On press, scale the button down to 96% size to simulate a physical "click" into the screen.
|
||||
* **Cards & Lists:** Forbid divider lines. Separate list items using a `spacing-3` (1rem) gap and alternating background colors between `surface_container_low` and `surface_container`.
|
||||
* **Input Fields:** Use `surface_container_highest` for the input track. Corners must be `xl` (3rem). Labels sit *above* the field in `title-sm` to ensure children can always see the context.
|
||||
* **Selection Chips:** Use `secondary_container` (#ffc697) for selected states. The roundedness must be `full` to mimic smooth river stones.
|
||||
* **The "Joy" Progress Bar:** A custom component for Doodle Mini. Use a thick track (`1.5rem` height) in `surface_container_highest` with the progress indicator using a gradient of `tertiary` (#006b1b) to `tertiary_fixed` (#91f78e).
|
||||
|
||||
## 6. Do’s and Don’ts
|
||||
|
||||
### Do:
|
||||
* **Do** use `xl` and `full` corner radii for almost everything. Sharp corners are "scary."
|
||||
* **Do** lean into white space. Use `spacing-12` (4rem) between major sections to let the design breathe.
|
||||
* **Do** use `on_tertiary_container` (dark green) for success states; it feels organic and "earthy" against the yellow.
|
||||
|
||||
### Don’t:
|
||||
* **Don’t** use pure black (#000000). Use `on_surface` (#322e25) for all dark text to maintain the warm, sunny tone.
|
||||
* **Don’t** use 1px dividers. If you feel you need one, use a `surface_variant` (#e5dcc9) color block that is `4px` thick with `full` rounded caps.
|
||||
* **Don’t** crowd the interface. If a screen feels busy, increase the background "paper" size and use a scrollable layout instead of shrinking elements.
|
||||
@@ -0,0 +1,248 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="light" lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>分类 - Doodle Mini</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800;900&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"primary": "#6c5a00",
|
||||
"on-secondary": "#fff0e6",
|
||||
"secondary-fixed-dim": "#ffb470",
|
||||
"primary-container": "#ffd709",
|
||||
"inverse-primary": "#ffd709",
|
||||
"outline-variant": "#b3ac9f",
|
||||
"surface-variant": "#e5dcc9",
|
||||
"on-primary": "#fff2cd",
|
||||
"surface-dim": "#dcd4c0",
|
||||
"on-tertiary": "#d1ffc8",
|
||||
"primary-fixed": "#ffd709",
|
||||
"outline": "#7c766a",
|
||||
"on-secondary-container": "#6d3b00",
|
||||
"secondary-container": "#ffc697",
|
||||
"on-surface": "#322e25",
|
||||
"primary-fixed-dim": "#efc900",
|
||||
"tertiary-fixed-dim": "#83e881",
|
||||
"background": "#fef6e7",
|
||||
"surface-bright": "#fef6e7",
|
||||
"error-container": "#f95630",
|
||||
"tertiary-fixed": "#91f78e",
|
||||
"tertiary-container": "#91f78e",
|
||||
"secondary-fixed": "#ffc697",
|
||||
"on-primary-fixed-variant": "#665500",
|
||||
"surface-container-high": "#eae2d0",
|
||||
"on-surface-variant": "#605b50",
|
||||
"tertiary-dim": "#005d16",
|
||||
"surface": "#fef6e7",
|
||||
"on-primary-container": "#5b4b00",
|
||||
"inverse-on-surface": "#a29c8f",
|
||||
"secondary-dim": "#794200",
|
||||
"on-tertiary-container": "#005e17",
|
||||
"on-tertiary-fixed": "#00480f",
|
||||
"on-error": "#ffefec",
|
||||
"inverse-surface": "#110e06",
|
||||
"surface-container-highest": "#e5dcc9",
|
||||
"primary-dim": "#5e4e00",
|
||||
"surface-container": "#f0e7d6",
|
||||
"error": "#b02500",
|
||||
"secondary": "#8a4c00",
|
||||
"surface-tint": "#6c5a00",
|
||||
"on-background": "#322e25",
|
||||
"on-primary-fixed": "#453900",
|
||||
"on-secondary-fixed": "#512a00",
|
||||
"on-tertiary-fixed-variant": "#00691a",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"on-secondary-fixed-variant": "#7a4300",
|
||||
"error-dim": "#b92902",
|
||||
"surface-container-low": "#f8f0e0",
|
||||
"tertiary": "#006b1b",
|
||||
"on-error-container": "#520c00"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "1rem",
|
||||
"lg": "2rem",
|
||||
"xl": "3rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"headline": ["Plus Jakarta Sans"],
|
||||
"display": ["Plus Jakarta Sans"],
|
||||
"body": ["Plus Jakarta Sans"],
|
||||
"label": ["Plus Jakarta Sans"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
.material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
|
||||
.icon-fill { font-variation-settings: 'FILL' 1; }
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background text-on-surface h-screen flex flex-col overflow-hidden">
|
||||
<!-- TopAppBar equivalent for search -->
|
||||
<header class="bg-surface-container-low/80 backdrop-blur-xl z-50 px-4 py-3 flex-none sticky top-0">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex-1 bg-surface-container-highest rounded-full flex items-center px-4 py-2">
|
||||
<span class="material-symbols-outlined text-outline mr-2">search</span>
|
||||
<input class="bg-transparent border-none focus:ring-0 text-body-lg text-on-surface placeholder-on-surface-variant w-full p-0" placeholder="搜索练习纸..." type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Main Content Area -->
|
||||
<main class="flex-1 flex overflow-hidden">
|
||||
<!-- Left Sidebar (Categories) -->
|
||||
<aside class="w-20 md:w-40 bg-surface-container-low flex flex-col overflow-y-auto hide-scrollbar py-2 px-2 gap-1 flex-none rounded-r-[2rem]">
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full text-on-surface-variant hover:bg-surface-container transition-colors">
|
||||
<span class="text-xs md:text-sm font-medium">全部</span>
|
||||
</button>
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full bg-primary-container text-on-primary-container font-bold shadow-sm scale-105 transition-all">
|
||||
<span class="text-xs md:text-sm">数感启蒙</span>
|
||||
</button>
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full text-on-surface-variant hover:bg-surface-container transition-colors">
|
||||
<span class="text-xs md:text-sm font-medium">汉语拼音</span>
|
||||
</button>
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full text-on-surface-variant hover:bg-surface-container transition-colors">
|
||||
<span class="text-xs md:text-sm font-medium">专注力游戏</span>
|
||||
</button>
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full text-on-surface-variant hover:bg-surface-container transition-colors">
|
||||
<span class="text-xs md:text-sm font-medium">趣味识字</span>
|
||||
</button>
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full text-on-surface-variant hover:bg-surface-container transition-colors">
|
||||
<span class="text-xs md:text-sm font-medium">英语启蒙</span>
|
||||
</button>
|
||||
<button class="flex flex-col md:flex-row items-center gap-1 md:gap-3 px-2 md:px-4 py-2 rounded-full text-on-surface-variant hover:bg-surface-container transition-colors">
|
||||
<span class="text-xs md:text-sm font-medium">创意手工</span>
|
||||
</button>
|
||||
</aside>
|
||||
<!-- Right Content List -->
|
||||
<section class="flex-1 overflow-y-auto p-2 md:p-4 bg-background">
|
||||
<div class="flex flex-col gap-2 pb-24">
|
||||
<!-- Card 1 -->
|
||||
<article class="bg-surface-container-lowest rounded-[20px] p-2 flex gap-3 shadow-sm border border-surface-container-high hover:shadow-md transition-shadow">
|
||||
<div class="w-24 shrink-0 rounded-[20px] overflow-hidden bg-surface-container relative">
|
||||
<img alt="Colorful counting beads on a wooden frame, bright sunny lighting, educational" class="w-full h-full object-cover" data-alt="Colorful counting beads on a wooden frame, bright sunny lighting, educational" src="https://lh3.googleusercontent.com/aida-public/AB6AXuC9YDdXdSqQute8UWn7lNaZDuRi4z_BD5HYyM2GKRikRpUs7G-CuwDgAhVqH_6tqN7icRuAhrtmrxbGtrv4T65CdT9ItF68N-9SgNeU1mFQiliih1bt7Cc-nKeyJW2_bgZCg-FOZsl_1S_sD25qt7qBhPsmXT8X3ahauX3VpI3-84vfatabv2wk_TUNOeSt3SdbIpmCHvZR1RqKkyrvaAxPxKIO4uY5v0BhccLxE5L-L96DyM5JAcxxQKRXtnFY2qfvBWMqPT3LC_E"/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between flex-1 overflow-hidden py-1">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-on-surface tracking-tight mb-1 truncate">认识基础图形</h3>
|
||||
<p class="text-on-surface-variant text-xs mb-2 truncate">通过趣味拼贴,让孩子初步感知圆形、方形与三角形的美妙世界。</p>
|
||||
<div class="flex gap-2 mb-1">
|
||||
<span class="px-2 py-0.5 bg-primary-container text-on-primary-container rounded-full text-[10px] font-medium whitespace-nowrap">3-6岁</span>
|
||||
<span class="px-2 py-0.5 bg-surface-container-high rounded-full text-[10px] font-medium text-on-surface-variant whitespace-nowrap">入门</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-[10px] text-outline mt-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">favorite</span> 456</span>
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">download</span> 89</span>
|
||||
</div>
|
||||
<span>2024-05-20</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<!-- Card 2 -->
|
||||
<article class="bg-surface-container-lowest rounded-[20px] p-2 flex gap-3 shadow-sm border border-surface-container-high hover:shadow-md transition-shadow">
|
||||
<div class="w-24 shrink-0 rounded-[20px] overflow-hidden bg-surface-container relative">
|
||||
<img alt="Hand drawn numbers on colorful paper cutouts, messy desk, creative warm light" class="w-full h-full object-cover" data-alt="Hand drawn numbers on colorful paper cutouts, messy desk, creative warm light" src="https://lh3.googleusercontent.com/aida-public/AB6AXuCyTKBE2-6CRjamB6TIUQBymqI1pU6sGFiSLL3meuf0rC8-B-37beMuXbFxJN4bhoA7mZqqYM9QzUAiu-iQmDBLhaayZkJGc0QfTTAAte3Mp7gNwGMy9UDJah-oiJcuY6UUTp0tOTeT-A1Nley0IwNVpeQ2ED1p-NwFwYPojmDcdsfbYRcj5GmnGzR_au03NR8AqFe4o1MtgjRrw4s3_U89bYBmBcpzBTo9BEMsltkwgKbcboX7j6nh2iyyGbCqwtJxSjgzoqbquhA"/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between flex-1 overflow-hidden py-1">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-on-surface tracking-tight mb-1 truncate">数字连连看</h3>
|
||||
<p class="text-on-surface-variant text-xs mb-2 truncate">跟随小兔子走迷宫,在游戏中掌握1-10的数字顺序。</p>
|
||||
<div class="flex gap-2 mb-1">
|
||||
<span class="px-2 py-0.5 bg-tertiary-container text-on-tertiary-container rounded-full text-[10px] font-medium whitespace-nowrap">4-5岁</span>
|
||||
<span class="px-2 py-0.5 bg-surface-container-high rounded-full text-[10px] font-medium text-on-surface-variant whitespace-nowrap">进阶</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-[10px] text-outline mt-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">favorite</span> 230</span>
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">download</span> 45</span>
|
||||
</div>
|
||||
<span>2024-05-18</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<!-- Card 3 -->
|
||||
<article class="bg-surface-container-lowest rounded-[20px] p-2 flex gap-3 shadow-sm border border-surface-container-high hover:shadow-md transition-shadow">
|
||||
<div class="w-24 shrink-0 rounded-[20px] overflow-hidden bg-surface-container relative">
|
||||
<img alt="Wooden abacus with colorful beads on a bright yellow desk, soft shadows" class="w-full h-full object-cover" data-alt="Wooden abacus with colorful beads on a bright yellow desk, soft shadows" src="https://lh3.googleusercontent.com/aida-public/AB6AXuCZTJ8e802cJ_5FfgED6WRGmFayr9x84nGvf4F-Prhl0jI8Cl0jJAMVtNM2ccSAgCM3XTBTSrMUPL1Ez2W40lJGQsopbLz0Lkm6cNMbPpI0xluIUX5iWqB-BsMCoiOAFN0Zrn5_7wwT1Y14CqEt7gjjPdk9HgHWM5fNu2Fxn-vSvbAZdFGGAsanZQkQ_pjfjQX0vgLSwT13Zo0uCy50CskhRd-NB9bCG4NEby-b7lht5gHvBco21O8_IRh1Mal3jWmubIen-2KxGb4"/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between flex-1 overflow-hidden py-1">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-on-surface tracking-tight mb-1 truncate">加法启蒙</h3>
|
||||
<p class="text-on-surface-variant text-xs mb-2 truncate">结合生动插画,帮助孩子轻松记忆基础加法运算。</p>
|
||||
<div class="flex gap-2 mb-1">
|
||||
<span class="px-2 py-0.5 bg-secondary-container text-on-secondary-container rounded-full text-[10px] font-medium whitespace-nowrap">5-7岁</span>
|
||||
<span class="px-2 py-0.5 bg-surface-container-high rounded-full text-[10px] font-medium text-on-surface-variant whitespace-nowrap">挑战</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-[10px] text-outline mt-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">favorite</span> 890</span>
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">download</span> 156</span>
|
||||
</div>
|
||||
<span>2024-05-15</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<!-- Card 4 -->
|
||||
<article class="bg-surface-container-lowest rounded-[20px] p-2 flex gap-3 shadow-sm border border-surface-container-high hover:shadow-md transition-shadow">
|
||||
<div class="w-24 shrink-0 rounded-[20px] overflow-hidden bg-surface-container relative">
|
||||
<img alt="Comic style colorful abstract shapes on white paper, playful child drawing" class="w-full h-full object-cover" data-alt="Comic style colorful abstract shapes on white paper, playful child drawing" src="https://lh3.googleusercontent.com/aida-public/AB6AXuDNI9UXLOiyKRJscHCtr4bBERSio7GZGyntl-0IkJW-OHd-3hdwx2bL00mpzqAHVVu-O2944uDbQ8Zy1la27ucH2vIFOz01EEe5lCsV4aWSr7KUIQVqvMP8kSq0kPBiJV2EJCgZJp-YY3q4A9PPNRlq5i9qbj01ZJipPmG71aVYjRrz4JBt7J8V8Zl5OQH7kU7HgaT-NNVDCTXnZcmVQXCQtJwiEExpJkrAb7jPi4V1QpMDFIIpqdtD1cHVDOvO7418cr24yRaGPK8"/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between flex-1 overflow-hidden py-1">
|
||||
<div>
|
||||
<h3 class="text-base font-bold text-on-surface tracking-tight mb-1 truncate">找规律</h3>
|
||||
<p class="text-on-surface-variant text-xs mb-2 truncate">简单的剪贴纸工艺,培养孩子的动手能力与色彩感知。</p>
|
||||
<div class="flex gap-2 mb-1">
|
||||
<span class="px-2 py-0.5 bg-primary-container text-on-primary-container rounded-full text-[10px] font-medium whitespace-nowrap">4-6岁</span>
|
||||
<span class="px-2 py-0.5 bg-surface-container-high rounded-full text-[10px] font-medium text-on-surface-variant whitespace-nowrap">逻辑</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-[10px] text-outline mt-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">favorite</span> 512</span>
|
||||
<span class="flex items-center gap-0.5"><span class="material-symbols-outlined text-[14px]">download</span> 110</span>
|
||||
</div>
|
||||
<span>2024-05-10</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<!-- BottomNavBar -->
|
||||
<nav class="bg-surface-container-low/90 backdrop-blur-xl pb-safe pt-2 px-6 flex justify-between items-center fixed bottom-0 w-full z-50 md:hidden">
|
||||
<button class="flex flex-col items-center p-2 text-primary">
|
||||
<span class="material-symbols-outlined icon-fill">explore</span>
|
||||
<span class="text-xs font-bold mt-1">发现</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center p-2 text-on-surface-variant">
|
||||
<span class="material-symbols-outlined">filter_list</span>
|
||||
<span class="text-xs font-medium mt-1">分龄</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center p-2 text-on-surface-variant">
|
||||
<span class="material-symbols-outlined">favorite</span>
|
||||
<span class="text-xs font-medium mt-1">收藏</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center p-2 text-on-surface-variant">
|
||||
<span class="material-symbols-outlined">person</span>
|
||||
<span class="text-xs font-medium mt-1">我的</span>
|
||||
</button>
|
||||
</nav>
|
||||
</body></html>
|
||||
|
After Width: | Height: | Size: 359 KiB |