You've already forked SmartisanNote.Remake
新增 便签删除功能;
优化便签列表页布局;
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div class="code-fun-flex-row code-fun-justify-center code-fun-relative list-item_7">
|
||||
<!-- 删除按钮 -->
|
||||
<button class="btn_delete" @click.stop="handleDelete" :style="deleteButtonStyle">
|
||||
<span>删除</span>
|
||||
</button>
|
||||
<!-- 便签条 -->
|
||||
<div class="code-fun-flex-col code-fun-relative section_17" @click="handlePress" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd" :style="{ transform: `translateX(${slideOffset}px)` }">
|
||||
<div class="code-fun-flex-row code-fun-justify-between">
|
||||
@@ -19,10 +23,6 @@
|
||||
<img v-if="hasImage" class="image_28" src="/assets/icons/drawable-xxhdpi/list_item_image_icon.png" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 删除按钮 -->
|
||||
<button class="btn_delete">
|
||||
<span>删除</span>
|
||||
</button>
|
||||
<!-- 便签夹未滑动状态 -->
|
||||
<img class="image_27 pos_18" :src="isSliding ? '/assets/icons/drawable-xxhdpi/note_item_clip_up.png' : '/assets/icons/drawable-xxhdpi/note_item_clip_normal.png'" />
|
||||
</div>
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { formatDateTime } from '../utils/dateUtils'
|
||||
|
||||
const props = defineProps({
|
||||
content: {
|
||||
@@ -86,11 +85,8 @@ const formattedDate = computed(() => {
|
||||
// 处理显示内容,过滤HTML标签并只显示第一行
|
||||
// 用于在便签列表中显示便签的预览内容
|
||||
const displayContent = computed(() => {
|
||||
console.log('NoteItem content:', props.content)
|
||||
// 过滤HTML标签,只保留纯文本内容
|
||||
let text = props.content.replace(/<[^>]*>/g, '')
|
||||
console.log('NoteItem text without HTML:', text)
|
||||
|
||||
// 处理换行符,统一为\n
|
||||
text = text.replace(/\\n/g, '\n')
|
||||
|
||||
@@ -101,6 +97,14 @@ const displayContent = computed(() => {
|
||||
return lines[0]?.trim() || '无内容'
|
||||
})
|
||||
|
||||
// 计算删除按钮的样式
|
||||
const deleteButtonStyle = computed(() => {
|
||||
return {
|
||||
opacity: isSlided.value ? 1 : 0,
|
||||
pointerEvents: isSlided.value ? 'auto' : 'none',
|
||||
}
|
||||
})
|
||||
|
||||
// 滑动阈值(删除按钮宽度)
|
||||
// 当滑动距离超过此值时,显示删除按钮
|
||||
const SLIDE_THRESHOLD = 64 // 4rem 转换为 px
|
||||
@@ -133,9 +137,12 @@ const handleTopToggle = () => {
|
||||
// 处理删除事件
|
||||
// 点击删除按钮时调用父组件传递的回调函数
|
||||
const handleDelete = () => {
|
||||
if (props.onDelete) {
|
||||
props.onDelete()
|
||||
}
|
||||
// 阻止事件冒泡,避免触发便签条的点击事件
|
||||
props.onDelete()
|
||||
// 重置滑动状态
|
||||
slideOffset.value = 0
|
||||
isSliding.value = false
|
||||
isSlided.value = false
|
||||
}
|
||||
|
||||
// 触摸开始事件处理函数
|
||||
@@ -224,6 +231,7 @@ const handleTouchEnd = () => {
|
||||
text-align: right;
|
||||
border: none;
|
||||
padding: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
span {
|
||||
margin-right: 0.7rem;
|
||||
font-size: 0.6rem;
|
||||
|
||||
@@ -1,67 +1,54 @@
|
||||
<template>
|
||||
<ion-app>
|
||||
<ion-page>
|
||||
<div class="container">
|
||||
<Header
|
||||
:title="headerTitle"
|
||||
:onAction="handleHeaderAction"
|
||||
actionIcon="create"
|
||||
leftType="settings"
|
||||
:onLeftAction="handleSettingsPress"
|
||||
:onFolderToggle="handleFolderToggle"
|
||||
:isFolderExpanded="isFolderExpanded"
|
||||
:onTitlePress="handleFolderToggle" />
|
||||
<ion-content class="content">
|
||||
<Header
|
||||
:title="headerTitle"
|
||||
:onAction="handleHeaderAction"
|
||||
actionIcon="create"
|
||||
leftType="settings"
|
||||
:onLeftAction="handleSettingsPress"
|
||||
:onFolderToggle="handleFolderToggle"
|
||||
:isFolderExpanded="isFolderExpanded"
|
||||
:onTitlePress="handleFolderToggle"
|
||||
slot="fixed" />
|
||||
|
||||
<!-- 悬浮文件夹列表 - 使用绝对定位实现 -->
|
||||
<div v-if="isFolderExpanded" class="folder-list">
|
||||
<FolderManage
|
||||
:allCount="allNotesCount"
|
||||
:starredCount="starredNotesCount"
|
||||
:trashCount="trashNotesCount"
|
||||
:archiveCount="0"
|
||||
:selectedFolder="currentFolder"
|
||||
:onAllClick="handleAllNotesClick"
|
||||
:onStarredClick="handleStarredNotesClick"
|
||||
:onTrashClick="handleTrashNotesClick" />
|
||||
</div>
|
||||
<!-- 点击外部区域收起文件夹列表的覆盖层 -->
|
||||
<div v-if="isFolderExpanded" @click="() => setIsFolderExpanded(false)" class="folder-overlay"></div>
|
||||
|
||||
<div class="search-container">
|
||||
<SearchBar v-model="searchQuery" @search="handleSearch" @clear="handleClearSearch" @focus="handleSearchFocus" @blur="handleSearchBlur" />
|
||||
</div>
|
||||
|
||||
<div class="notes-container">
|
||||
<div v-for="note in filteredAndSortedNotes" :key="note.id" class="note-item">
|
||||
<NoteItem
|
||||
:title="note.title"
|
||||
:content="note.content"
|
||||
:date="formatDate(note.updatedAt)"
|
||||
:isStarred="note.isStarred"
|
||||
:isTop="note.isTop || false"
|
||||
:hasImage="note.hasImage || false"
|
||||
:onPress="() => handleNotePress(note.id)"
|
||||
:onStarToggle="() => handleStarToggle(note.id)"
|
||||
:onTopToggle="() => handleTopToggle(note.id)"
|
||||
:onDelete="() => handleDeleteNote(note.id)" />
|
||||
<!-- 悬浮文件夹列表 - 使用绝对定位实现 -->
|
||||
<div v-if="isFolderExpanded" class="folder-list">
|
||||
<FolderManage
|
||||
:allCount="allNotesCount"
|
||||
:starredCount="starredNotesCount"
|
||||
:trashCount="trashNotesCount"
|
||||
:archiveCount="0"
|
||||
:selectedFolder="currentFolder"
|
||||
:onAllClick="handleAllNotesClick"
|
||||
:onStarredClick="handleStarredNotesClick"
|
||||
:onTrashClick="handleTrashNotesClick" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 点击外部区域收起文件夹列表的覆盖层 -->
|
||||
<div v-if="isFolderExpanded" @click="() => setIsFolderExpanded(false)" class="folder-overlay"></div>
|
||||
<div class="search-container">
|
||||
<SearchBar v-model="searchQuery" @search="handleSearch" @clear="handleClearSearch" @focus="handleSearchFocus" @blur="handleSearchBlur" />
|
||||
</div>
|
||||
|
||||
<div class="notes-container">
|
||||
<div v-for="note in filteredAndSortedNotes" :key="note.id" class="note-item">
|
||||
<NoteItem
|
||||
:title="note.title"
|
||||
:content="note.content"
|
||||
:date="formatDate(note.updatedAt)"
|
||||
:isStarred="note.isStarred"
|
||||
:isTop="note.isTop || false"
|
||||
:hasImage="note.hasImage || false"
|
||||
:onPress="() => handleNotePress(note.id)"
|
||||
:onStarToggle="() => handleStarToggle(note.id)"
|
||||
:onTopToggle="() => handleTopToggle(note.id)"
|
||||
:onDelete="() => confirmDeleteNote(note.id)" />
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</div>
|
||||
<ion-alert
|
||||
:is-open="showAlert"
|
||||
@didDismiss="() => setShowAlert(false)"
|
||||
header="删除便签"
|
||||
message="确定要删除这个便签吗?"
|
||||
:buttons="[
|
||||
{
|
||||
text: '取消',
|
||||
role: 'cancel',
|
||||
},
|
||||
{
|
||||
text: '删除',
|
||||
handler: confirmDeleteNote,
|
||||
},
|
||||
]"></ion-alert>
|
||||
</ion-app>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -73,6 +60,7 @@ import Header from '../components/Header.vue'
|
||||
import FolderManage from '../components/FolderManage.vue'
|
||||
import SearchBar from '../components/SearchBar.vue'
|
||||
import { formatNoteListDate } from '../utils/dateUtils'
|
||||
import { IonContent, IonPage } from '@ionic/vue'
|
||||
|
||||
const store = useAppStore()
|
||||
const router = useRouter()
|
||||
@@ -94,7 +82,6 @@ const searchQuery = ref('')
|
||||
const sortBy = ref('date') // 排序方式:'date'(按日期)、'title'(按标题)、'starred'(按星标)
|
||||
const isFolderExpanded = ref(false) // 文件夹列表是否展开
|
||||
const currentFolder = ref('all') // 当前选中的文件夹,默认是"全部便签"
|
||||
const showAlert = ref(false)
|
||||
const noteToDelete = ref(null)
|
||||
|
||||
// 计算加星便签数量(未删除的)
|
||||
@@ -197,11 +184,6 @@ const handleHeaderAction = actionType => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteNote = noteId => {
|
||||
noteToDelete.value = noteId
|
||||
showAlert.value = true
|
||||
}
|
||||
|
||||
const handleStarToggle = async noteId => {
|
||||
const note = store.notes.find(n => n.id === noteId)
|
||||
if (note) {
|
||||
@@ -226,7 +208,8 @@ const handleTopToggle = async noteId => {
|
||||
}
|
||||
}
|
||||
|
||||
const confirmDeleteNote = async () => {
|
||||
const confirmDeleteNote = async noteId => {
|
||||
noteToDelete.value = noteId
|
||||
if (noteToDelete.value) {
|
||||
try {
|
||||
// 检查当前是否在回收站中
|
||||
@@ -244,7 +227,6 @@ const confirmDeleteNote = async () => {
|
||||
console.error('Failed to delete note:', error)
|
||||
}
|
||||
}
|
||||
showAlert.value = false
|
||||
}
|
||||
|
||||
// 处理排序方式切换
|
||||
@@ -347,10 +329,6 @@ const setSearchQuery = query => {
|
||||
searchQuery.value = query
|
||||
}
|
||||
|
||||
const setShowAlert = show => {
|
||||
showAlert.value = show
|
||||
}
|
||||
|
||||
const notes = computed(() => store.notes)
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@@ -383,6 +361,11 @@ const notes = computed(() => store.notes)
|
||||
background-color: transparent;
|
||||
z-index: 99;
|
||||
}
|
||||
.content {
|
||||
--background: transparent;
|
||||
--padding-top: 4.5rem;
|
||||
--padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
padding: 0.8rem 0.5rem;
|
||||
|
||||
Reference in New Issue
Block a user