-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Page can be previewed, but no styles yet.
- Loading branch information
Showing
17 changed files
with
7,489 additions
and
30 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<script lang="ts"> | ||
// import type { Page } from '../../routes/api/[site]/components/lib'; | ||
// import { page } from '$lib/stores/page'; | ||
// import DropdownMenu from '$lib/components/DropdownMenu.svelte'; | ||
// import NewPageDialog from '$lib/components/NewPageDialog.svelte'; | ||
// import { goto } from '$app/navigation'; | ||
import type { Page } from "$lib/types"; | ||
export let page: Page; | ||
// function handlePageSelect(e: CustomEvent<Page>) { | ||
// goto(e.detail.id); | ||
// } | ||
function getPageName(page: Page): string { | ||
return (!page.path || page.path === '') ? 'index' : page.path; | ||
} | ||
</script> | ||
<div | ||
class="flex-1 flex flex-col" | ||
data-test-id="fake-browser"> | ||
<div | ||
class="bg-gray-50 border-b border-gray-200 border-solid rounded-t-xl h-12 px-3.5 flex" | ||
data-test-id="address-bar"> | ||
<div class="ml-4 py-2"> | ||
<span class="inline-block h-2 w-2 ml-2 rounded-full bg-red-900"></span> | ||
<span class="inline-block h-2 w-2 ml-2 rounded-full bg-amber-400"></span> | ||
<span class="inline-block h-2 w-2 ml-2 rounded-full bg-lime-700"></span> | ||
</div> | ||
<div class="flex-1 py-2.5 overflow-visible"> | ||
<div class="rounded bg-white bg-gray-50 border-b border-gray-200 shadow max-w-xs mx-auto text-center py-0.5 relative"> | ||
<span data-test-id="url-box">{getPageName(page)}</span> | ||
|
||
<!-- <NewPageDialog let:show> | ||
<DropdownMenu items={pages} on:select={handlePageSelect} let:item > | ||
{getPageName(item)} | ||
<button slot="extra" let:close type="button" on:click={() => { close(); show() }}>Add new page</button> | ||
</DropdownMenu> | ||
</NewPageDialog> --> | ||
</div> | ||
</div> | ||
<div class="py-3"> | ||
D | T | P | ||
</div> | ||
</div> | ||
<slot/> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<script lang="ts"> | ||
import { isAstElement } from '$lib/stores/page'; | ||
import type { AstNode } from '$lib/types'; | ||
export let node: AstNode; | ||
</script> | ||
|
||
{#if isAstElement(node)} | ||
{#if node.tag === 'html_comment'} | ||
{@html "<!--" + node.content + "-->"} | ||
{:else if node.tag === 'eex_comment'} | ||
{@html "<!--" + node.content + "-->"} | ||
{:else if node.tag === 'eex' && node.content[0] === '@inner_content'} | ||
<slot/> | ||
{:else if node.rendered_html} | ||
{@html node.rendered_html} | ||
{:else if node.attrs.selfClose} | ||
<svelte:element this={node.tag} {...node.attrs}/> | ||
{:else} | ||
<svelte:element this={node.tag} {...node.attrs}> | ||
{#each node.content as subnode, index} | ||
<svelte:self node={subnode}/> | ||
{/each} | ||
</svelte:element> | ||
{/if} | ||
{:else} | ||
{node} | ||
{/if} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<script lang="ts"> | ||
import { selectedAstElement, slotTargetElement, selectedAstElementId, highlightedAstElement, isAstElement } from '$lib/stores/page'; | ||
import type { AstNode } from '$lib/types'; | ||
export let node: AstNode; | ||
export let nodeId: string; | ||
import { draggedObject } from '$lib/stores/dragAndDrop'; | ||
function handleDragEnter() { | ||
if (isAstElement(node) && $draggedObject?.category === 'basic') { | ||
$slotTargetElement = node; | ||
} | ||
} | ||
function handleDragLeave() { | ||
if (isAstElement(node) && $draggedObject?.category === 'basic' && $slotTargetElement === node) { | ||
$slotTargetElement = undefined; | ||
} | ||
} | ||
function handleMouseOver() { | ||
isAstElement(node) && ($highlightedAstElement = node); | ||
} | ||
function handleMouseOut() { | ||
$highlightedAstElement = undefined | ||
} | ||
function handleClick() { | ||
$selectedAstElementId = nodeId | ||
} | ||
// When rendering raw html, we can't add the usual classes to the wrapper. | ||
function highlightContent(wrapperDiv: HTMLElement, { selected, highlighted }: { selected: boolean, highlighted: boolean }) { | ||
let startsWithOneChildren = wrapperDiv.children.length === 1; | ||
if (startsWithOneChildren) { | ||
let child = wrapperDiv.children[0]; | ||
child.setAttribute('data-selected', String(selected)); | ||
child.setAttribute('data-highlighted', String(highlighted)); | ||
} | ||
return { | ||
update({ selected, highlighted }: { selected: boolean, highlighted: boolean }) { | ||
if (wrapperDiv.children.length === 1) { | ||
let child = wrapperDiv.children[0]; | ||
child.setAttribute('data-selected', String(selected)); | ||
child.setAttribute('data-highlighted', String(highlighted)); | ||
} else if (wrapperDiv.children.length === 0 && wrapperDiv.childNodes.length === 1) { | ||
wrapperDiv.setAttribute('data-nochildren', "true"); | ||
wrapperDiv.setAttribute('data-selected', String(selected)); | ||
wrapperDiv.setAttribute('data-highlighted', String(highlighted)); | ||
} else if (startsWithOneChildren) { | ||
Array.from(wrapperDiv.children).forEach(child => { | ||
child.removeAttribute('data-selected'); | ||
child.removeAttribute('data-highlighted'); | ||
}); | ||
} | ||
}, | ||
destroy() { | ||
// noop | ||
} | ||
} | ||
} | ||
</script> | ||
|
||
{#if isAstElement(node)} | ||
{#if node.tag === 'html_comment'} | ||
{@html "<!--" + node.content + "-->"} | ||
{:else if node.tag === 'eex_comment'} | ||
{@html "<!--" + node.content + "-->"} | ||
{:else if node.tag === 'eex' && node.content[0] === '@inner_content'} | ||
<slot/> | ||
{:else if node.rendered_html} | ||
<div | ||
class="contents" | ||
on:mouseover|stopPropagation={handleMouseOver} | ||
on:mouseout|stopPropagation={handleMouseOut} | ||
on:click|preventDefault|stopPropagation={() => $selectedAstElementId = nodeId} | ||
use:highlightContent={{selected: $selectedAstElement === node, highlighted: $highlightedAstElement === node}} | ||
>{@html node.rendered_html}</div> | ||
{:else if node.attrs.selfClose} | ||
<svelte:element | ||
this={node.tag} | ||
{...node.attrs} | ||
data-selected={$selectedAstElement === node} | ||
data-highlighted={$highlightedAstElement === node} | ||
data-slot-target={$slotTargetElement === node && !$slotTargetElement.attrs.selfClose} | ||
on:dragenter|stopPropagation={handleDragEnter} | ||
on:dragleave|stopPropagation={handleDragLeave} | ||
on:mouseover|stopPropagation={handleMouseOver} | ||
on:mouseout|stopPropagation={handleMouseOut} | ||
on:click|preventDefault|stopPropagation={handleClick} /> | ||
{:else} | ||
<svelte:element | ||
this={node.tag} | ||
{...node.attrs} | ||
data-selected={$selectedAstElement === node} | ||
data-highlighted={$highlightedAstElement === node} | ||
data-slot-target={$slotTargetElement === node} | ||
on:dragenter|stopPropagation={handleDragEnter} | ||
on:dragleave|stopPropagation={handleDragLeave} | ||
on:mouseover|stopPropagation={handleMouseOver} | ||
on:mouseout|stopPropagation={handleMouseOut} | ||
on:click|preventDefault|stopPropagation={() => $selectedAstElementId = nodeId}> | ||
{#each node.content as subnode, index} | ||
<svelte:self node={subnode} nodeId="{nodeId}.{index}"/> | ||
{/each} | ||
</svelte:element> | ||
{/if} | ||
{:else} | ||
{node} | ||
{/if} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<script lang="ts"> | ||
import { Page, AstElement } from "$lib/types" | ||
import LayoutAstNode from './LayoutAstNode.svelte'; | ||
import PageAstNode from './PageAstNode.svelte'; | ||
import BrowserFrame from './BrowserFrame.svelte'; | ||
import { selectedAstElementId } from "$lib/stores/page"; | ||
export let page: Page; | ||
let isDraggingOver = false; | ||
async function handleDragDrop(e: DragEvent) { | ||
// let { target } = e; | ||
// $currentComponentCategory = null; | ||
// if (!$draggedObject) return; | ||
// if ($draggedObject.category === 'basic') { | ||
// if (!(target instanceof HTMLElement)) return; | ||
// if (target.id === 'fake-browser-content') return; | ||
// if (!$slotTargetElement) return; | ||
// if ($slotTargetElement.attrs.selfClose) return; | ||
// addBasicComponentToTarget($slotTargetElement); | ||
// } else { | ||
// let { ast }: { ast: AstNode[] } = await renderComponentInPage($draggedObject.id, $page); | ||
// $page.ast = [...$page.ast, ...ast] | ||
// let { data: newPage} = await updatePage(); | ||
// $page = newPage; | ||
// } | ||
// isDraggingOver = false; | ||
} | ||
async function addBasicComponentToTarget(astElement: AstElement) { | ||
// if (!$draggedObject) return; | ||
// let componentDefinition = $draggedObject; | ||
// $draggedObject = null; | ||
// let targetNode = astElement; | ||
// let { ast }: { ast: AstNode[] } = await renderComponentInPage(componentDefinition.id, $page); | ||
// targetNode?.content.push(...ast); | ||
// $slotTargetElement = undefined; | ||
// let { data: newPage} = await updatePage(); | ||
// $page = newPage; | ||
} | ||
function dragOver() { | ||
isDraggingOver = true; | ||
} | ||
</script> | ||
|
||
<div class="flex-1 px-8 py-4 flex max-h-full" data-test-id="main"> | ||
<BrowserFrame page={page}> | ||
<div | ||
on:drop|preventDefault={handleDragDrop} | ||
on:dragover|preventDefault={dragOver} | ||
style="--outlined-id: title-1" | ||
id="fake-browser-content" | ||
class="bg-white rounded-b-xl relative overflow-hidden flex-1 {isDraggingOver && 'border-dashed border-blue-500 border-2'}" | ||
data-test-id="browser-content"> | ||
<div id="page-wrapper" class="p-1 m-1" data-selected={$selectedAstElementId === 'root'}> | ||
{#each page.layout.ast as layoutAstNode} | ||
<LayoutAstNode node={layoutAstNode}> | ||
{#each page.ast as astNode, index} | ||
<PageAstNode node={astNode} nodeId="{index}"/> | ||
{/each} | ||
</LayoutAstNode> | ||
{/each} | ||
</div> | ||
</div> | ||
</BrowserFrame> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,21 @@ | ||
<script lang="ts"> | ||
import ComponentsSidebar from "./ComponentsSidebar.svelte"; | ||
import Backdrop from "./Backdrop.svelte"; | ||
import type { ComponentDefinition, Page } from "../types"; | ||
import PagePreview from "./PagePreview.svelte"; | ||
import { page as pageStore } from "$lib/stores/page"; | ||
import type { ComponentDefinition, Page } from "$lib/types"; | ||
export let components: ComponentDefinition; | ||
export let page: Page; | ||
$: $pageStore = page; | ||
</script> | ||
<Backdrop/> | ||
<div class="flex min-h-screen bg-gray-100" data-test-id="app-container"> | ||
<!-- Left sidebar --> | ||
<ComponentsSidebar {components}/> | ||
|
||
<!-- Main --> | ||
<PagePreview {page} /> | ||
|
||
<!-- <slot/> --> | ||
</div> |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { writable, derived, get } from 'svelte/store'; | ||
import type { Writable, Readable } from 'svelte/store'; | ||
import type { AstElement, AstNode, Page } from '$lib/types'; | ||
|
||
export const page: Writable<Page> = writable(); | ||
export const selectedAstElementId: Writable<string | undefined> = writable(); | ||
// export const highlightedAstElementId: Writable<string | undefined> = writable(); | ||
export const highlightedAstElement: Writable<AstElement | undefined> = writable(); | ||
export const slotTargetElement: Writable<AstElement | undefined> = writable(); | ||
|
||
export const rootAstElement: Readable<AstElement | undefined> = derived([page], ([$page]) => { | ||
// This is a virtual AstElement intended to simulate the page itself to reorder the components at the first level. | ||
return { tag: 'root', attrs: {}, content: $page.ast }; | ||
}); | ||
export const selectedAstElement: Readable<AstElement | undefined> = derived([page, selectedAstElementId], ([$page, $selectedAstElementId]) => { | ||
if ($selectedAstElementId) { | ||
if ($selectedAstElementId === 'root') return get(rootAstElement); | ||
return findAstElement($page.ast, $selectedAstElementId); | ||
} | ||
}); | ||
|
||
export function isAstElement(maybeNode: AstNode): maybeNode is AstElement { | ||
return typeof maybeNode !== 'string'; | ||
} | ||
|
||
export function findAstElement(ast: AstNode[], id: string): AstElement { | ||
let indexes = id.split(".").map(s => parseInt(s, 10)); | ||
let node: AstNode = ast[indexes[0]] as AstElement | ||
ast = node.content; | ||
for(let i = 1; i < indexes.length; i++) { | ||
node = ast[indexes[i]] as AstElement; | ||
ast = node.content; | ||
} | ||
return node; | ||
} | ||
export function findAstElementId(astNode: AstNode): string | undefined { | ||
let $page = get(page); | ||
return _findAstElementId($page.ast, astNode, ""); | ||
} | ||
|
||
export function _findAstElementId(ast: AstNode[], astNode: AstNode, id: string): string | undefined { | ||
for(let i = 0; i < ast.length; i++) { | ||
let currentNode = ast[i]; | ||
if (currentNode === astNode) { | ||
return id + i; | ||
} else if (isAstElement(currentNode)) { | ||
let result = _findAstElementId(currentNode.content, astNode, id + i + "."); | ||
if (result) { | ||
return result; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.