Compare commits
2 commits
9ed028a560
...
f760e1942a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f760e1942a | ||
|
|
59dfa18ec7 |
16 changed files with 95 additions and 81 deletions
8
public/assets/css/src/_global.scss
Normal file
8
public/assets/css/src/_global.scss
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
button[disabled] {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
button[disabled]:hover {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
|
@ -234,8 +234,8 @@ img {
|
|||
--space-m: 2rem;
|
||||
--space-big: 3em;
|
||||
--curve: cubic-bezier(0.86, 0, 0.07, 1);
|
||||
--sans-serif: "DM Sans", sans-serif;
|
||||
--mono: "Inconsolata", monospace;
|
||||
--sans-serif: 'DM Sans', sans-serif;
|
||||
--mono: 'Inconsolata', monospace;
|
||||
--input-h: 26px;
|
||||
--input-w: 160px;
|
||||
--input-w-small: 45px;
|
||||
|
|
@ -688,4 +688,13 @@ input[type=number] {
|
|||
line-height: 1.5;
|
||||
resize: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button[disabled] {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
button[disabled]:hover {
|
||||
background-color: inherit !important;
|
||||
}/*# sourceMappingURL=style.css.map */
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -8,3 +8,4 @@
|
|||
@use "src/_forms-section.scss" as *;
|
||||
@use "src/_buttons.scss" as *;
|
||||
@use "src/_settings-popup.scss" as *;
|
||||
@use "src/_global.scss" as *;
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 2.4 MiB |
|
|
@ -1 +1 @@
|
|||
Uuid: f9jqf7vus7w0dx6z
|
||||
Uuid: kmmswqjqh5mxyecl
|
||||
|
|
@ -15,9 +15,9 @@ Mapdata:
|
|||
background:
|
||||
type: osm
|
||||
center:
|
||||
lat: 43.82684265866453
|
||||
lon: 4.3375882121084715
|
||||
zoom: 11.37799302158894
|
||||
lat: 43.484330002696964
|
||||
lon: 4.029111008525206
|
||||
zoom: 6.503825883663738
|
||||
|
||||
----
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ body {
|
|||
font-family: "DM Sans", sans-serif;
|
||||
text-align: left;
|
||||
color: rgb(190, 9, 9);
|
||||
background: blue;
|
||||
}
|
||||
|
||||
p {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ columns:
|
|||
template:
|
||||
- map
|
||||
- geoformat
|
||||
info: "{{ page.intendedTemplate }}"
|
||||
sidebar:
|
||||
width: 1/3
|
||||
sections:
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@ columns:
|
|||
fields:
|
||||
type: fields
|
||||
fields:
|
||||
subtitle:
|
||||
subtitle:
|
||||
label: Sous-titre
|
||||
type: text
|
||||
width: 1/2
|
||||
cover:
|
||||
cover:
|
||||
label: Image de couverture
|
||||
type: files
|
||||
multiple: false
|
||||
width: 1/2
|
||||
pages:
|
||||
label: Narratives
|
||||
label: Récits
|
||||
type: pages
|
||||
template: narrative
|
||||
sidebar:
|
||||
|
|
@ -26,6 +26,3 @@ columns:
|
|||
files:
|
||||
label: Fichiers
|
||||
type: files
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
27
src/App.vue
27
src/App.vue
|
|
@ -2,7 +2,7 @@
|
|||
import PagedJsWrapper from './components/PagedJsWrapper.vue';
|
||||
import EditorPanel from './components/editor/EditorPanel.vue';
|
||||
import ElementPopup from './components/ElementPopup.vue';
|
||||
import PagePopup from './components/PagePopup.vue';
|
||||
// import PagePopup from './components/PagePopup.vue'; // DISABLED: page template styling feature
|
||||
import PreviewLoader from './components/PreviewLoader.vue';
|
||||
import SaveButton from './components/SaveButton.vue';
|
||||
import { onMounted, ref, computed, provide } from 'vue';
|
||||
|
|
@ -19,22 +19,22 @@ const narrativeStore = useNarrativeStore();
|
|||
const previewFrame1 = ref(null);
|
||||
const previewFrame2 = ref(null);
|
||||
const elementPopup = ref(null);
|
||||
const pagePopup = ref(null);
|
||||
// const pagePopup = ref(null); // DISABLED: page template styling feature
|
||||
const activeTab = ref('');
|
||||
|
||||
provide('activeTab', activeTab);
|
||||
|
||||
// Setup iframe interactions (hover, click, labels)
|
||||
const {
|
||||
hoveredPage,
|
||||
selectedPages,
|
||||
// hoveredPage, // DISABLED: page template styling feature
|
||||
// selectedPages, // DISABLED: page template styling feature
|
||||
hoveredElement,
|
||||
selectedElement,
|
||||
handleIframeMouseMove,
|
||||
handleIframeClick,
|
||||
handlePagePopupClose,
|
||||
// handlePagePopupClose, // DISABLED: page template styling feature
|
||||
handleElementPopupClose,
|
||||
} = useIframeInteractions({ elementPopup, pagePopup });
|
||||
} = useIframeInteractions({ elementPopup });
|
||||
|
||||
// Setup preview renderer with double buffering
|
||||
const {
|
||||
|
|
@ -61,13 +61,10 @@ const activeFrame = computed(() => {
|
|||
const { printPreview } = usePrintPreview(activeFrame);
|
||||
|
||||
// Setup keyboard shortcuts (depends on printPreview)
|
||||
const {
|
||||
handleKeyboardShortcut,
|
||||
isMac
|
||||
} = useKeyboardShortcuts({
|
||||
const { handleKeyboardShortcut, isMac } = useKeyboardShortcuts({
|
||||
stylesheetStore,
|
||||
elementPopup,
|
||||
pagePopup,
|
||||
// pagePopup, // DISABLED: page template styling feature
|
||||
activeTab,
|
||||
printPreview,
|
||||
});
|
||||
|
|
@ -117,13 +114,19 @@ onMounted(async () => {
|
|||
:iframeRef="activeFrame"
|
||||
@close="handleElementPopupClose"
|
||||
/>
|
||||
<!-- DISABLED: page template styling feature
|
||||
<PagePopup
|
||||
ref="pagePopup"
|
||||
:iframeRef="activeFrame"
|
||||
@close="handlePagePopupClose"
|
||||
/>
|
||||
-->
|
||||
|
||||
<button class="print-btn" @click="printPreview" :title="`Imprimer (${isMac ? '⌘' : 'Ctrl'}+P)`">
|
||||
<button
|
||||
class="print-btn"
|
||||
@click="printPreview"
|
||||
:title="`Imprimer (${isMac ? '⌘' : 'Ctrl'}+P)`"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
class="tab"
|
||||
:class="{ active: activeTab === 'contenu' }"
|
||||
@click="activeTab = 'contenu'"
|
||||
title="Ouvrir l'onglet Contenu"
|
||||
title="fonctionnalité à venir"
|
||||
disabled
|
||||
>
|
||||
Contenu
|
||||
</button>
|
||||
|
|
@ -131,11 +132,9 @@ nav {
|
|||
position: relative;
|
||||
left: calc(var(--panel-w) * -1);
|
||||
|
||||
|
||||
background-color: var(--color-panel-bg);
|
||||
box-shadow: -5px 0px 12px;
|
||||
|
||||
|
||||
transition: left 0.3s var(--curve);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
|
@ -145,7 +144,7 @@ nav {
|
|||
}
|
||||
|
||||
.tab-panel {
|
||||
height: calc(100% - var(--panel-nav-h)*2);
|
||||
height: calc(100% - var(--panel-nav-h) * 2);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0 2em;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import { ref } from 'vue';
|
|||
* Composable for managing interactions with pages and elements in the iframe
|
||||
* Handles hover effects, labels, and click events for both pages and content elements
|
||||
*/
|
||||
export function useIframeInteractions({ elementPopup, pagePopup }) {
|
||||
// Page interaction state
|
||||
const hoveredPage = ref(null);
|
||||
const selectedPages = ref([]); // Pages with active border (when popup is open)
|
||||
export function useIframeInteractions({ elementPopup /*, pagePopup // DISABLED: page template styling feature */ }) {
|
||||
// DISABLED: page template styling feature
|
||||
// const hoveredPage = ref(null);
|
||||
// const selectedPages = ref([]); // Pages with active border (when popup is open)
|
||||
const hoveredElement = ref(null); // Currently hovered content element
|
||||
const selectedElement = ref(null); // Selected element (when popup is open)
|
||||
const EDGE_THRESHOLD = 30; // px from edge to trigger hover
|
||||
// const EDGE_THRESHOLD = 30; // px from edge to trigger hover // DISABLED: page template styling feature
|
||||
|
||||
// Text elements that can trigger ElementPopup (excluding containers, images, etc.)
|
||||
const CONTENT_ELEMENTS = [
|
||||
|
|
@ -34,6 +34,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
'FIGCAPTION',
|
||||
];
|
||||
|
||||
/* DISABLED: page template styling feature
|
||||
// Check if mouse position is near the edges of a page element
|
||||
const isNearPageEdge = (pageElement, mouseX, mouseY) => {
|
||||
const rect = pageElement.getBoundingClientRect();
|
||||
|
|
@ -64,6 +65,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
(p) => (p.getAttribute('data-page-type') || 'default') === pageType
|
||||
);
|
||||
};
|
||||
*/
|
||||
|
||||
// Get selector for element (same logic as ElementPopup)
|
||||
const getSelectorFromElement = (element) => {
|
||||
|
|
@ -117,6 +119,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
}
|
||||
};
|
||||
|
||||
/* DISABLED: page template styling feature
|
||||
// Create and position page label on hover
|
||||
const createPageLabel = (page) => {
|
||||
const doc = page.ownerDocument;
|
||||
|
|
@ -148,6 +151,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
label.remove();
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// Check if element is a content element (or find closest content parent)
|
||||
const getContentElement = (element) => {
|
||||
|
|
@ -161,6 +165,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
return null;
|
||||
};
|
||||
|
||||
/* DISABLED: page template styling feature
|
||||
// Clear selection highlight from all selected pages
|
||||
const clearSelectedPages = () => {
|
||||
selectedPages.value.forEach((page) => {
|
||||
|
|
@ -168,6 +173,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
});
|
||||
selectedPages.value = [];
|
||||
};
|
||||
*/
|
||||
|
||||
// Clear selected element highlight
|
||||
const clearSelectedElement = () => {
|
||||
|
|
@ -188,6 +194,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
|
||||
// Handle mouse movement in iframe
|
||||
const handleIframeMouseMove = (event) => {
|
||||
/* DISABLED: page template styling feature
|
||||
const pages = event.target.ownerDocument.querySelectorAll('.pagedjs_page');
|
||||
let foundPage = null;
|
||||
|
||||
|
|
@ -217,44 +224,31 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
|
||||
hoveredPage.value = foundPage;
|
||||
}
|
||||
*/
|
||||
|
||||
// If not near page edge, check for content element hover
|
||||
if (!foundPage) {
|
||||
const contentElement = getContentElement(event.target);
|
||||
const doc = event.target.ownerDocument;
|
||||
// Check for content element hover
|
||||
const contentElement = getContentElement(event.target);
|
||||
const doc = event.target.ownerDocument;
|
||||
|
||||
if (contentElement !== hoveredElement.value) {
|
||||
// Remove highlight from previous element (only if not selected)
|
||||
if (
|
||||
hoveredElement.value &&
|
||||
hoveredElement.value !== selectedElement.value
|
||||
) {
|
||||
hoveredElement.value.classList.remove('element-hovered');
|
||||
}
|
||||
|
||||
// Remove previous labels
|
||||
removeElementLabel(doc);
|
||||
removePageLabel(doc);
|
||||
|
||||
// Add highlight to new element (only if not already selected)
|
||||
if (contentElement && contentElement !== selectedElement.value) {
|
||||
contentElement.classList.add('element-hovered');
|
||||
createElementLabel(contentElement);
|
||||
}
|
||||
|
||||
hoveredElement.value = contentElement;
|
||||
}
|
||||
} else {
|
||||
// Clear element hover when hovering page edge
|
||||
if (contentElement !== hoveredElement.value) {
|
||||
// Remove highlight from previous element (only if not selected)
|
||||
if (
|
||||
hoveredElement.value &&
|
||||
hoveredElement.value !== selectedElement.value
|
||||
) {
|
||||
hoveredElement.value.classList.remove('element-hovered');
|
||||
hoveredElement.value = null;
|
||||
}
|
||||
// Remove element label when hovering page edge
|
||||
removeElementLabel(event.target.ownerDocument);
|
||||
|
||||
// Remove previous label
|
||||
removeElementLabel(doc);
|
||||
|
||||
// Add highlight to new element (only if not already selected)
|
||||
if (contentElement && contentElement !== selectedElement.value) {
|
||||
contentElement.classList.add('element-hovered');
|
||||
createElementLabel(contentElement);
|
||||
}
|
||||
|
||||
hoveredElement.value = contentElement;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -262,6 +256,7 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
const handleIframeClick = (event) => {
|
||||
const element = event.target;
|
||||
|
||||
/* DISABLED: page template styling feature
|
||||
// Check if clicking near a page edge
|
||||
if (hoveredPage.value) {
|
||||
event.stopPropagation();
|
||||
|
|
@ -286,35 +281,28 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
elementPopup.value.close();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// Only show popup for elements inside the page template
|
||||
const isInsidePage = element.closest('.pagedjs_page');
|
||||
if (!isInsidePage) {
|
||||
clearSelectedPages();
|
||||
clearSelectedElement();
|
||||
elementPopup.value.close();
|
||||
pagePopup.value.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Only show ElementPopup for content elements, not divs
|
||||
const contentElement = getContentElement(element);
|
||||
if (!contentElement) {
|
||||
clearSelectedPages();
|
||||
clearSelectedElement();
|
||||
elementPopup.value.close();
|
||||
pagePopup.value.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear page selections
|
||||
clearSelectedPages();
|
||||
|
||||
// If popup is already open and we're clicking another element, close it
|
||||
if (elementPopup.value.visible) {
|
||||
clearSelectedElement();
|
||||
elementPopup.value.close();
|
||||
pagePopup.value.close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -332,7 +320,6 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
// Get document and remove labels when opening popup
|
||||
const doc = event.target.ownerDocument;
|
||||
removeElementLabel(doc);
|
||||
removePageLabel(doc);
|
||||
|
||||
// Select the new element
|
||||
selectedElement.value = contentElement;
|
||||
|
|
@ -342,13 +329,14 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
const count = getSimilarElementsCount(contentElement, doc);
|
||||
|
||||
elementPopup.value.handleIframeClick(event, contentElement, count);
|
||||
pagePopup.value.close();
|
||||
};
|
||||
|
||||
// Handlers for popup close events
|
||||
/* DISABLED: page template styling feature
|
||||
const handlePagePopupClose = () => {
|
||||
clearSelectedPages();
|
||||
};
|
||||
*/
|
||||
|
||||
const handleElementPopupClose = () => {
|
||||
clearSelectedElement();
|
||||
|
|
@ -356,17 +344,17 @@ export function useIframeInteractions({ elementPopup, pagePopup }) {
|
|||
|
||||
return {
|
||||
// State
|
||||
hoveredPage,
|
||||
selectedPages,
|
||||
// hoveredPage, // DISABLED: page template styling feature
|
||||
// selectedPages, // DISABLED: page template styling feature
|
||||
hoveredElement,
|
||||
selectedElement,
|
||||
// Handlers
|
||||
handleIframeMouseMove,
|
||||
handleIframeClick,
|
||||
handlePagePopupClose,
|
||||
// handlePagePopupClose, // DISABLED: page template styling feature
|
||||
handleElementPopupClose,
|
||||
// Utilities
|
||||
clearSelectedPages,
|
||||
// clearSelectedPages, // DISABLED: page template styling feature
|
||||
clearSelectedElement,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { onMounted, onUnmounted } from 'vue';
|
|||
export function useKeyboardShortcuts({
|
||||
stylesheetStore,
|
||||
elementPopup,
|
||||
pagePopup,
|
||||
// pagePopup, // DISABLED: page template styling feature
|
||||
activeTab,
|
||||
printPreview
|
||||
}) {
|
||||
|
|
@ -22,10 +22,12 @@ export function useKeyboardShortcuts({
|
|||
elementPopup.value.close();
|
||||
return;
|
||||
}
|
||||
/* DISABLED: page template styling feature
|
||||
if (pagePopup.value?.visible) {
|
||||
pagePopup.value.close();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Backslash key - toggle editor panel
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export function usePreviewRenderer({
|
|||
let savedScrollPercentage = 0;
|
||||
const currentFrameIndex = ref(1); // 1 or 2, which iframe is currently visible
|
||||
const isTransitioning = ref(false);
|
||||
const initialized = ref(false);
|
||||
let keyboardShortcutHandler = null;
|
||||
|
||||
/**
|
||||
|
|
@ -117,6 +118,9 @@ export function usePreviewRenderer({
|
|||
// Swap current frame
|
||||
currentFrameIndex.value = currentFrameIndex.value === 1 ? 2 : 1;
|
||||
isTransitioning.value = false;
|
||||
if (!initialized.value) {
|
||||
initialized.value = true;
|
||||
}
|
||||
}, 200); // Match CSS transition duration
|
||||
}, 50); // Small delay to ensure scroll is set
|
||||
}, 200); // Wait for PagedJS
|
||||
|
|
@ -127,6 +131,7 @@ export function usePreviewRenderer({
|
|||
watch(
|
||||
() => stylesheetStore.content,
|
||||
() => {
|
||||
if (!initialized.value) return;
|
||||
renderPreview();
|
||||
}
|
||||
);
|
||||
|
|
@ -135,6 +140,7 @@ export function usePreviewRenderer({
|
|||
watch(
|
||||
() => narrativeStore.data,
|
||||
() => {
|
||||
if (!initialized.value) return;
|
||||
if (narrativeStore.data) {
|
||||
renderPreview();
|
||||
}
|
||||
|
|
@ -152,6 +158,7 @@ export function usePreviewRenderer({
|
|||
renderPreview,
|
||||
currentFrameIndex,
|
||||
isTransitioning,
|
||||
initialized,
|
||||
setKeyboardShortcutHandler,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
@import '../public/assets/css/style.scss';
|
||||
/* @import '../public/assets/css/style.scss'; */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue