feat: add CSS file import with drag & drop support
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 16s
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 16s
Add CssFileImport component to StylesheetViewer allowing users to import CSS files to replace custom CSS content. Features: - Click to select file via file dialog - Drag & drop support with visual feedback - File validation (.css only, max 1MB) - Error messages for invalid files - Direct replacement of customCss content New component: - src/components/ui/CssFileImport.vue Integration: - Added at top of StylesheetViewer - Emits 'import' event with file content - Content replaces customCss in store Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b692047ff2
commit
e88c217b1e
2 changed files with 168 additions and 0 deletions
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div id="stylesheet-viewer">
|
||||
<!-- CSS File Import -->
|
||||
<CssFileImport @import="handleCssImport" />
|
||||
|
||||
<!-- Base CSS Section (Collapsable, closed by default) -->
|
||||
<div class="css-section">
|
||||
<div class="section-header" @click="isBaseCssExpanded = !isBaseCssExpanded">
|
||||
|
|
@ -53,6 +56,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { useStylesheetStore } from '../stores/stylesheet';
|
||||
import CssFileImport from './ui/CssFileImport.vue';
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import css from 'highlight.js/lib/languages/css';
|
||||
import 'highlight.js/styles/atom-one-dark.css';
|
||||
|
|
@ -90,6 +94,11 @@ const handleFocus = () => {
|
|||
stylesheetStore.isEditing = true;
|
||||
};
|
||||
|
||||
const handleCssImport = (cssContent) => {
|
||||
// Replace custom CSS with imported content
|
||||
stylesheetStore.customCss = cssContent;
|
||||
};
|
||||
|
||||
// Watch editing mode and format when exiting
|
||||
watch(isCustomCssEditable, async (newValue, oldValue) => {
|
||||
stylesheetStore.isEditing = newValue;
|
||||
|
|
|
|||
159
src/components/ui/CssFileImport.vue
Normal file
159
src/components/ui/CssFileImport.vue
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<template>
|
||||
<div
|
||||
class="css-import"
|
||||
:class="{ 'is-dragging': isDragging }"
|
||||
@dragover.prevent="handleDragOver"
|
||||
@dragleave.prevent="handleDragLeave"
|
||||
@drop.prevent="handleDrop"
|
||||
>
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
accept=".css"
|
||||
@change="handleFileSelect"
|
||||
style="display: none"
|
||||
/>
|
||||
|
||||
<button class="import-button" @click="openFileDialog" type="button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/>
|
||||
</svg>
|
||||
<span>Importer un fichier CSS</span>
|
||||
</button>
|
||||
|
||||
<span class="import-hint">ou glisser-déposer ici</span>
|
||||
|
||||
<div v-if="error" class="import-error">{{ error }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const emit = defineEmits(['import']);
|
||||
|
||||
const fileInput = ref(null);
|
||||
const isDragging = ref(false);
|
||||
const error = ref('');
|
||||
|
||||
const openFileDialog = () => {
|
||||
fileInput.value?.click();
|
||||
};
|
||||
|
||||
const handleDragOver = (e) => {
|
||||
isDragging.value = true;
|
||||
};
|
||||
|
||||
const handleDragLeave = (e) => {
|
||||
isDragging.value = false;
|
||||
};
|
||||
|
||||
const handleDrop = (e) => {
|
||||
isDragging.value = false;
|
||||
const files = e.dataTransfer.files;
|
||||
|
||||
if (files.length > 0) {
|
||||
processFile(files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileSelect = (e) => {
|
||||
const files = e.target.files;
|
||||
|
||||
if (files.length > 0) {
|
||||
processFile(files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const processFile = (file) => {
|
||||
error.value = '';
|
||||
|
||||
// Validate file type
|
||||
if (!file.name.endsWith('.css')) {
|
||||
error.value = 'Seuls les fichiers .css sont acceptés';
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate file size (max 1MB)
|
||||
if (file.size > 1024 * 1024) {
|
||||
error.value = 'Le fichier est trop volumineux (max 1MB)';
|
||||
return;
|
||||
}
|
||||
|
||||
// Read file content
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (e) => {
|
||||
const content = e.target.result;
|
||||
emit('import', content);
|
||||
|
||||
// Reset input
|
||||
if (fileInput.value) {
|
||||
fileInput.value.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = () => {
|
||||
error.value = 'Erreur lors de la lecture du fichier';
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.css-import {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
background: #21252b;
|
||||
border: 2px dashed transparent;
|
||||
border-radius: 0.25rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.css-import.is-dragging {
|
||||
border-color: #61afef;
|
||||
background: #2c313c;
|
||||
}
|
||||
|
||||
.import-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: #2c313c;
|
||||
color: #abb2bf;
|
||||
border: 1px solid #3e4451;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.import-button:hover {
|
||||
background: #3e4451;
|
||||
border-color: #61afef;
|
||||
color: #61afef;
|
||||
}
|
||||
|
||||
.import-button svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.import-hint {
|
||||
font-size: 0.75rem;
|
||||
color: #5c6370;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.import-error {
|
||||
font-size: 0.75rem;
|
||||
color: #e06c75;
|
||||
background: rgba(224, 108, 117, 0.1);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue