django-components/tests/__snapshots__/test_benchmark_djc.ambr
2025-04-14 12:01:16 +02:00

8590 lines
318 KiB
Text

# serializer version: 1
# name: test_render
'''
<!DOCTYPE html>
<html lang="en" class="h-full" data-djc-id-ca1bc3e="" data-djc-id-ca1bc4e="" data-djc-id-ca1bc6a="" data-djc-id-ca1bc79="" data-djc-id-ca1bc7d="">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>DEMO</title>
</head>
<body class="bg-neutral-200 h-full">
<div
x-data="layout"
@resize.window="onWindowResize"
>
<!-- Static sidebar for desktop -->
<div
class="hidden"
:class="{
'fixed inset-y-0 z-40 flex w-72 flex-col': sidebarOpen,
'hidden': !sidebarOpen,
}"
>
<div
class="flex grow flex-col gap-y-5 overflow-y-auto px-6 pb-4 bg-neutral-900 text-neutral-200"
data-djc-id-ca1bc83="">
<div class="flex h-16 shrink-0 items-center">
DEMO
</div>
<nav class="flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-7">
<li>
<li x-data="bookmarks" class="pt-4" data-djc-id-ca1bc9e="">
<div data-djc-id-ca1bcb1="">
<span
class="py-2 text-sm group flex gap-x-3 rounded-md leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcba="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Project Bookmarks
</span>
</div>
<ul class="mx-4">
<li
x-data="bookmark"
x-props="{
onMenuToggle: onContextMenuToggle,
bookmark: {&#x27;id&#x27;: 82, &#x27;text&#x27;: &#x27;Test bookmark&#x27;, &#x27;url&#x27;: &#x27;http://localhost:8000/bookmarks/9/create&#x27;, &#x27;edit_url&#x27;: &#x27;/edit/1/bookmark/82&#x27;},
}"
class="list-disc ml-8"
data-djc-id-ca1bcb2="">
<div class="flex">
<a
href="http://localhost:8000/bookmarks/9/create"
target="_blank"
class="grow px-2 py-1 text-xs font-semibold hover:bg-neutral-700 hover:text-white transition"
>
Test bookmark
</a>
<div x-ref="bookmark_menu" @click="onMenuToggle" class="self-center cursor-pointer" data-djc-id-ca1bcbb="">
<span
class="p-0 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="inline hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcbc="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
</li>
<li>
<div data-djc-id-ca1bcb4="">
<a
href="/create/1/bookmark"
class="px-2 py-1 text-xs hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="mt-0.5 ml-1 hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 18px; height: 18px;" data-djc-id-ca1bcbd="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Add New Bookmark
</a>
</div>
</li>
<div class="border-b border-gray-200 my-2 pt-2 text-sm font-bold">
Attachments:
</div>
</ul>
<template x-if="contextMenuItem.value">
<div class="self-center">
<div
@click_outside="onContextMenuClickOutside"
x-data="{
'isModelOverriden': true,
'modelName': &#x27;contextMenuItem.value&#x27;,
'closeOnClickOutside': true,
onClickOutside(event) {
if (this.closeOnClickOutside) {
if (!this.isModelOverriden) {
this[this.modelName] = false;
}
$dispatch('click_outside', { origEvent: event });
}
},
}"
@keydown.escape="contextMenuItem.value = false"
data-djc-id-ca1bcb5="">
<div
role="menu"
aria-orientation="vertical"
x-anchor.bottom="contextMenuRef.value" x-show="contextMenuItem.value" x-cloak="" class="w-24 ml-8 z-40 mt-2 divide-y divide-gray-300 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
data-djc-id-ca1bcbe="">
<div class="py-1" role="group">
<a
role="menuitem"
tabindex="0"
href="#"
:href="contextMenuItem.value.edit_url" class="px-4 py-1 text-sm text-gray-900 hover:bg-gray-100 cursor-pointer block"
>
Edit
</a>
</div>
</div>
</div>
</div>
</template>
</li>
<ul role="list" class="-mx-2 space-y-1">
<li>
<div data-djc-id-ca1bca5="">
<a
href="/"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc2="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Homepage
</a>
</div>
</li>
<li>
<div data-djc-id-ca1bca6="">
<a
href="/projects"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc3="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Projects
</a>
</div>
</li>
<li class="ml-8 rounded-md hover:bg-neutral-700 hover:text-white transition">
<a
href="/projects/1"
class="p-2 !w-full inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline"
data-djc-id-ca1bca7="">
Project Name
</a>
</li>
<li>
<div data-djc-id-ca1bcab="">
<a
href="/page-3"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc4="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Page 3
</a>
</div>
</li>
<li>
<div data-djc-id-ca1bcac="">
<a
href="/page-4"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc5="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Page 4
</a>
</div>
</li>
<li>
<div data-djc-id-ca1bcad="">
<a
href="/page-5"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc6="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
page-5
</a>
</div>
</li>
<li>
<div data-djc-id-ca1bcae="">
<a
href="/faq"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc7="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
FAQ
</a>
</div>
</li>
</ul>
<li class="mt-auto">
<div data-djc-id-ca1bcaf="">
<a
href="/faq"
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc8="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
FAQ
</a>
</div>
<div data-djc-id-ca1bcb0="">
<span
class="p-2 hover:bg-neutral-700 hover:text-white transition group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="hover:bg-neutral-700 hover:text-white transition h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcc9="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
Feedback
</span>
</div>
</li>
</li>
</ul>
</nav>
</div>
</div>
<div :class="{ 'pl-72': sidebarOpen }" class="flex flex-col" style="height: 100vh;">
<div
@sidebar_toggle="toggleSidebar" class="sticky top-0 z-30 flex h-16 shrink-0 items-center gap-x-4 border-b border-gray-200 bg-white px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-8"
data-djc-id-ca1bc8b="">
<button
type="button"
class="-m-2.5 p-2.5 text-gray-700"
@click="$dispatch('sidebar_toggle')"
>
<span class="sr-only">Open sidebar</span>
<div data-djc-id-ca1bcca="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bccb="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</button>
<!-- Separator -->
<div class="h-6 w-px bg-gray-900/10 lg:hidden" aria-hidden="true"></div>
<div class="flex flex-1 gap-x-4 self-stretch lg:gap-x-6">
<form class="relative flex flex-1 items-center" action="#" method="GET">
</form>
<div class="flex items-center gap-x-4 lg:gap-x-6">
<!-- Separator -->
<div
class="hidden lg:block lg:h-6 lg:w-px lg:bg-gray-900/10"
aria-hidden="true"
></div>
</div>
</div>
</div>
<main class="flex-auto flex flex-col">
<nav
aria-label="Breadcrumb"
class="flex border-b border-gray-200 bg-white"
data-djc-id-ca1bc8e="">
<ol
role="list"
class="mx-auto flex w-full max-w-screen-xl space-x-4 px-4 sm:px-6 lg:px-8"
>
<li class="flex">
<div class="flex items-center">
<a
href="/projects"
class="ml-4 text-sm font-medium text-gray-500 hover:text-gray-700"
>
<div data-djc-id-ca1bc4f="">
<span
class="text-gray-400 hover:text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" class="text-gray-400 hover:text-gray-500 h-6 w-6 shrink-0" style="width: 20px; height: 20px;" data-djc-id-ca1bc55="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</a>
</div>
</li>
<li class="flex">
<div class="flex items-center">
<svg
class="h-full w-6 flex-shrink-0 text-gray-200"
viewBox="0 0 24 44"
preserveAspectRatio="none"
fill="currentColor"
aria-hidden="true"
>
<path d="M.293 0l22 22-22 22h1.414l22-22-22-22H.293z" />
</svg>
<a
href="/projects/1"
class="ml-4 text-sm font-medium text-gray-500 hover:text-gray-700"
>
Project Name
</a>
</div>
</li>
</ol>
</nav>
<div class="px-4 pt-10 sm:px-6 lg:px-8 flex-auto flex flex-col">
<div class="flex pb-6">
<div class="flex justify-between gap-x-12">
<div class="prose">
<h3>Project Name</h3>
</div>
<div class="prose font-semibold text-gray-500 pt-1">
2022-02-06 - 2024-02-07
</div>
</div>
</div>
<div class="flex flex-col" data-djc-id-ca1bc92="">
<ul class="flex border-b mb-5 bg-white">
<li class="border-b-2">
<a
href="/projects/1/tab-2"
class="bg-white inline-block py-2 px-4 font-semibold transition text-gray-500 hover:text-blue-700"
>
Tab 2
</a>
</li>
<li class="border-b-2 border-blue-700">
<a
href="/projects/1/tab-1"
class="bg-white inline-block py-2 px-4 font-semibold transition text-blue-700"
>
Tab 1
</a>
</li>
</ul>
<div class="w-full h-full flex-grow-1 relative overflow-y-scroll">
<article class="px-4 pt-5 absolute w-full h-full">
<div >
None
</div>
</article>
</div>
</div>
<div class="flex flex-auto gap-6">
<div class="w-1/3 relative h-full pb-4">
<div class="absolute w-full h-full">
<ul role="list" class="flex flex-col gap-4" data-djc-id-ca1bc97="">
<li class="py-5 group flex justify-between gap-x-6 border border-gray-300 pl-4 pr-6 bg-white">
<div class="flex min-w-0 w-full gap-x-4">
<div class="min-w-0 flex-auto">
<a href="/projects/1/phases/PHASE_1">
<p class="text-sm font-semibold leading-6 text-gray-900 hover:text-gray-500">
Phase 1
</p>
</a>
</div>
</div>
</li>
<li class="py-5 group flex justify-between gap-x-6 border border-gray-300 pl-4 pr-6 bg-white">
<div class="flex min-w-0 w-full gap-x-4">
<div class="min-w-0 flex-auto">
<a href="/projects/1/phases/PHASE_2">
<p class="text-sm font-semibold leading-6 text-gray-900 hover:text-gray-500">
Phase 2
</p>
</a>
</div>
</div>
</li>
<li class="py-5 group flex justify-between gap-x-6 border border-gray-300 pl-4 pr-6 bg-white">
<div class="flex min-w-0 w-full gap-x-4">
<div class="min-w-0 flex-auto">
<a href="/projects/1/phases/PHASE_3">
<p class="text-sm font-semibold leading-6 text-gray-900 hover:text-gray-500">
Phase 3
</p>
</a>
</div>
</div>
</li>
<li class="py-5 group flex justify-between gap-x-6 border border-gray-300 pl-4 pr-6 bg-white">
<div class="flex min-w-0 w-full gap-x-4">
<div class="min-w-0 flex-auto">
<a href="/projects/1/phases/PHASE_4">
<p class="text-sm font-semibold leading-6 text-gray-900 hover:text-gray-500">
Phase 4
</p>
</a>
</div>
</div>
</li>
<li class="py-5 group flex justify-between gap-x-6 border border-gray-300 pl-4 pr-6 bg-white">
<div class="flex min-w-0 w-full gap-x-4">
<div class="min-w-0 flex-auto">
<a href="/projects/1/phases/PHASE_5">
<p class="text-sm font-semibold leading-6 text-gray-900 hover:text-gray-500">
Phase 5
</p>
</a>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="w-2/3 h-full">
<div class="h-full divide-y divide-gray-200 bg-white shadow overflow-y-hidden">
<div
x-data="tabs"
data-init="{&quot;name&quot;: &quot;proj-right&quot;}"
class="p-6 h-full flex flex-col"
data-djc-id-ca1be32="">
<ul class="flex border-b text-sm">
<li
@click="setOpenTab( 1 )"
:class="{
'border-b-2 border-blue-700': openTab === 1
}"
>
<a
href="#"
:class="openTab === 1 ? 'text-blue-700' : 'text-gray-500 hover:text-blue-700'"
class="bg-white inline-block py-2 px-4 font-semibold transition"
>
Project Info
</a>
</li>
<li
@click="setOpenTab( 2 )"
:class="{
'border-b-2 border-blue-700': openTab === 2
}"
>
<a
href="#"
:class="openTab === 2 ? 'text-blue-700' : 'text-gray-500 hover:text-blue-700'"
class="bg-white inline-block py-2 px-4 font-semibold transition"
>
Notes 1
</a>
</li>
<li
@click="setOpenTab( 3 )"
:class="{
'border-b-2 border-blue-700': openTab === 3
}"
>
<a
href="#"
:class="openTab === 3 ? 'text-blue-700' : 'text-gray-500 hover:text-blue-700'"
class="bg-white inline-block py-2 px-4 font-semibold transition"
>
Notes 2
</a>
</li>
<li
@click="setOpenTab( 4 )"
:class="{
'border-b-2 border-blue-700': openTab === 4
}"
>
<a
href="#"
:class="openTab === 4 ? 'text-blue-700' : 'text-gray-500 hover:text-blue-700'"
class="bg-white inline-block py-2 px-4 font-semibold transition"
>
Notes 3
</a>
</li>
<li
@click="setOpenTab( 5 )"
:class="{
'border-b-2 border-blue-700': openTab === 5
}"
>
<a
href="#"
:class="openTab === 5 ? 'text-blue-700' : 'text-gray-500 hover:text-blue-700'"
class="bg-white inline-block py-2 px-4 font-semibold transition"
>
Outputs
</a>
</li>
</ul>
<div class="w-full h-full flex-grow-1 relative overflow-y-scroll" x-ref="container">
<article class="px-4 pt-5 absolute w-full h-full">
<div
x-show="openTab === 1"
class="flex flex-col"
>
<div class="prose flex flex-col gap-8" data-djc-id-ca1bc9b="" data-djc-id-ca1bccd="" data-djc-id-ca1bcd5="">
<div class="border-b border-neutral-300">
<div class="flex justify-between items-start">
<h3 class="mt-0">Project Info</h3>
<a
href="/edit/1/"
class="not-prose bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bcdc="">
Edit Project
</a>
</div>
<table>
<tr>
<td class="font-bold pr-4">
Org:
</td>
<td>
Org Name
</td>
</tr>
<tr>
<td class="font-bold pr-4">
Duration:
</td>
<td>
2022-02-06 - 2024-02-07
</td>
</tr>
<tr>
<td class="font-bold pr-4">
Status:
</td>
<td>
INPROGRESS
</td>
</tr>
<tr>
<td class="font-bold pr-4">
Tags:
</td>
<td>
-
</td>
</tr>
</table>
</div>
<div class="prose border-b border-neutral-300 pb-8" data-djc-id-ca1bcdd="">
<div class="flex justify-between items-start mb-4">
<h3 class="mt-0">Status Updates</h3>
<a
href="/create/1/status_update"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bcea="">
Add status update
</a>
</div>
</div>
<div class="xl:grid xl:grid-cols-2 gap-10">
<div class="border-b border-neutral-300">
<div class="flex justify-between items-start">
<h3 class="mt-0">Team</h3>
<a
href="/edit/1/roles/"
class="not-prose bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bce0="">
Edit Team
</a>
</div>
<div x-data="project_users" data-djc-id-ca1bce1="">
<div @user_delete="onUserDelete" class="flow-root" data-djc-id-ca1bceb="">
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
scope="col"
class="text-left text-sm font-semibold text-gray-900 py-3.5 pl-4 pr-3 sm:pl-0"
>
Name
</th>
<th
scope="col"
class="text-left text-sm font-semibold text-gray-900 py-3.5 px-3"
>
Role
</th>
<th
scope="col"
class="text-left text-sm font-semibold text-gray-900 py-3.5 px-3"
>
<span class="sr-only"> </span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr >
<td
colspan="1"
>
UserName
</td>
<td
colspan="1"
>
Assistant
</td>
<td
colspan="1"
>
</td>
</tr>
<tr >
<td
colspan="1"
>
UserName
</td>
<td
colspan="1"
>
Owner
</td>
<td
colspan="1"
>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div>
<div class="flex justify-between items-start max-xl:mt-6">
<h3 class="mt-0">Contacts</h3>
<a
href="/edit/1/contacts/"
class="not-prose bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bce9="">
Edit Contacts
</a>
</div>
<p class="text-sm italic">No entries</p>
</div>
</div>
</div>
</div>
<div
x-show="openTab === 2"
class="flex flex-col"
>
<div class="prose" data-djc-id-ca1bc9b="" data-djc-id-ca1bcd0="" data-djc-id-ca1bcf2="">
<h3>Notes</h3>
<div class="mt-8">
<div class="py-2" style="border-top: solid 1px lightgrey">
<div class="flex justify-between gap-4 pt-2">
<span class="prose-sm prose-figure">
2025-02-07T08:59:58.689Z
</span>
<div data-djc-id-ca1bcf7="">
<a
href="/edit/1/note/1/"
class="text-gray-400 hover:text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="text-gray-400 hover:text-gray-500 h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcfc="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</a>
</div>
</div>
<p class="my-0 text-gray-900">
Test note 1
</p>
<details class="px-8 py-2">
<summary class="font-medium">
Comments
</summary>
<div class="text-right">
<a
href="/create/1/note/1/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bcf8="">
Add comment
</a>
</div>
</details>
</div>
<div class="py-2" style="border-top: solid 1px lightgrey">
<div class="flex justify-between gap-4 pt-2">
<span class="prose-sm prose-figure">
2025-02-07T08:59:58.689Z
</span>
<div data-djc-id-ca1bcf9="">
<a
href="/edit/1/note/2/"
class="text-gray-400 hover:text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="text-gray-400 hover:text-gray-500 h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bcfd="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</a>
</div>
</div>
<p class="my-0 text-gray-900">
Test note 2
</p>
<details class="px-8 py-2">
<summary class="font-medium">
Comments
</summary>
<div class="text-right">
<a
href="/create/1/note/2/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bcfa="">
Add comment
</a>
</div>
</details>
</div>
</div>
<a
href="/create/1/note/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bcfb="">
Add Note
</a>
</div>
</div>
<div
x-show="openTab === 3"
class="flex flex-col"
>
<div class="prose" data-djc-id-ca1bc9b="" data-djc-id-ca1bcd1="" data-djc-id-ca1bcff="">
<h3>Notes</h3>
<div class="mt-8">
<div class="py-2" style="border-top: solid 1px lightgrey">
<div class="flex justify-between gap-4 pt-2">
<span class="prose-sm prose-figure">
2024-02-07T11:20:49.085Z
</span>
<div data-djc-id-ca1bd00="">
<a
href="/edit/1/note/1/"
class="text-gray-400 hover:text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="text-gray-400 hover:text-gray-500 h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd03="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</a>
</div>
</div>
<p class="my-0 text-gray-900">
Test note x
</p>
<details class="px-8 py-2">
<summary class="font-medium">
Comments
</summary>
<div class="text-right">
<a
href="/create/1/note/1/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bd01="">
Add comment
</a>
</div>
</details>
</div>
</div>
<a
href="/create/1/note/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bd02="">
Add Note
</a>
</div>
</div>
<div
x-show="openTab === 4"
class="flex flex-col"
>
<div class="prose" data-djc-id-ca1bc9b="" data-djc-id-ca1bcd2="" data-djc-id-ca1bd05="">
<h3>Notes</h3>
<div class="mt-8">
<div class="py-2" style="border-top: solid 1px lightgrey">
<div class="flex justify-between gap-4 pt-2">
<span class="prose-sm prose-figure">
2024-02-07T11:20:49.085Z
</span>
<div data-djc-id-ca1bd06="">
<a
href="/edit/1/note/2/"
class="text-gray-400 hover:text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="text-gray-400 hover:text-gray-500 h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd09="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</a>
</div>
</div>
<p class="my-0 text-gray-900">
Test note 2
</p>
<details class="px-8 py-2">
<summary class="font-medium">
Comments
</summary>
<div class="text-right">
<a
href="/create/1/note/2/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bd07="">
Add comment
</a>
</div>
</details>
</div>
</div>
<a
href="/create/1/note/"
class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm no-underline"
data-djc-id-ca1bd08="">
Add Note
</a>
</div>
</div>
<div
x-show="openTab === 5"
class="flex flex-col"
>
<div class="flex flex-col gap-y-3" data-djc-id-ca1bc9b="" data-djc-id-ca1bcd3="" data-djc-id-ca1bd0b="">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: true}"
data-djc-id-ca1bd10="">
<div
@click="togglePanel"
class="flex gap-x-2 prose pb-2 cursor-pointer"
>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd1c="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd24="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
<h3 class="m-0">
Phase 1
</h3>
</div>
<div x-show="isOpen" >
<div class="flex flex-col" data-djc-id-ca1bd1d="">
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd25="">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full bg-blue-600 group-hover:bg-blue-500 transition">
<div class="p-2" data-djc-id-ca1bd29="">
<span
class="text-white group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" class="text-white h-6 w-6 shrink-0" style="width: 20px; height: 20px;" data-djc-id-ca1bd2a="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="18" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd28="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 12
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd2b="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd31="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[{&quot;url&quot;: &quot;http://localhost:8000/create/bookmmarks/9/&quot;, &quot;text&quot;: &quot;Test bookmark&quot;, &quot;tags&quot;: []}]'
}"
data-djc-id-ca1bd2c="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bd32="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
checked
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd3c="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd3d="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd3e="">
<div>
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bd44="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd45="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd46="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd47="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd4c="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd4d="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: true}"
data-djc-id-ca1bd18="">
<div
@click="togglePanel"
class="flex gap-x-2 prose pb-2 cursor-pointer"
>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd4e="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd50="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
<h3 class="m-0">
Phase 2
</h3>
</div>
<div x-show="isOpen" >
<div class="flex flex-col" data-djc-id-ca1bd4f="">
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd51="">
<div title="A dependent dependency has not been met!" data-djc-id-ca1bd5d="">
<span
class="text-black group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" class="text-black h-6 w-6 shrink-0" style="width: 32px; height: 32px;" data-djc-id-ca1bd5e="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="14" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd52="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 16
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd5f="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd65="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
class="pb-3 mb-3 border-b border-solid border-gray-300"
x-data="project_output_dependency"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bd60="">
<div class="w-full bg-gray-100 text-sm p-2" style="min-height: 100px;">
<span class="text-gray-500 italic">
<div class="float-left pr-1" data-djc-id-ca1bd66="">
<span
class="text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" class="text-gray-500 h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd69="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
Missing '' from
<a
href="/phase/1/PHASE_3"
target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline"
data-djc-id-ca1bd67="">
</a>
</span>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd68="">
<div>
This output does not have any attachments.
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bd6a="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
disabled
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
disabled
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd6b="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
disabled
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
</div>
</div>
</template>
</div>
</div>
</template>
</div>
</div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bd64="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bd6c="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd6d="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd6e="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd6f="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bd70="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd71="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd72="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd73="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd74="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd75="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd53="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="21" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd54="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 9
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd76="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd78="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bd77="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bd79="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd7a="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd7b="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd7c="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bd7d="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd7e="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd7f="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd80="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd81="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd82="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd55="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="22" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd56="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 8
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd83="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd85="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bd84="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bd86="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd87="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd88="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd89="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bd8a="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd8b="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd8c="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd8d="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd8e="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd8f="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd57="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="23" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd58="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 7
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd90="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd92="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bd91="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bd93="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd94="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd95="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd96="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bd97="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd98="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd99="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bd9a="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd9b="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bd9c="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd59="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="24" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd5a="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 6
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bd9d="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bd9f="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bd9e="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bda0="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bda1="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bda2="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bda3="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bda4="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bda5="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bda6="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bda7="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bda8="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bda9="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bd5b="">
<div title="A dependent dependency has not been met!" data-djc-id-ca1bdaa="">
<span
class="text-black group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" class="text-black h-6 w-6 shrink-0" style="width: 32px; height: 32px;" data-djc-id-ca1bdab="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="14" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bd5c="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 16
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bdac="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bdaf="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
class="pb-3 mb-3 border-b border-solid border-gray-300"
x-data="project_output_dependency"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bdad="">
<div class="w-full bg-gray-100 text-sm p-2" style="min-height: 100px;">
<span class="text-gray-500 italic">
<div class="float-left pr-1" data-djc-id-ca1bdb0="">
<span
class="text-gray-500 group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" class="text-gray-500 h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bdb3="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
Missing '' from
<a
href="/phase/1/PHASE_3"
target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline"
data-djc-id-ca1bdb1="">
</a>
</span>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdb2="">
<div>
This output does not have any attachments.
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bdb4="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
disabled
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
disabled
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdb5="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
disabled
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
</div>
</div>
</template>
</div>
</div>
</template>
</div>
</div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bdae="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bdb6="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdb7="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdb8="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdb9="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bdba="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdbb="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdbc="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdbd="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdbe="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdbf="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: true}"
data-djc-id-ca1bd19="">
<div
@click="togglePanel"
class="flex gap-x-2 prose pb-2 cursor-pointer"
>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bdc0="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bdc2="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
<h3 class="m-0">
Phase 3
</h3>
</div>
<div x-show="isOpen" >
<div class="flex flex-col" data-djc-id-ca1bdc1="">
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bdc3="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="14" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bdc4="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 16
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bdcb="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bdcd="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bdcc="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bdce="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdcf="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdd0="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdd1="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bdd2="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdd3="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdd4="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdd5="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdd6="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdd7="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bdc5="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="15" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bdc6="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 15
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bdd8="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bdda="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bdd9="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bddb="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bddc="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bddd="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdde="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bddf="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bde0="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bde1="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bde2="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bde3="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bde4="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bdc7="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="16" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bdc8="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 14
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bde5="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bde7="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bde6="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bde8="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bde9="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdea="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdeb="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bdec="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bded="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdee="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdef="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdf0="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdf1="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1bdc9="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="17" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1bdca="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 13
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bdf2="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1bdf4="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1bdf3="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1bdf5="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdf6="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdf7="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdf8="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1bdf9="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdfa="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdfb="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1bdfc="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdfd="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1bdfe="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: true}"
data-djc-id-ca1bd1a="">
<div
@click="togglePanel"
class="flex gap-x-2 prose pb-2 cursor-pointer"
>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1bdff="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1be01="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
<h3 class="m-0">
Phase 4
</h3>
</div>
<div x-show="isOpen" >
<div class="flex flex-col" data-djc-id-ca1be00="">
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1be02="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="25" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1be03="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 5
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1be06="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1be08="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1be07="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1be09="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be0a="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be0b="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1be0c="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1be0d="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be0e="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be0f="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1be10="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be11="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be12="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1be04="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="26" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1be05="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 4
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1be13="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1be15="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1be14="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1be16="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be17="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be18="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1be19="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1be1a="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be1b="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be1c="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1be1d="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be1e="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be1f="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: true}"
data-djc-id-ca1bd1b="">
<div
@click="togglePanel"
class="flex gap-x-2 prose pb-2 cursor-pointer"
>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1be20="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1be22="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
<h3 class="m-0">
Phase 5
</h3>
</div>
<div x-show="isOpen" >
<div class="flex flex-col" data-djc-id-ca1be21="">
<div class="flex gap-x-3">
<div>
<span class="flex h-9 items-center" data-djc-id-ca1be23="">
<span class="flex h-9 items-center" aria-hidden="true">
<span class="relative z-10 flex h-8 w-8 items-center justify-center rounded-full border-2 border-gray-300 bg-white">
</span>
</span>
</span>
</div>
<div class="w-full">
<div
x-data="expansion_panel"
data-init="{&quot;open&quot;: false}"
data-panelid="27" class="border-b border-solid border-gray-300 pb-2 mb-3"
data-djc-id-ca1be24="">
<div
@click="togglePanel"
class="flex align-center justify-between pb-2 cursor-pointer"
>
<div>
Lorem ipsum 3
</div>
<div :class="{ 'rotate-180': isOpen }" style="width: fit-content;" data-djc-id-ca1be25="">
<span
class="group flex gap-x-3 rounded-md text-sm leading-6 font-semibold"
>
<svg viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" class="h-6 w-6 shrink-0" style="width: 24px; height: 24px;" data-djc-id-ca1be27="">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5" />
</svg>
</span>
</div>
</div>
<div x-show="isOpen" >
<div>
<div
x-data="project_output_form"
x-props="{
initAttachments: '[]'
}"
data-djc-id-ca1be26="">
<form
action="/update"
method="post"
x-data="form"
data-djc-id-ca1be28="">
<div
@click="updateFormModel"
@change="updateFormModel"
>
<textarea
name="description"
class="w-full text-sm p-2 mb-2"
placeholder="Placeholder text"
style="min-height: 100px;"
></textarea>
<div class="flex flex-wrap justify-between items-center gap-y-3">
<div class="flex items-center gap-x-2">
Completed:
<input type='hidden' value='0' name='completed'
/>
<input type="checkbox"
name="completed"
style="height: 20px; width: 20px"
/>
</div>
<div class="flex gap-x-2 ml-auto items-center justify-between basis-52 ">
<button
type="button"
@click="addAttachment" class="bg-white text-gray-800 ring-gray-300 hover:bg-gray-100 focus-visible:outline-gray-600 transition ring-1 ring-inset inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be29="">
Add attachment
</button>
<button
type="button"
@click="onOutputSubmit({ reload: true })" class="bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be2a="">
Save
</button>
</div>
</div>
<div
x-data="project_output_attachments"
x-props="{
...{ attachments: attachments.value, onToggleAttachment: (index) =&gt; toggleAttachmentPreview(index), onSetAttachmentTags: (index, tags) =&gt; setAttachmentTags(index, tags), onUpdateAttachmentData: (index, data) =&gt; updateAttachmentData(index, data), onRemoveAttachment: (index) =&gt; removeAttachment(index) },
}"
class="pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1be2b="">
<div>
This output does not have any attachments, create one below:
</div>
<template x-for="(attachment, index) in attachments.value">
<div class="project-output-form-attachment w-full">
<div class="text-sm flex gap-3 w-full justify-between">
<div x-show="attachment.isPreview">
<a
href="None"
x-bind:href="attachment.url" x-text="attachment.text" target="_blank" class="hover:text-gray-600 !underline inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 no-underline" style="color: cornflowerblue;"
data-djc-id-ca1be2c="">
</a>
</div>
<div x-show="!attachment.isPreview" class="flex flex-col gap-1">
<label for="id_text">Text:</label>
<input
type="text"
name="text"
id="id_text"
maxlength="255"
required
class="text-sm py-1 px-2"
:value="attachment.text"
@change="(ev) => $emit('updateAttachmentData', index, { text: ev.target.value })"
/>
<label for="id_url">Url:</label>
<input
type="url"
name="url"
id="id_url"
required
class="text-sm py-1 px-2"
:value="attachment.url"
@change="(ev) => $emit('updateAttachmentData', index, { url: ev.target.value })"
/>
</div>
<div class="flex gap-2 flex-wrap justify-end">
<div>
<button
type="button"
x-text="attachment.isPreview ? 'Edit' : 'Preview'" @click="() => $emit('toggleAttachment', index)" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be2d="">
Edit
</button>
</div>
<div>
<button
type="button"
@click="() => $emit('removeAttachment', index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be2e="">
Remove
</button>
</div>
</div>
</div>
<div
x-data="tags"
x-props="{
initAllTags: '[&quot;Tag 9&quot;, &quot;Tag 10&quot;, &quot;Tag 11&quot;, &quot;Tag 12&quot;, &quot;Tag 13&quot;, &quot;Tag 14&quot;, &quot;Tag 15&quot;, &quot;Tag 16&quot;, &quot;Tag 17&quot;, &quot;Tag 18&quot;, &quot;Tag 19&quot;, &quot;Tag 20&quot;]',
initTags: attachment.tags,
onChange: (tags) => $emit('setAttachmentTags', index, tags),
}"
class="pb-8 pt-3 flex flex-col gap-y-3 items-start"
data-djc-id-ca1be2f="">
<input x-ref="tagsInput" type="hidden" name="tags" value="" />
<p class="text-sm">
Tags:
</p>
<template x-for="(tag, index) in tags.value">
<div
class="tag text-sm flex flex-col gap-1 w-full"
style="max-width: 300px"
>
<div class="flex gap-6 w-full justify-between items-center">
<select
name="_tags"
class="flex-auto py-1 px-2"
@change="(ev) => setTag(index, ev.target.value)"
>
<template x-for="option in tag.options">
<option
:value="option"
:selected="option === tag.value"
x-text="option"
>
</option>
</template>
</select>
<div>
<button
type="button"
@click="removeTag(index)" class="!py-1 bg-red-600 text-white hover:bg-red-500 focus-visible:outline-red-600 inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be30="">
Remove
</button>
</div>
</div>
</div>
</template>
<div x-show="tags.value.length < allTags.value.length">
<button
type="button"
@click="addTag" class="!py-1 bg-blue-600 text-white hover:bg-blue-500 focus-visible:outline-blue-600 transition inline-flex w-full text-sm font-semibold sm:mt-0 sm:w-auto focus-visible:outline-2 focus-visible:outline-offset-2 px-3 py-2 justify-center rounded-md shadow-sm"
data-djc-id-ca1be31="">
Add tag
</button>
</div>
</div>
</div>
</template>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</article>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<script src="//unpkg.com/@alpinejs/anchor" defer></script>
<script src="https://cdn.jsdelivr.net/npm/alpine-reactivity@0.1.10/dist/cdn.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/alpine-composition@0.1.27/dist/cdn.min.js"></script>
<script src="//unpkg.com/alpinejs" defer></script>
<script type="text/javascript" src="js/htmx.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="django_components/django_components.min.js"></script><script type="application/json" data-djc>{"loadedCssUrls": [], "loadedJsUrls": ["L2NvbXBvbmVudHMvY2FjaGUvQmFzZV9kMTZhNmQuanM=", "L2NvbXBvbmVudHMvY2FjaGUvQm9va21hcmtfMWZkMDFmLmpz", "L2NvbXBvbmVudHMvY2FjaGUvQm9va21hcmtzXzg3ODZmMS5qcw==", "L2NvbXBvbmVudHMvY2FjaGUvRXhwYW5zaW9uUGFuZWxfNjkwMjM5Lmpz", "L2NvbXBvbmVudHMvY2FjaGUvRm9ybV83ODhlMTIuanM=", "L2NvbXBvbmVudHMvY2FjaGUvTGF5b3V0XzZhYmE2Yy5qcw==", "L2NvbXBvbmVudHMvY2FjaGUvUHJvamVjdE91dHB1dEF0dGFjaG1lbnRzXzE2NGQ2NC5qcw==", "L2NvbXBvbmVudHMvY2FjaGUvUHJvamVjdE91dHB1dERlcGVuZGVuY3lfZWVkMzI4Lmpz", "L2NvbXBvbmVudHMvY2FjaGUvUHJvamVjdE91dHB1dEZvcm1fODQ3YjM0Lmpz", "L2NvbXBvbmVudHMvY2FjaGUvUHJvamVjdFVzZXJzX2U1NTFmZC5qcw==", "L2NvbXBvbmVudHMvY2FjaGUvVGFnc19iNzMxNTMuanM=", "L2NvbXBvbmVudHMvY2FjaGUvX1RhYnNJbXBsX2NlZWNjMS5qcw=="], "toLoadCssTags": [], "toLoadJsTags": []}</script><script>document.addEventListener('alpine:init', () => {
// NOTE: Defined as standalone function so we can call it variable initialization
const computeSidebarState = (prevState) => {
const width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
// We automatically hide the sidebar when window is smaller than 1024px
const sidebarBreakpoint = 1024;
if (!prevState && width >= sidebarBreakpoint) {
return true;
} else if (prevState && width < sidebarBreakpoint) {
return false;
} else {
return prevState;
}
};
Alpine.data('layout', () => ({
// Variables
sidebarOpen: computeSidebarState(false),
init() {
this.onWindowResize();
},
// Handlers
toggleSidebar() {
this.sidebarOpen = !this.sidebarOpen;
},
onWindowResize() {
this.sidebarOpen = computeSidebarState(this.sidebarOpen);
},
}));
});</script><script>////////////////////////////////////////////////////////////////
// base.js
////////////////////////////////////////////////////////////////
/** Global JS state / methods */
const app = {
// NOTE: queryManager.js MUST be loaded before this script!
query: createQueryManager(),
};
app.query.load();
////////////////////////////////////////////////////////////////
// queryManager.js
////////////////////////////////////////////////////////////////
/**
* Callback when a URL's query param changes.
*
* @callback OnParamChangeCallback
* @param {string | null} newValue - New value of the query param.
* @param {string | null} oldValue - Old value of the query param.
*/
/**
* Function that can be called once to remove the registered callback.
*
* @callback UnregisterFn
*/
/**
* Callback for modifying URL.
*
* @callback OnUrlModifyCallback
* @param {URL} currUrl - Current URL.
* @returns {URL | string} New URL.
*/
/**
* Singular interface for manipulating URL search/query parameters
* and reacting to changes.
*
* See https://developer.mozilla.org/en-US/docs/Web/API/Location/search
*/
const createQueryManager = () => {
/**
* @type {Record<string, OnParamChangeCallback[]>}
*/
const callbacks = {};
/**
* Store previous values of query params, so we can provide both new and old
* values to the callbacks.
*
* NOTE: Use `setParamValue` instead of setting values directly.
*
* @type {Record<string, string | null>}
*/
const previousParamValues = {};
/**
* @param {string} key
* @param {string | null} newValue
*/
const setParamValue = (key, newValue) => {
const oldValue =
previousParamValues[key] === undefined ? null : previousParamValues[key];
previousParamValues[key] = newValue;
const paramCallbacks = callbacks[key] || [];
paramCallbacks.forEach((cb) => cb(newValue, oldValue));
};
/**
* Register a listener that will be triggered when a value changes for the query param
* of given name.
*
* Returns a function that can be called once to remove the registered callback.
*
* @param {string} paramName
* @param {OnParamChangeCallback} callback
* @returns {UnregisterFn}
*/
const registerParam = (paramName, callback) => {
if (callbacks[paramName] == undefined) {
callbacks[paramName] = [];
}
callbacks[paramName].push(callback);
// Run the callback once if the query param already has some value
if (previousParamValues[paramName] != null) {
callback(previousParamValues[paramName], null);
}
// Return a function that can be called once to remove the registered callback
let unregisterCalled = false;
const unregister = () => {
if (unregisterCalled) return;
unregisterCalled = true;
unregisterParam(paramName, callback);
};
return unregister;
};
/**
* Unregister a callback that was previously registered with `registerParam`
* for the query param of given name.
*
* @param {string} paramName
* @param {OnParamChangeCallback} callback
*/
const unregisterParam = (paramName, callback) => {
// Nothing to do
if (callbacks[paramName] == undefined) return;
// Remove one instance of callback from the array to simulate similar behavior
// as browser's addEventListener/removeEventListener.
// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
const indexToRemove = callbacks[paramName].indexOf(callback);
if (indexToRemove !== -1) {
callbacks[paramName].splice(indexToRemove, 1);
}
};
/**
* Shared logic for modifying the page's URL in-place (without reload).
*
* @param {OnUrlModifyCallback} mapFn
*/
const modifyUrl = (mapFn) => {
// Prepare current URL
const currUrl = new URL(globalThis.location.href);
// Let the user of this function decide how to transform the URL
let updatedUrl = mapFn(currUrl);
// Update browser URL without reloading the page
// See https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
// And https://stackoverflow.com/a/3354511/9788634
globalThis.history.replaceState(null, "", updatedUrl.toString());
};
/**
* Set query parameters to the URL.
*
* If the URL already contains query params of the same name, these will be overwritten.
*
* @param {Record<string, string>} params
*/
const setParams = (params) => {
modifyUrl((currUrl) => {
Object.entries(params).forEach(([key, val]) => {
currUrl.searchParams.set(key, val);
});
return currUrl.href;
});
// Trigger callbacks for all params that were set.
Object.entries(params).forEach(([key, val]) => setParamValue(key, val));
};
/** Clear all query parameters from the URL. */
const clearParams = () => {
modifyUrl((currUrl) => {
currUrl.search = "";
return currUrl.href;
});
// Trigger callbacks for all params that were unset.
Object.entries(previousParamValues)
.filter(([key, val]) => val !== null)
.forEach(([key, val]) => setParamValue(key, val));
};
/** Load query params from the current page URL, triggering any registered callbacks. */
const load = () => {
const currUrl = new URL(globalThis.location.href);
currUrl.searchParams.forEach((value, key) => setParamValue(key, value));
};
return {
setParams,
clearParams,
registerParam,
unregisterParam,
load,
};
};
////////////////////////////////////////////////////////////////
// submitForm.js
////////////////////////////////////////////////////////////////
/**
* @param {HTMLFormElement} formEl
*/
const getFormData = (formEl) => {
return Object.fromEntries(new FormData(formEl));
};
/**
* @param {HTMLFormElement} formEl
* @param {object} formData
*/
const submitForm = (formEl, data, { reload = false } = {}) => {
// Do not submit anything when the form doesn't specify the target URL
if (!formEl.hasAttribute('action')) Promise.resolve();
return axios.post(formEl.action, data, {
method: formEl.method,
})
.then((response) => {
if (reload) location.reload();
})
.catch((error) => {
console.error(error);
});
};</script><script>const useContextMenu = (reactivity) => {
const { ref } = reactivity;
const contextMenuItem = ref(null);
const contextMenuRef = ref(null);
const contextMenuReset = () => {
contextMenuItem.value = null;
contextMenuRef.value = null;
};
const onContextMenuToggle = (data) => {
const { item, el } = data;
const willUntoggle = contextMenuItem.value && contextMenuItem.value.id === item.id;
// NOTE: We need to remove the component first before we can re-render it
// at a different place using `x-anchor`.
contextMenuItem.value = null;
contextMenuRef.value = null;
// If we are to untoggled currently-active menu, since we've already set values to null,
// there's nothing more to be done.
if (willUntoggle) {
return;
}
// Otherwise, we should open a new menu
setTimeout(() => {
contextMenuItem.value = item;
contextMenuRef.value = el;
});
};
const onContextMenuClickOutside = (event) => {
contextMenuReset();
};
return {
contextMenuItem,
contextMenuRef,
contextMenuReset,
onContextMenuToggle,
onContextMenuClickOutside,
};
};
// Define component similarly to defining Vue components
const Bookmarks = AlpineComposition.defineComponent({
name: "bookmarks",
props: {},
emits: {},
setup(props, vm, reactivity) {
const {
contextMenuItem,
contextMenuRef,
onContextMenuToggle,
onContextMenuClickOutside,
} = useContextMenu(reactivity);
return {
contextMenuItem,
contextMenuRef,
onContextMenuToggle,
onContextMenuClickOutside,
};
},
});
document.addEventListener('alpine:init', () => {
AlpineComposition.registerComponent(Alpine, Bookmarks);
});</script><script>// Define component similarly to defining Vue components
const Bookmark = AlpineComposition.defineComponent({
name: "bookmark",
props: {
bookmark: { type: Object, required: true },
},
emits: {
menuToggle: (obj) => true,
},
setup(props, vm) {
const onMenuToggle = () => {
vm.$emit('menuToggle', { item: props.bookmark, el: vm.$refs.bookmark_menu });
}
return {
bookmark: props.bookmark,
onMenuToggle,
};
},
});
document.addEventListener('alpine:init', () => {
AlpineComposition.registerComponent(Alpine, Bookmark);
});</script><script>document.addEventListener("alpine:init", () => {
Alpine.data("tabs", () => ({
// Variables
openTab: 1,
name: null,
// Computed
get tabQueryName() {
return `tabs-${this.name}`;
},
// Methods
init() {
// If we provided the `name` argument to the "tabs" component, then
// we register a listener for the query param `tabs-{name}`.
// The value of this query param is the current active tab (index).
//
// When user changes the currently-open tab, we push that info to the URL
// by updating the `tabs-{name}` query param.
//
// And when we navigate to a URL that already had `tabs-{name}` query param
// set, we load that tab.
if (this.$el.dataset['init']) {
const { name } = JSON.parse(this.$el.dataset['init']);
if (name) {
this.name = name
app.query.registerParam(
this.tabQueryName,
(newVal, oldVal) => this.onTabQueryParamChange(newVal, oldVal),
);
}
}
// Sometimes, the scrollable tab content area is scrolled to the bottom
// when the page loads. So we ensure here that the we scroll to the top if not already
// Also see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop
const containerEl = this.$refs.container;
if (containerEl.scrollTop) {
this.$refs.container.scrollTop = 0;
}
},
/**
* Set the current open tab and push the info to query params.
*
* @param {number} tabIndex
*/
setOpenTab(tabIndex) {
this.openTab = tabIndex;
if (this.name) {
app.query.setParams({ [this.tabQueryName]: tabIndex });
}
},
/**
* Handle tab change from URL
*
* @param {*} newValue
* @param {*} oldValue
*/
onTabQueryParamChange(newValue, oldValue) {
if (newValue == null) return;
const newValNum = typeof newValue === "number" ? newValue : Number.parseInt(newValue);
if (newValNum === this.openTab) return;
this.setOpenTab(newValNum);
},
}));
});</script><script>document.addEventListener('alpine:init', () => {
Alpine.data('project_users', () => ({
// Variables
isDeleteDialogOpen: false,
role: null,
// Methods
onUserDelete(event) {
const { role } = event.detail;
this.role = role;
this.isDeleteDialogOpen = !!role;
},
}));
});</script><script>document.addEventListener("alpine:init", () => {
Alpine.data("expansion_panel", () => ({
// Variables
isOpen: false,
// Methods
init() {
const initDataStr = this.$el.dataset.init;
const initData = JSON.parse(initDataStr);
this.isOpen = initData.open;
const panelId = this.$el.dataset.panelid;
const panel = new URL(location.href).searchParams.get("panel");
if (panel && panel == panelId) {
this.isOpen = true;
this.$el.scrollIntoView();
}
},
togglePanel(event) {
this.isOpen = !this.isOpen;
},
}));
});</script><script>// Define component similarly to defining Vue components
const ProjectOutputForm = AlpineComposition.defineComponent({
name: 'project_output_form',
props: {
initAttachments: { type: String, required: true },
},
// Instead of Alpine's init(), use setup()
// Props are passed down as reactive props, same as in Vue
// Second argument is the Alpine component instance.
setup(props, vm, { ref, nextTick, watch }) {
const attachments = ref([]);
// Set the initial state
if (props.initAttachments) {
attachments.value = JSON.parse(props.initAttachments).map(({ url, text, tags }) => ({
url,
text,
isPreview: true,
tags,
}));
}
watch(attachments, () => {
onAttachmentsChange();
}, { immediate: true });
// Methods
const addAttachment = () => {
attachments.value = [...attachments.value, { url: "", text: "", tags: [], isPreview: false }];
};
const removeAttachment = (index) => {
attachments.value = attachments.value.filter((_, i) => i !== index);
// NOTE: For unknown reason, AlpineJS removes the attachment from for-loop
// only on second click. So we do so ourselves
const attachmentEls = [...vm.$el.querySelectorAll('.project-output-form-attachment')];
if (attachmentEls.length > attachments.value.length) {
attachmentEls[index].remove();
}
// Send the request to remove the attachment in the server too, but
// don't yet reload the page in case user is editing other attachments.
onOutputSubmit({ reload: false });
};
const setAttachmentTags = (index, tags) => {
attachments.value = attachments.value.map((attach, currIndex) => {
if (index !== currIndex) return attach;
return { ...attach, tags };
});
};
const updateAttachmentData = (index, data) => {
attachments.value = attachments.value.map((attach, currIndex) => {
if (index !== currIndex) return attach;
return { ...attach, ...data };
});
};
const toggleAttachmentPreview = (index) => {
let didCloseEditing = false;
attachments.value = attachments.value.map((attach, i) => {
if (index === i) {
attach.isPreview = !attach.isPreview;
if (attach.isPreview) didCloseEditing = true;
}
return attach;
});
if (didCloseEditing) onOutputSubmit({ reload: false });
};
// When attachments are added or removed, we add/remove HTML by AlpineJS,
// so user doesn't have to refresh the page.
function onAttachmentsChange() {
// We wait until the HTML is updated...
nextTick(() => {
// ...Then populate the generated HTML
const attachmentEls = [...vm.$el.querySelectorAll('.project-output-form-attachment')];
attachmentEls.forEach((attachEl, index) => {
if (index >= attachments.value.length) return;
const attachment = attachments.value[index];
attachEl.querySelector('input[name="url"]').value = attachment.url;
attachEl.querySelector('input[name="text"]').value = attachment.text;
});
});
}
const onOutputSubmit = ({ reload }) => {
/** @type {HTMLFormElement} */
const formEl = vm.$el.querySelector('form');
const formData = Object.fromEntries(new FormData(formEl));
const data = {
description: formData.description,
completed: formData.completed.toLowerCase() === "on",
attachments: attachments.value.map(({ text, url, tags }) => ({ text, url, tags })),
};
axios.post(formEl.action, data, {
method: formEl.method,
})
.then((response) => {
if (reload) location.reload();
})
.catch((error) => {
console.error(error);
});
};
return {
attachments,
addAttachment,
removeAttachment,
setAttachmentTags,
updateAttachmentData,
toggleAttachmentPreview,
onOutputSubmit,
};
},
});
document.addEventListener('alpine:init', () => {
AlpineComposition.registerComponent(Alpine, ProjectOutputForm);
});</script><script>document.addEventListener('alpine:init', () => {
Alpine.data('form', () => {
const data = Alpine.reactive({
// Variables
formData: {},
isSubmitting: false,
// Methods
updateFormModel(event) {
const form = this.$el.closest("form");
if (!form) {
this.formData = null;
return;
};
const formDataObj = new FormData(form)
this.formData = [...formDataObj.entries()].reduce((agg, [key, val]) => {
agg[key] = val;
return agg;
}, {});
},
onSubmit(event) {
if (this.isSubmitting) return;
this.isSubmitting = true;
event.target.submit();
},
});
// Detect when Alpine's form state has changed and emit event when that happens
// NOTE: Alpine's reactivity is based on @vue/reactivity
Alpine.watch(() => data.formData, (newVal, oldVal) => {
const hasDataChanged = JSON.stringify(newVal || null) !== JSON.stringify(oldVal || null);
if (!hasDataChanged) return;
data.$dispatch('change', newVal);
});
return data;
});
});</script><script>const ProjectOutputAttachments = AlpineComposition.defineComponent({
name: "project_output_attachments",
props: {
attachments: { type: Object, required: true },
},
emits: {
updateAttachmentData: (index, data) => true,
setAttachmentTags: (index, tags) => true,
removeAttachment: (index) => true,
toggleAttachment: (index) => true,
},
setup(props, vm, { toRefs, watch }) {
const { attachments } = toRefs(props);
return {
attachments,
};
},
});
document.addEventListener("alpine:init", () => {
AlpineComposition.registerComponent(Alpine, ProjectOutputAttachments);
});</script><script>// Define component similarly to defining Vue components
const Tags = AlpineComposition.defineComponent({
name: "tags",
props: {
initAllTags: { type: String, required: true },
initTags: { type: Array, required: true },
},
emits: {
change: () => true,
},
// Instead of Alpine's init(), use setup()
// Props are passed down as reactive props, same as in Vue
// Second argument is the Alpine component instance.
setup(props, vm) {
const { ref, watch } = AlpineComposition.createReactivityAPI(vm);
const allTags = ref([]);
const tags = ref([]);
// Set the initial state from HTML
if (props.initAllTags) {
allTags.value = JSON.parse(props.initAllTags);
}
if (props.initTags) {
tags.value = props.initTags.map((t) => ({
value: t,
options: [],
}));
const availableTags = getAvailableTags();
tags.value = tags.value.map((t) => ({
value: t.value,
options: [t.value, ...availableTags],
}));
}
watch(tags, () => {
onTagsChange();
});
onTagsChange();
// Methods
const addTag = () => {
const availableTags = getAvailableTags();
if (!availableTags.length) return;
// Add tag by removing it from available tags
const nextValue = availableTags.shift();
const newSelectedTags = [
...tags.value.map((t) => t.value),
nextValue,
];
// And add it to the selected tags
tags.value = newSelectedTags.map((t) => ({
value: t,
options: [t, ...availableTags],
}));
}
const removeTag = (index) => {
// Remove the removed tag from selected items
tags.value = tags.value.filter((_, i) => i !== index);
// And add it to the available tags
const availableTags = getAvailableTags();
tags.value = tags.value.map((t) => ({
value: t.value,
options: [t.value, ...availableTags],
}));
}
const setTag = (index, value) => {
// Update the value
const oldValue = tags.value[index].value;
tags.value = tags.value.map((t) => ({
value: t.value === oldValue ? value : t.value,
options: t.options,
}));
// Then update the available tags
const availableTags = getAvailableTags();
tags.value = tags.value.map((t) => ({
value: t.value,
options: [t.value, ...availableTags],
}));
}
// When tags are added or removed, we add/remove HTML by AlpineJS,
// so user doesn't have to refresh the page.
function onTagsChange() {
if (vm.$refs.tagsInput) {
vm.$refs.tagsInput.value = tags.value.map((t) => t.value).join(',');
}
// Emit the final list of selected tags
const payload = tags.value.map((t) => t.value);
vm.$emit("change", payload);
}
function getAvailableTags() {
const selectedTagsSet = new Set(tags.value.map((t) => t.value));
return allTags.value.filter((t) => !selectedTagsSet.has(t));
}
return {
tags,
allTags,
addTag,
removeTag,
setTag,
};
},
});
document.addEventListener('alpine:init', () => {
AlpineComposition.registerComponent(Alpine, Tags);
});</script><script>// Define component similarly to defining Vue components
const ProjectOutputDependency = AlpineComposition.defineComponent({
name: 'project_output_dependency',
props: {
initAttachments: { type: String, required: true },
},
// Instead of Alpine's init(), use setup()
// Props are passed down as reactive props, same as in Vue
// Second argument is the Alpine component instance.
setup(props, vm, { ref }) {
const attachments = ref([]);
// Set the initial state from HTML
if (props.initAttachments) {
attachments.value = JSON.parse(props.initAttachments).map(({ url, text, tags }) => ({
url,
text,
tags,
isPreview: true,
}));
}
// Only those variables exposed by returning can be accessed from within HTML
return {
attachments,
};
},
});
document.addEventListener('alpine:init', () => {
AlpineComposition.registerComponent(Alpine, ProjectOutputDependency);
});</script>
<script>
(function () {
const token = 'predictabletoken';
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = token;
});
document.addEventListener('alpine:init', () => {
Alpine.store('csrf', {
token,
});
});
})();
</script>
</body>
</html>
'''
# ---