feat: add DropZone and App layout skeleton

This commit is contained in:
timeTable2 dev
2026-07-13 18:39:15 +08:00
parent 361cc38384
commit 906679fc11
2 changed files with 141 additions and 3 deletions

View File

@@ -1,9 +1,48 @@
<script setup>
import { useCalendar } from './composables/useCalendar.js'
import DropZone from './components/DropZone.vue'
const { isLoaded } = useCalendar()
</script>
<template>
<div style="font-family: sans-serif; padding: 40px;">
<h1>📅 ICS 日程整理器</h1>
<p>脚手架就绪</p>
<div class="app">
<header class="app-header">
<h1>📅 ICS 日程整理器</h1>
</header>
<main class="app-main">
<DropZone v-if="!isLoaded" />
<div v-else class="placeholder">
<p>文件已加载列表与编辑器待实现</p>
</div>
</main>
</div>
</template>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, "Segoe UI", Roboto, "Microsoft YaHei", sans-serif;
background: #f5f6f8;
color: #222;
line-height: 1.5;
}
.app { min-height: 100vh; display: flex; flex-direction: column; }
.app-header {
background: #2c3e50;
color: #fff;
padding: 14px 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.app-header h1 { font-size: 18px; font-weight: 600; }
.app-main { flex: 1; display: flex; overflow: hidden; }
.placeholder {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: #95a5a6;
}
</style>

View File

@@ -0,0 +1,99 @@
<script setup>
import { ref } from 'vue'
import { useCalendar } from '../composables/useCalendar.js'
const { loadFile } = useCalendar()
const dragOver = ref(false)
const error = ref('')
function onDrop(e) {
dragOver.value = false
error.value = ''
const file = e.dataTransfer.files[0]
if (!file) return
if (!file.name.toLowerCase().endsWith('.ics')) {
error.value = '请选择 .ics 文件'
return
}
loadFile(file).catch((err) => {
error.value = '解析失败:' + (err.message || err)
})
}
function onPick(e) {
error.value = ''
const file = e.target.files[0]
if (!file) return
loadFile(file).catch((err) => {
error.value = '解析失败:' + (err.message || err)
})
}
</script>
<template>
<div
class="dropzone"
:class="{ active: dragOver }"
@dragover.prevent="dragOver = true"
@dragleave.prevent="dragOver = false"
@drop.prevent="onDrop"
>
<div class="dropzone-content">
<div class="icon">📅</div>
<p class="hint">拖入 .ics 文件</p>
<label class="pick-btn">
点击选择文件
<input type="file" accept=".ics" @change="onPick" hidden />
</label>
<p v-if="error" class="error">{{ error }}</p>
</div>
</div>
</template>
<style scoped>
.dropzone {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
border: 2px dashed #bdc3c7;
border-radius: 12px;
margin: 40px;
transition: all 0.2s;
}
.dropzone.active {
border-color: #3498db;
background: #eaf4fc;
}
.dropzone-content {
text-align: center;
}
.icon {
font-size: 48px;
margin-bottom: 16px;
}
.hint {
color: #7f8c8d;
font-size: 14px;
margin-bottom: 16px;
}
.pick-btn {
display: inline-block;
padding: 10px 24px;
background: #3498db;
color: #fff;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background 0.15s;
}
.pick-btn:hover {
background: #2980b9;
}
.error {
color: #e74c3c;
font-size: 13px;
margin-top: 16px;
}
</style>