重命名前端项目目录:web-flowith -> web
- 将前端项目目录从 web-flowith 重命名为 web,使目录结构更简洁 - 保持所有前端代码和配置文件不变 - 统一项目目录命名规范
This commit is contained in:
@@ -0,0 +1,778 @@
|
||||
<template>
|
||||
<div class="life-trajectory-page">
|
||||
<!-- 头部 -->
|
||||
<header class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
<a-button type="text" @click="$router.back()" class="back-btn">
|
||||
<ArrowLeftOutlined />
|
||||
</a-button>
|
||||
<h1 class="page-title">人生轨迹</h1>
|
||||
</div>
|
||||
<a-button type="primary" @click="showNewEventModal = true" class="new-event-btn">
|
||||
<PlusOutlined />
|
||||
添加事件
|
||||
</a-button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 主要内容 -->
|
||||
<main class="page-main">
|
||||
<div class="container">
|
||||
<!-- 筛选控制 -->
|
||||
<div class="filter-section">
|
||||
<a-input-search
|
||||
v-model:value="searchKeyword"
|
||||
placeholder="搜索事件..."
|
||||
style="width: 300px"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
<a-select
|
||||
v-model:value="typeFilter"
|
||||
placeholder="类型筛选"
|
||||
style="width: 120px"
|
||||
@change="handleFilterChange"
|
||||
>
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option value="milestone">里程碑</a-select-option>
|
||||
<a-select-option value="achievement">成就</a-select-option>
|
||||
<a-select-option value="memory">回忆</a-select-option>
|
||||
<a-select-option value="goal">目标</a-select-option>
|
||||
</a-select>
|
||||
<a-range-picker
|
||||
v-model:value="dateRange"
|
||||
@change="handleDateRangeChange"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 时间线视图 -->
|
||||
<div class="timeline-container">
|
||||
<a-timeline class="life-timeline">
|
||||
<a-timeline-item
|
||||
v-for="event in filteredEvents"
|
||||
:key="event.id"
|
||||
:color="getEventColor(event.type)"
|
||||
class="timeline-item"
|
||||
>
|
||||
<template #dot>
|
||||
<div class="timeline-dot" :class="`dot-${event.type}`">
|
||||
<component :is="getEventIcon(event.type)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="event-card" @click="viewEventDetail(event)">
|
||||
<div class="event-header">
|
||||
<div class="event-meta">
|
||||
<a-tag :color="getEventColor(event.type)" size="small">
|
||||
{{ getEventTypeText(event.type) }}
|
||||
</a-tag>
|
||||
<span class="event-date">{{ formatTime.date(event.date) }}</span>
|
||||
<div class="importance-stars">
|
||||
<StarFilled
|
||||
v-for="i in event.importance"
|
||||
:key="i"
|
||||
class="star-filled"
|
||||
/>
|
||||
<StarOutlined
|
||||
v-for="i in (5 - event.importance)"
|
||||
:key="i + event.importance"
|
||||
class="star-empty"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<a-dropdown @click.stop>
|
||||
<a-button type="text" size="small">
|
||||
<MoreOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="editEvent(event)">
|
||||
<EditOutlined />
|
||||
编辑
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="deleteEvent(event.id)" danger>
|
||||
<DeleteOutlined />
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="event-content">
|
||||
<h3 class="event-title">{{ event.title }}</h3>
|
||||
<p class="event-description" v-if="event.description">
|
||||
{{ event.description }}
|
||||
</p>
|
||||
|
||||
<div class="event-tags" v-if="event.tags && event.tags.length">
|
||||
<a-tag
|
||||
v-for="tag in event.tags.slice(0, 3)"
|
||||
:key="tag"
|
||||
size="small"
|
||||
class="event-tag"
|
||||
>
|
||||
{{ tag }}
|
||||
</a-tag>
|
||||
<span v-if="event.tags.length > 3" class="more-tags">
|
||||
+{{ event.tags.length - 3 }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div v-if="filteredEvents.length === 0" class="empty-state">
|
||||
<a-empty
|
||||
description="暂无人生事件记录"
|
||||
:image="Empty.PRESENTED_IMAGE_SIMPLE"
|
||||
>
|
||||
<a-button type="primary" @click="showNewEventModal = true">
|
||||
记录第一个事件
|
||||
</a-button>
|
||||
</a-empty>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 新建事件模态框 -->
|
||||
<a-modal
|
||||
v-model:open="showNewEventModal"
|
||||
title="添加人生事件"
|
||||
@ok="createEvent"
|
||||
@cancel="resetEventForm"
|
||||
:confirm-loading="isCreating"
|
||||
width="600px"
|
||||
>
|
||||
<a-form :model="eventForm" layout="vertical">
|
||||
<a-form-item label="事件标题" required>
|
||||
<a-input
|
||||
v-model:value="eventForm.title"
|
||||
placeholder="请输入事件标题"
|
||||
:maxlength="50"
|
||||
show-count
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="事件描述">
|
||||
<a-textarea
|
||||
v-model:value="eventForm.description"
|
||||
placeholder="请输入事件描述(可选)"
|
||||
:rows="3"
|
||||
:maxlength="300"
|
||||
show-count
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="事件类型" required>
|
||||
<a-select v-model:value="eventForm.type" placeholder="选择事件类型">
|
||||
<a-select-option value="milestone">里程碑</a-select-option>
|
||||
<a-select-option value="achievement">成就</a-select-option>
|
||||
<a-select-option value="memory">回忆</a-select-option>
|
||||
<a-select-option value="goal">目标</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="事件日期" required>
|
||||
<a-date-picker
|
||||
v-model:value="eventForm.date"
|
||||
placeholder="选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="重要程度">
|
||||
<a-rate v-model:value="eventForm.importance" :count="5" />
|
||||
<div class="importance-desc">
|
||||
<span v-if="eventForm.importance === 1">一般重要</span>
|
||||
<span v-else-if="eventForm.importance === 2">比较重要</span>
|
||||
<span v-else-if="eventForm.importance === 3">重要</span>
|
||||
<span v-else-if="eventForm.importance === 4">非常重要</span>
|
||||
<span v-else-if="eventForm.importance === 5">极其重要</span>
|
||||
<span v-else>请选择重要程度</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="标签">
|
||||
<div class="tags-input-section">
|
||||
<a-input
|
||||
v-model:value="newTagInput"
|
||||
placeholder="添加标签,按回车确认"
|
||||
@press-enter="addTag"
|
||||
style="margin-bottom: 8px"
|
||||
/>
|
||||
<div class="selected-tags" v-if="eventForm.tags.length">
|
||||
<a-tag
|
||||
v-for="tag in eventForm.tags"
|
||||
:key="tag"
|
||||
closable
|
||||
@close="removeTag(tag)"
|
||||
color="blue"
|
||||
>
|
||||
{{ tag }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 事件详情模态框 -->
|
||||
<a-modal
|
||||
v-model:open="showDetailModal"
|
||||
:title="selectedEvent?.title"
|
||||
:footer="null"
|
||||
width="700px"
|
||||
>
|
||||
<div v-if="selectedEvent" class="event-detail">
|
||||
<div class="detail-header">
|
||||
<div class="detail-meta">
|
||||
<a-tag :color="getEventColor(selectedEvent.type)" size="large">
|
||||
{{ getEventTypeText(selectedEvent.type) }}
|
||||
</a-tag>
|
||||
<span class="detail-date">{{ formatTime.standard(selectedEvent.date) }}</span>
|
||||
</div>
|
||||
<div class="detail-importance">
|
||||
<span class="importance-label">重要程度:</span>
|
||||
<a-rate :value="selectedEvent.importance" disabled />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-description" v-if="selectedEvent.description">
|
||||
<h4>详细描述</h4>
|
||||
<p>{{ selectedEvent.description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="detail-tags" v-if="selectedEvent.tags && selectedEvent.tags.length">
|
||||
<h4>相关标签</h4>
|
||||
<div class="tags-list">
|
||||
<a-tag
|
||||
v-for="tag in selectedEvent.tags"
|
||||
:key="tag"
|
||||
color="blue"
|
||||
>
|
||||
{{ tag }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-actions">
|
||||
<a-button type="primary" @click="editEvent(selectedEvent)">
|
||||
<EditOutlined />
|
||||
编辑事件
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
PlusOutlined,
|
||||
MoreOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
StarFilled,
|
||||
StarOutlined,
|
||||
TrophyOutlined,
|
||||
FlagOutlined,
|
||||
HeartOutlined,
|
||||
BulbOutlined,
|
||||
} from '@ant-design/icons-vue'
|
||||
import { Empty, message } from 'ant-design-vue'
|
||||
import { formatTime } from '@/utils'
|
||||
import type { LifeEvent } from '@/types'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
|
||||
// 响应式数据
|
||||
const showNewEventModal = ref(false)
|
||||
const showDetailModal = ref(false)
|
||||
const isCreating = ref(false)
|
||||
const searchKeyword = ref('')
|
||||
const typeFilter = ref('')
|
||||
const dateRange = ref<[Dayjs, Dayjs] | null>(null)
|
||||
const newTagInput = ref('')
|
||||
const selectedEvent = ref<LifeEvent | null>(null)
|
||||
|
||||
// 事件数据
|
||||
const events = ref<LifeEvent[]>([
|
||||
{
|
||||
id: '1',
|
||||
title: '大学毕业',
|
||||
description: '完成了四年的大学学习,获得了计算机科学学士学位',
|
||||
date: '2020-06-15',
|
||||
type: 'milestone',
|
||||
importance: 5,
|
||||
tags: ['教育', '毕业', '成长']
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '第一份工作',
|
||||
description: '加入了一家科技公司,开始了职业生涯',
|
||||
date: '2020-08-01',
|
||||
type: 'achievement',
|
||||
importance: 4,
|
||||
tags: ['工作', '职业', '新开始']
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '学会游泳',
|
||||
description: '终于克服了对水的恐惧,学会了游泳',
|
||||
date: '2021-07-20',
|
||||
type: 'achievement',
|
||||
importance: 3,
|
||||
tags: ['运动', '技能', '突破']
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '第一次独自旅行',
|
||||
description: '一个人去了云南,体验了不同的文化和风景',
|
||||
date: '2022-03-10',
|
||||
type: 'memory',
|
||||
importance: 4,
|
||||
tags: ['旅行', '独立', '体验']
|
||||
}
|
||||
])
|
||||
|
||||
// 表单数据
|
||||
const eventForm = reactive({
|
||||
title: '',
|
||||
description: '',
|
||||
type: 'milestone' as LifeEvent['type'],
|
||||
date: null as Dayjs | null,
|
||||
importance: 3 as LifeEvent['importance'],
|
||||
tags: [] as string[]
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const filteredEvents = computed(() => {
|
||||
let result = [...events.value]
|
||||
|
||||
// 关键词搜索
|
||||
if (searchKeyword.value) {
|
||||
result = result.filter(event =>
|
||||
event.title.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
|
||||
event.description?.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
|
||||
event.tags?.some(tag => tag.toLowerCase().includes(searchKeyword.value.toLowerCase()))
|
||||
)
|
||||
}
|
||||
|
||||
// 类型筛选
|
||||
if (typeFilter.value) {
|
||||
result = result.filter(event => event.type === typeFilter.value)
|
||||
}
|
||||
|
||||
// 日期范围筛选
|
||||
if (dateRange.value && dateRange.value.length === 2) {
|
||||
const [start, end] = dateRange.value
|
||||
result = result.filter(event => {
|
||||
const eventDate = new Date(event.date)
|
||||
return eventDate >= start.toDate() && eventDate <= end.toDate()
|
||||
})
|
||||
}
|
||||
|
||||
// 按日期排序(最新的在前)
|
||||
return result.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||
})
|
||||
|
||||
// 方法
|
||||
const getEventColor = (type: LifeEvent['type']) => {
|
||||
const colors = {
|
||||
milestone: 'blue',
|
||||
achievement: 'green',
|
||||
memory: 'orange',
|
||||
goal: 'purple'
|
||||
}
|
||||
return colors[type]
|
||||
}
|
||||
|
||||
const getEventTypeText = (type: LifeEvent['type']) => {
|
||||
const texts = {
|
||||
milestone: '里程碑',
|
||||
achievement: '成就',
|
||||
memory: '回忆',
|
||||
goal: '目标'
|
||||
}
|
||||
return texts[type]
|
||||
}
|
||||
|
||||
const getEventIcon = (type: LifeEvent['type']) => {
|
||||
const icons = {
|
||||
milestone: FlagOutlined,
|
||||
achievement: TrophyOutlined,
|
||||
memory: HeartOutlined,
|
||||
goal: BulbOutlined
|
||||
}
|
||||
return icons[type]
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
// 搜索逻辑已在计算属性中处理
|
||||
}
|
||||
|
||||
const handleFilterChange = () => {
|
||||
// 筛选逻辑已在计算属性中处理
|
||||
}
|
||||
|
||||
const handleDateRangeChange = () => {
|
||||
// 日期范围筛选逻辑已在计算属性中处理
|
||||
}
|
||||
|
||||
const createEvent = async () => {
|
||||
if (!eventForm.title.trim()) {
|
||||
message.warning('请输入事件标题')
|
||||
return
|
||||
}
|
||||
if (!eventForm.date) {
|
||||
message.warning('请选择事件日期')
|
||||
return
|
||||
}
|
||||
|
||||
isCreating.value = true
|
||||
try {
|
||||
const newEvent: LifeEvent = {
|
||||
id: Date.now().toString(),
|
||||
title: eventForm.title.trim(),
|
||||
description: eventForm.description.trim() || undefined,
|
||||
date: eventForm.date.format('YYYY-MM-DD'),
|
||||
type: eventForm.type,
|
||||
importance: eventForm.importance,
|
||||
tags: eventForm.tags.length ? eventForm.tags : undefined
|
||||
}
|
||||
|
||||
events.value.push(newEvent)
|
||||
message.success('事件添加成功')
|
||||
showNewEventModal.value = false
|
||||
resetEventForm()
|
||||
} catch (error) {
|
||||
message.error('添加失败,请重试')
|
||||
} finally {
|
||||
isCreating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resetEventForm = () => {
|
||||
eventForm.title = ''
|
||||
eventForm.description = ''
|
||||
eventForm.type = 'milestone'
|
||||
eventForm.date = null
|
||||
eventForm.importance = 3
|
||||
eventForm.tags = []
|
||||
newTagInput.value = ''
|
||||
}
|
||||
|
||||
const addTag = () => {
|
||||
const tag = newTagInput.value.trim()
|
||||
if (tag && !eventForm.tags.includes(tag)) {
|
||||
eventForm.tags.push(tag)
|
||||
newTagInput.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const removeTag = (tag: string) => {
|
||||
const index = eventForm.tags.indexOf(tag)
|
||||
if (index > -1) {
|
||||
eventForm.tags.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const viewEventDetail = (event: LifeEvent) => {
|
||||
selectedEvent.value = event
|
||||
showDetailModal.value = true
|
||||
}
|
||||
|
||||
const editEvent = (event: LifeEvent) => {
|
||||
// TODO: 实现编辑功能
|
||||
message.info('编辑功能开发中...')
|
||||
}
|
||||
|
||||
const deleteEvent = (id: string) => {
|
||||
const index = events.value.findIndex(e => e.id === id)
|
||||
if (index > -1) {
|
||||
events.value.splice(index, 1)
|
||||
message.success('事件删除成功')
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
// 初始化数据
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.life-trajectory-page {
|
||||
min-height: 100vh;
|
||||
background: $light-gray;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background: white;
|
||||
box-shadow: $shadow-sm;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $spacing-md $spacing-lg;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
color: $text-medium;
|
||||
|
||||
&:hover {
|
||||
color: $tech-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $text-dark;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.new-event-btn {
|
||||
border-radius: $border-radius-full;
|
||||
}
|
||||
|
||||
.page-main {
|
||||
padding: $spacing-lg;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
margin-bottom: $spacing-xl;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.timeline-container {
|
||||
.life-timeline {
|
||||
:deep(.ant-timeline-item-tail) {
|
||||
border-left: 2px solid #e8e8e8;
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
margin-bottom: $spacing-xl;
|
||||
}
|
||||
|
||||
.timeline-dot {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: $font-size-base;
|
||||
|
||||
&.dot-milestone {
|
||||
background: #1890ff;
|
||||
}
|
||||
|
||||
&.dot-achievement {
|
||||
background: #52c41a;
|
||||
}
|
||||
|
||||
&.dot-memory {
|
||||
background: #fa8c16;
|
||||
}
|
||||
|
||||
&.dot-goal {
|
||||
background: #722ed1;
|
||||
}
|
||||
}
|
||||
|
||||
.event-card {
|
||||
background: white;
|
||||
border-radius: $border-radius-lg;
|
||||
padding: $spacing-lg;
|
||||
box-shadow: $shadow-sm;
|
||||
cursor: pointer;
|
||||
transition: all $transition-normal;
|
||||
margin-left: $spacing-md;
|
||||
|
||||
&:hover {
|
||||
box-shadow: $shadow-md;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.event-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: $spacing-md;
|
||||
|
||||
.event-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-xs;
|
||||
|
||||
.event-date {
|
||||
color: $text-medium;
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
|
||||
.importance-stars {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
|
||||
.star-filled {
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.star-empty {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.event-content {
|
||||
.event-title {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $text-dark;
|
||||
margin-bottom: $spacing-sm;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.event-description {
|
||||
color: $text-medium;
|
||||
line-height: 1.6;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.event-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $spacing-xs;
|
||||
|
||||
.event-tag {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.more-tags {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: $spacing-xxl;
|
||||
}
|
||||
|
||||
// 模态框样式
|
||||
.tags-input-section {
|
||||
.selected-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $spacing-xs;
|
||||
}
|
||||
}
|
||||
|
||||
.importance-desc {
|
||||
margin-top: $spacing-xs;
|
||||
font-size: $font-size-sm;
|
||||
color: $text-medium;
|
||||
}
|
||||
|
||||
.event-detail {
|
||||
.detail-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: $spacing-lg;
|
||||
padding-bottom: $spacing-md;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.detail-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-xs;
|
||||
|
||||
.detail-date {
|
||||
color: $text-medium;
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-importance {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
|
||||
.importance-label {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-description,
|
||||
.detail-tags {
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
h4 {
|
||||
font-size: $font-size-base;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $text-dark;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $text-dark;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $spacing-xs;
|
||||
}
|
||||
|
||||
.detail-actions {
|
||||
padding-top: $spacing-md;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user