1
0

initial commit

This commit is contained in:
Tony Lea 2023-05-24 08:29:02 -04:00
commit 99b1372472
79 changed files with 4011 additions and 0 deletions

10
Readme.md Normal file
View File

@ -0,0 +1,10 @@
# Pines UI Library
This is the main repo for the Open Source <a href="https://devdojo.com/pines" target="_blank">Pines UI Library</a>. This repo is simple to setup and get running on your local if you wish to submit a fix or make some additions to the library.
1. Download the contents of the Github repo and store it in a folder.
2. Make sure you have <a href="https://nodejs.org/" target="_blank">NodeJS</a> installed along with the <a href="https://www.npmjs.com/package/http-server" target="_blank">http-server</a> package.
3. CD into your folder and run `http-serve`
4. Visit the localhost URL to see PinesUI
Be sure to visit <a href="https://devdojo.com/questions" target="_blank">DevDojo discussions</a> section to ask questions and get assistance.

111
data.json Normal file
View File

@ -0,0 +1,111 @@
{
"elements" : {
"accordion" : "Accordion",
"alert" : "Alert",
"badge" : "Badge",
"banner" : "Banner",
"breadcrumbs" : "Breadcrumbs",
"button" : "Button",
"card" : "Card",
"checkbox" : "Checkbox",
"context-menu" : "Context Menu",
"copy-to-clipboard" : "Copy to Clipboard",
"date-picker" : "Date Picker",
"dropdown-menu" : "Dropdown Menu",
"full-screen-menu" : "Full Screen Menu",
"full-screen-modal" : "Full Screen Modal",
"menubar" : "Menu Bar",
"modal" : "Modal",
"navigation-menu" : "Navigation Menu",
"pagination" : "Pagination",
"popover" : "Popover",
"progress" : "Progress",
"range-slider": "Range Slider",
"select" : "Select",
"switch" : "Switch",
"table" : "Table",
"table-of-contents" : "Table of Contents",
"tabs" : "Tabs",
"text-animation" : "Text Animation",
"text-input" : "Text Input",
"textarea" : "Textarea",
"tooltip" : "Tooltip",
"typing-effect" : "Typing Effect",
"video" : "Video"
},
"description" : {
"accordion" : "A simple accordion element that can be used to show and hide content.",
"alert" : "An alert element that is used to draw attention.",
"badge" : "A badge element used to highlight new or updated content, indicate status, or convey additional information.",
"banner" : "Call to action banner that stick to the top or bottom of the page.",
"breadcrumbs" : "A breadcrumb navigation element that can be used to show a user's location within a website.",
"button" : "A button element that can be used to trigger an action.",
"card" : "A card element that can be used to display content.",
"checkbox" : "A checkbox element that can be used to select one or more options.",
"context-menu" : "A context menu element that can be used to show a menu of actions for functions.",
"copy-to-clipboard" : "An element that will copy text to clipboard when clicked.",
"date-picker" : "A date picker element that can be used to select a date.",
"dropdown-menu": "A simple dropdown menu element.",
"full-screen-menu" : "A full screen menu element.",
"full-screen-modal" : "A full screen modal element.",
"modal" : "A simple modal element that can be used to show and hide content.",
"menubar" : "A visually persistent menu common in desktop applications, offering convenient access to a consistent set of commands.",
"navigation-menu" : "A simple navigation menu element",
"pagination" : "A pagination element that can be used to navigate through pages of content.",
"popover" : "A popover element that can display rich content in a portal, triggered by a button.",
"range-slider" : "A range slider element that uses the input type range.",
"select" : "A custom select input element that can be used to select an option.",
"switch" : "A simple toggle switch element to enable or disable an option.",
"tabs" : "A tab element that can be used to show and hide content.",
"table-of-contents" : "This element will generate a TOC from an HTML string.",
"text-animation" : "Simple text animation elements.",
"text-input" : "A form input element that can be used to collect user input.",
"tooltip": "A simple tooltip element that can be used to show additional information.",
"typing-effect" : "This is an element that can be used to type text on to the screen.",
"video" : "A customized video element that can be used to display a video."
},
"container" : {
"accordion" : "p-10 box-border flex items-start justify-start max-w-lg mx-auto",
"alert" : "p-10 box-border flex flex-col space-y-5 items-center justify-center max-w-3xl mx-auto",
"badge" : "p-10 box-border flex items-center justify-center space-x-2",
"banner" : "relative overflow-hidden",
"breadcrumbs" : "p-10 box-border flex items-center justify-center mx-auto",
"button" : "p-10 box-border flex space-x-3 items-center justify-center mx-auto",
"card" : "p-10 box-border flex items-center justify-center mx-auto",
"checkbox" : "p-10 box-border flex items-center justify-center mx-auto",
"context-menu" : "p-10 box-border flex items-center justify-center",
"copy-to-clipboard" : "p-10 box-border flex items-center justify-center",
"date-picker" : "p-10 box-border flex items-center justify-center",
"dropdown-menu" : "p-10 box-border flex items-center justify-center",
"full-screen-menu" : "p-10 box-border flex items-center justify-center",
"full-screen-modal" : "rounded-md overflow-hidden",
"modal" : "p-10 box-border flex items-center justify-center",
"menubar" : "p-10 box-border flex items-center justify-center",
"navigation-menu" : "p-10 box-border flex items-center justify-center",
"pagination" : "flex items-end justify-center",
"popover" : "p-10 box-border flex items-center justify-center",
"range-slider" : "p-10 box-border flex items-center justify-center",
"select" : "p-10 box-border flex items-center justify-center",
"switch" : "p-10 box-border flex items-center justify-center",
"tabs" : "p-10 box-border flex items-center justify-center",
"table-of-contents" : "p-10 box-border flex items-center justify-center",
"text-animation" : "py-10 box-border flex items-center justify-center",
"text-input" : "py-10 px-48 box-border flex items-center justify-center",
"tooltip" : "p-10 box-border flex items-center justify-center",
"typing-effect" : "p-10 flex items-center justify-center",
"video" : "py-10 w-[640px] mx-auto box-border flex items-center justify-center"
},
"tailwind_only" : [
"alert",
"badge",
"breadcrumbs",
"button",
"card",
"checkbox",
"range-slider",
"table",
"text-input",
"textarea",
"pagination"
]
}

View File

@ -0,0 +1,50 @@
<div x-data="{
activeAccordion: '',
setActiveAccordion(id) {
this.activeAccordion = (this.activeAccordion == id) ? '' : id
}
}" class="relative w-full max-w-md mx-auto text-xs">
<div x-data="{ id: $id('accordion') }" :class="{ 'border-neutral-200/60 text-neutral-800' : activeAccordion==id, 'border-transparent text-neutral-600 hover:text-neutral-800' : activeAccordion!=id }" class="duration-200 ease-out bg-white border rounded-md cursor-pointer group" x-cloak>
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full px-5 py-4 font-semibold select-none">
<span>What is Pines?</span>
<div :class="{ 'rotate-90': activeAccordion==id }" class="relative flex items-center justify-center w-2.5 h-2.5 duration-300 ease-out">
<div class="absolute w-0.5 h-full bg-neutral-500 group-hover:bg-neutral-800 rounded-full"></div>
<div :class="{ 'rotate-90': activeAccordion==id }" class="absolute w-full h-0.5 ease duration-500 bg-neutral-500 group-hover:bg-neutral-800 rounded-full"></div>
</div>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-5 pt-0 opacity-70">
Pines is a UI library built for AlpineJS and TailwindCSS.
</div>
</div>
</div>
<div x-data="{ id: $id('accordion') }" :class="{ 'border-neutral-200/60 text-neutral-800' : activeAccordion==id, 'border-transparent text-neutral-600 hover:text-neutral-800' : activeAccordion!=id }" class="duration-200 ease-out bg-white border rounded-md cursor-pointer group" x-cloak>
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full px-5 py-4 font-semibold select-none">
<span>How do I install Pines?</span>
<div :class="{ 'rotate-90': activeAccordion==id }" class="relative flex items-center justify-center w-2.5 h-2.5 duration-300 ease-out">
<div class="absolute w-0.5 h-full bg-neutral-500 group-hover:bg-neutral-800 rounded-full"></div>
<div :class="{ 'rotate-90': activeAccordion==id }" class="absolute w-full h-0.5 ease duration-500 bg-neutral-500 group-hover:bg-neutral-800 rounded-full"></div>
</div>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-5 pt-0 opacity-70">
Add AlpineJS and TailwindCSS to your page and then copy and paste any of these elements into your project.
</div>
</div>
</div>
<div x-data="{ id: $id('accordion') }" :class="{ 'border-neutral-200/60 text-neutral-800' : activeAccordion==id, 'border-transparent text-neutral-600 hover:text-neutral-800' : activeAccordion!=id }" class="duration-200 ease-out bg-white border rounded-md cursor-pointer group" x-cloak>
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full px-5 py-4 font-semibold select-none">
<span>Can I use Pines with other libraries or frameworks?</span>
<div :class="{ 'rotate-90': activeAccordion==id }" class="relative flex items-center justify-center w-2.5 h-2.5 duration-300 ease-out">
<div class="absolute w-0.5 h-full bg-neutral-500 group-hover:bg-neutral-800 rounded-full"></div>
<div :class="{ 'rotate-90': activeAccordion==id }" class="absolute w-full h-0.5 ease duration-500 bg-neutral-500 group-hover:bg-neutral-800 rounded-full"></div>
</div>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-5 pt-0 opacity-70">
Absolutely! Pines works with any other library or framework. Pines works especially well with the TALL stack.
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,40 @@
<div x-data="{
activeAccordion: '',
setActiveAccordion(id) {
this.activeAccordion = (this.activeAccordion == id) ? '' : id
}
}" class="relative w-full max-w-md mx-auto text-sm font-normal">
<div x-data="{ id: $id('accordion') }" :class="{ 'text-neutral-900': activeAccordion==id, 'text-neutral-600 hover:text-neutral-900': activeAccordion!=id }" class="cursor-pointer group">
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 pb-1 select-none">
<span>What is Pines?</span>
<svg class="w-5 h-5 duration-300 ease-out" :class="{ '-rotate-[45deg]': activeAccordion==id }" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6" /></svg>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-4 pt-2 opacity-70">
Pines is a UI library built for AlpineJS and TailwindCSS.
</div>
</div>
</div>
<div x-data="{ id: $id('accordion') }" :class="{ 'text-neutral-900': activeAccordion==id, 'text-neutral-600 hover:text-neutral-900': activeAccordion!=id }" class="cursor-pointer group">
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 pb-1 select-none">
<span>How do I install Pines?</span>
<svg class="w-5 h-5 duration-300 ease-out" :class="{ '-rotate-[45deg]': activeAccordion==id }" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6" /></svg>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-4 pt-2 opacity-70">
Add AlpineJS and TailwindCSS to your page and then copy and paste any of these elements into your project.
</div>
</div>
</div>
<div x-data="{ id: $id('accordion') }" :class="{ 'text-neutral-900': activeAccordion==id, 'text-neutral-600 hover:text-neutral-900': activeAccordion!=id }" class="cursor-pointer group">
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 pb-1 select-none">
<span>Can I use Pines with other libraries or frameworks?</span>
<svg class="w-5 h-5 duration-300 ease-out" :class="{ '-rotate-[45deg]': activeAccordion==id }" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m6-6H6" /></svg>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-4 pt-2 opacity-70">
Absolutely! Pines works with any other library or framework. Pines works especially well with the TALL stack.
</div>
</div>
</div>
</div>

40
elements/accordion.html Normal file
View File

@ -0,0 +1,40 @@
<div x-data="{
activeAccordion: '',
setActiveAccordion(id) {
this.activeAccordion = (this.activeAccordion == id) ? '' : id
}
}" class="relative w-full mx-auto overflow-hidden text-sm font-normal bg-white border border-gray-200 divide-y divide-gray-200 rounded-md">
<div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
<span>What is Pines?</span>
<svg class="w-4 h-4 duration-200 ease-out" :class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-4 pt-0 opacity-70">
Pines is a UI library built for AlpineJS and TailwindCSS.
</div>
</div>
</div>
<div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
<span>How do I install Pines?</span>
<svg class="w-4 h-4 duration-200 ease-out" :class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-4 pt-0 opacity-70">
Add AlpineJS and TailwindCSS to your page and then copy and paste any of these elements into your project.
</div>
</div>
</div>
<div x-data="{ id: $id('accordion') }" class="cursor-pointer group">
<button @click="setActiveAccordion(id)" class="flex items-center justify-between w-full p-4 text-left select-none group-hover:underline">
<span>Can I use Pines with other libraries or frameworks?</span>
<svg class="w-4 h-4 duration-200 ease-out" :class="{ 'rotate-180': activeAccordion==id }" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
</button>
<div x-show="activeAccordion==id" x-collapse x-cloak>
<div class="p-4 pt-0 opacity-70">
Absolutely! Pines works with any other library or framework. Pines works especially well with the TALL stack.
</div>
</div>
</div>
</div>

10
elements/accordion.json Normal file
View File

@ -0,0 +1,10 @@
{
"data" : {
"activeAccordion" : "This will contain the string of the active accordion item (example: 'accordion-1')",
"setActiveAccordion(id)" : "This will set the active accordion with the associated id"
},
"alert_notification" : {
"title" : "Not seeing the animation?",
"description" : "We are using the <a href=\"https://alpinejs.dev/plugins/collapse\" target=\"_blank\" class=\"underline\">AlpineJS collapse plug-in</a> in this example. Simply, include it in your project and you will see the collapse plug-in in action."
}
}

View File

@ -0,0 +1,20 @@
<div class="relative w-full rounded-lg border border-transparent bg-blue-600 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>
<div class="relative w-full rounded-lg border border-transparent bg-red-600 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>
<div class="relative w-full rounded-lg border border-transparent bg-green-500 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>
<div class="relative w-full rounded-lg border border-transparent bg-yellow-500 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>

View File

@ -0,0 +1,20 @@
<div class="relative w-full rounded-lg border border-transparent bg-blue-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-blue-600">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>
<div class="relative w-full rounded-lg border border-transparent bg-red-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-red-600">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>
<div class="relative w-full rounded-lg border border-transparent bg-green-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-green-600">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>
<div class="relative w-full rounded-lg border border-transparent bg-yellow-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-yellow-600">
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-80">This is the subtext for your alert message, providing important information or instructions.</div>
</div>

5
elements/alert.html Normal file
View File

@ -0,0 +1,5 @@
<div class="relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-nuetral-900">
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"></polyline><line x1="12" x2="20" y1="19" y2="19"></line></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5>
<div class="text-sm opacity-70">This is the subtext for your alert message, providing important information or instructions.</div>
</div>

View File

@ -0,0 +1,8 @@
<span class="bg-blue-100 text-blue-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-gray-100 text-gray-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-red-100 text-red-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-green-100 text-green-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-yellow-100 text-yellow-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-indigo-100 text-indigo-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-purple-100 text-purple-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-pink-100 text-pink-800 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>

View File

@ -0,0 +1,8 @@
<span class="bg-transparent text-blue-500 border border-blue-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-gray-500 border border-gray-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-red-500 border border-red-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-green-500 border border-green-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-yellow-500 border border-yellow-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-indigo-500 border border-indigo-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-purple-500 border border-purple-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>
<span class="bg-transparent text-pink-500 border border-pink-500 text-xs font-semibold px-2.5 py-0.5 rounded-full">Badge</span>

View File

@ -0,0 +1,32 @@
<span class="bg-transparent text-blue-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-blue-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-gray-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-gray-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-red-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-red-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-green-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-green-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-yellow-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-yellow-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-indigo-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-indigo-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-purple-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-purple-500 rounded-full"></span>
<span>Badge</span>
</span>
<span class="bg-transparent text-pink-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="block w-1.5 h-1.5 -ml-0.5 mr-1 bg-pink-500 rounded-full"></span>
<span>Badge</span>
</span>

View File

@ -0,0 +1,25 @@
<span class="bg-blue-600 text-white relative flex items-center text-xs font-semibold pl-2 pr-2.5 py-1 rounded-full">
<svg class="relative w-3.5 h-3.5 -translate-x-0.5 opacity-90" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm8.706-1.442c1.146-.573 2.437.463 2.126 1.706l-.709 2.836.042-.02a.75.75 0 01.67 1.34l-.04.022c-1.147.573-2.438-.463-2.127-1.706l.71-2.836-.042.02a.75.75 0 11-.671-1.34l.041-.022zM12 9a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd" /></svg>
<span>Badge</span>
</span>
<span class="bg-red-600 text-white relative flex items-center text-xs font-semibold pl-2 pr-2.5 py-1 rounded-full">
<svg class="relative w-3.5 h-3.5 -translate-x-0.5 opacity-90" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-1.72 6.97a.75.75 0 10-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 101.06 1.06L12 13.06l1.72 1.72a.75.75 0 101.06-1.06L13.06 12l1.72-1.72a.75.75 0 10-1.06-1.06L12 10.94l-1.72-1.72z" clip-rule="evenodd" /></svg>
<span>Badge</span>
</span>
<span class="bg-green-600 text-white relative flex items-center text-xs font-semibold pl-2 pr-2.5 py-1 rounded-full">
<svg class="relative w-3.5 h-3.5 -translate-x-0.5 opacity-90" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm13.36-1.814a.75.75 0 10-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.14-.094l3.75-5.25z" clip-rule="evenodd" /></svg>
<span>Badge</span>
</span>
<span class="bg-amber-600 text-white relative flex items-center text-xs font-semibold pl-2 pr-2.5 py-1 rounded-full">
<svg class="relative w-3.5 h-3.5 -translate-x-0.5 opacity-90" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd" /></svg>
<span>Badge</span>
</span>
<span class="bg-indigo-600 text-white relative flex items-center text-xs font-semibold pl-2 pr-2.5 py-1 rounded-full">
<svg class="relative w-3.5 h-3.5 -translate-x-0.5 opacity-90" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm11.378-3.917c-.89-.777-2.366-.777-3.255 0a.75.75 0 01-.988-1.129c1.454-1.272 3.776-1.272 5.23 0 1.513 1.324 1.513 3.518 0 4.842a3.75 3.75 0 01-.837.552c-.676.328-1.028.774-1.028 1.152v.75a.75.75 0 01-1.5 0v-.75c0-1.279 1.06-2.107 1.875-2.502.182-.088.351-.199.503-.331.83-.727.83-1.857 0-2.584zM12 18a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd" /></svg>
<span>Badge</span>
</span>
<span class="bg-black text-white relative flex items-center text-xs font-semibold pl-2 pr-2.5 py-1 rounded-full">
<svg class="relative w-3.5 h-3.5 -translate-x-0.5 opacity-90" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M18.685 19.097A9.723 9.723 0 0021.75 12c0-5.385-4.365-9.75-9.75-9.75S2.25 6.615 2.25 12a9.723 9.723 0 003.065 7.097A9.716 9.716 0 0012 21.75a9.716 9.716 0 006.685-2.653zm-12.54-1.285A7.486 7.486 0 0112 15a7.486 7.486 0 015.855 2.812A8.224 8.224 0 0112 20.25a8.224 8.224 0 01-5.855-2.438zM15.75 9a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z" clip-rule="evenodd" /></svg>
<span>Badge</span>
</span>

3
elements/badge.html Normal file
View File

@ -0,0 +1,3 @@
<span class="rounded-full px-2.5 py-0.5 text-white text-xs font-semibold bg-black">
Badge
</span>

View File

@ -0,0 +1,26 @@
<div x-data="{
bannerVisible: false,
bannerVisibleAfter: 300
}"
x-show="bannerVisible"
x-transition:enter="transition ease-out duration-500"
x-transition:enter-start="translate-y-10"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-10"
x-init="
setTimeout(()=>{ bannerVisible = true }, bannerVisibleAfter);
"
class="fixed bottom-0 left-0 w-full h-10 duration-300 ease-out bg-black shadow-sm" x-cloak>
<div class="flex items-center justify-between w-full h-full px-3 mx-auto max-w-7xl ">
<a href="#" class="flex items-center w-full h-full text-xs leading-6 text-white duration-150 ease-out opacity-90 hover:opacity-100">
<svg class="w-4 h-4 mr-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="none"><path d="M10.1893 8.12241C9.48048 8.50807 9.66948 9.5633 10.4691 9.68456L13.5119 10.0862C13.7557 10.1231 13.7595 10.6536 13.7968 10.8949L14.2545 13.5486C14.377 14.3395 15.4432 14.5267 15.8333 13.8259L17.1207 11.3647C17.309 11.0046 17.702 10.7956 18.1018 10.8845C18.8753 11.1023 19.6663 11.3643 20.3456 11.4084C21.0894 11.4567 21.529 10.5994 21.0501 10.0342C20.6005 9.50359 20.0352 8.75764 19.4669 8.06623C19.2213 7.76746 19.1292 7.3633 19.2863 7.00567L20.1779 4.92643C20.4794 4.23099 19.7551 3.52167 19.0523 3.82031L17.1037 4.83372C16.7404 4.99461 16.3154 4.92545 16.0217 4.65969C15.3919 4.08975 14.6059 3.39451 14.0737 2.95304C13.5028 2.47955 12.6367 2.91341 12.6845 3.64886C12.7276 4.31093 13.0055 5.20996 13.1773 5.98734C13.2677 6.3964 13.041 6.79542 12.658 6.97364L10.1893 8.12241Z" stroke="currentColor" stroke-width="1.5"></path><path d="M12.1575 9.90759L3.19359 18.8714C2.63313 19.3991 2.61799 20.2851 3.16011 20.8317C3.70733 21.3834 4.60355 21.3694 5.13325 20.8008L13.9787 11.9552" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M5 6.25V3.75M3.75 5H6.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M18 20.25V17.75M16.75 19H19.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<strong class="font-semibold">New Feature</strong><span class="block w-px h-4 mx-3 rounded-full bg-neutral-700"></span>
<span>Click here to learn about our latest feature</span>
</a>
<button @click="bannerVisible=false; setTimeout(()=>{ bannerVisible = true }, 1000);" class="flex items-center flex-shrink-0 translate-x-1 ease-out duration-150 justify-center w-6 h-6 p-1.5 text-white rounded-full hover:bg-neutral-800">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-full h-full"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
</div>

View File

@ -0,0 +1,32 @@
<div x-data="{
bannerVisible: false,
bannerVisibleAfter: 300
}" x-show="bannerVisible"
x-transition:enter="transition ease-out duration-500"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
x-init="
setTimeout(()=>{ bannerVisible = true }, bannerVisibleAfter);
"
class="fixed bottom-0 right-0 h-auto px-5 pb-5 duration-300 ease-out w-96 lg:w-full" x-cloak>
<div class="flex flex-col items-center justify-between w-full h-full max-w-4xl p-8 mx-auto bg-white shadow-lg lg:flex-row rounded-xl">
<div class="flex flex-col items-start h-full pb-6 text-xs lg:items-center lg:flex-row lg:pb-0 lg:pr-6 lg:space-x-5 text-neutral-600">
<img src="https://cdn-icons-png.flaticon.com/512/9004/9004938.png" class="w-16 h-16">
<div class="pt-6 lg:pt-0">
<h4 class="w-full mb-1 text-xl font-bold leading-none -translate-y-1 text-neutral-900">Cookie Notice</h4>
<p>We use cookies to make your online experience better. By continuing to browse, you give us your digital consent to indulge you with some sweet, data-filled treats.</p>
</div>
</div>
<div class="flex items-end justify-end w-full pl-3 space-x-3 lg:flex-shrink-0 lg:w-auto">
<button @click="bannerVisible=false; setTimeout(()=>{ bannerVisible = true }, 1000);" class="inline-flex items-center justify-center flex-shrink-0 w-1/2 px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white border-2 rounded-md lg:w-auto text-neutral-600 hover:text-neutral-700 border-neutral-950 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
Deny All
</button>
<button @click="bannerVisible=false; setTimeout(()=>{ bannerVisible = true }, 1000);" class="inline-flex items-center justify-center flex-shrink-0 w-1/2 px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 border-2 rounded-md lg:w-auto bg-neutral-950 border-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
Accept All
</button>
</div>
</div>
</div>

27
elements/banner.html Normal file
View File

@ -0,0 +1,27 @@
<div x-data="{
bannerVisible: false,
bannerVisibleAfter: 300,
}"
x-show="bannerVisible"
x-transition:enter="transition ease-out duration-500"
x-transition:enter-start="-translate-y-10"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="-translate-y-10"
x-init="
setTimeout(()=>{ bannerVisible = true }, bannerVisibleAfter);
"
class="fixed top-0 left-0 w-full h-10 duration-300 ease-out bg-white shadow-sm" x-cloak>
<div class="flex items-center justify-between w-full h-full px-3 mx-auto max-w-7xl ">
<a href="#" class="flex items-center w-full h-full text-xs leading-6 text-black duration-150 ease-out opacity-80 hover:opacity-100">
<svg class="w-4 h-4 mr-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="none"><path d="M10.1893 8.12241C9.48048 8.50807 9.66948 9.5633 10.4691 9.68456L13.5119 10.0862C13.7557 10.1231 13.7595 10.6536 13.7968 10.8949L14.2545 13.5486C14.377 14.3395 15.4432 14.5267 15.8333 13.8259L17.1207 11.3647C17.309 11.0046 17.702 10.7956 18.1018 10.8845C18.8753 11.1023 19.6663 11.3643 20.3456 11.4084C21.0894 11.4567 21.529 10.5994 21.0501 10.0342C20.6005 9.50359 20.0352 8.75764 19.4669 8.06623C19.2213 7.76746 19.1292 7.3633 19.2863 7.00567L20.1779 4.92643C20.4794 4.23099 19.7551 3.52167 19.0523 3.82031L17.1037 4.83372C16.7404 4.99461 16.3154 4.92545 16.0217 4.65969C15.3919 4.08975 14.6059 3.39451 14.0737 2.95304C13.5028 2.47955 12.6367 2.91341 12.6845 3.64886C12.7276 4.31093 13.0055 5.20996 13.1773 5.98734C13.2677 6.3964 13.041 6.79542 12.658 6.97364L10.1893 8.12241Z" stroke="currentColor" stroke-width="1.5"></path><path d="M12.1575 9.90759L3.19359 18.8714C2.63313 19.3991 2.61799 20.2851 3.16011 20.8317C3.70733 21.3834 4.60355 21.3694 5.13325 20.8008L13.9787 11.9552" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M5 6.25V3.75M3.75 5H6.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M18 20.25V17.75M16.75 19H19.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<strong class="font-semibold">New Feature</strong><span class="block w-px h-4 mx-3 rounded-full bg-neutral-200"></span>
<span>Click here to learn about our latest feature</span>
</a>
<button @click="bannerVisible=false; setTimeout(()=>{ bannerVisible = true }, 1000);" class="flex items-center flex-shrink-0 translate-x-1 ease-out duration-150 justify-center w-6 h-6 p-1.5 text-black rounded-full hover:bg-neutral-100">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-full h-full"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
</div>

10
elements/banner.json Normal file
View File

@ -0,0 +1,10 @@
{
"data" : {
"bannerVisible" : "If the banner is visible (default: false)",
"bannerVisibleAfter" : "On initialize the banner will be visible after this many milliseconds"
},
"additional" : {
"description" : "<p>You can remove the <strong>setTimeout</strong> method in the <strong>init()</strong> method if you wish to toggle visibility another way.</p>",
"note" : "Inside the click function on the close button, you may want to remove the setTimeout to prevent the banner from re-showing."
}
}

View File

@ -0,0 +1,30 @@
<nav class="flex justify-between">
<ol class="inline-flex items-center mb-3 space-x-1 text-xs text-neutral-500 [&_.active-breadcrumb]:text-neutral-600 [&_.active-breadcrumb]:font-medium sm:mb-0">
<li class="flex items-center h-full">
<a href="#_" class="inline-flex items-center px-2 py-1.5 space-x-1.5 rounded-md hover:text-neutral-900 hover:bg-neutral-100">
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.6986 3.68267C12.7492 2.77246 11.2512 2.77244 10.3018 3.68263L4.20402 9.52838C3.43486 10.2658 3 11.2852 3 12.3507V19C3 20.1046 3.89543 21 5 21H8.04559C8.59787 21 9.04559 20.5523 9.04559 20V13.4547C9.04559 13.2034 9.24925 13 9.5 13H14.5456C14.7963 13 15 13.2034 15 13.4547V20C15 20.5523 15.4477 21 16 21H19C20.1046 21 21 20.1046 21 19V12.3507C21 11.2851 20.5652 10.2658 19.796 9.52838L13.6986 3.68267Z" fill="currentColor"></path></svg>
<span>Dashboard</span>
</a>
</li>
<svg class="w-5 h-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<li>
<a href="#_" class="inline-flex items-center px-2 py-1.5 space-x-1.5 font-normal rounded-md hover:bg-neutral-100 hover:text-neutral-900 focus:outline-none">
<svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M7.84 1.804A1 1 0 018.82 1h2.36a1 1 0 01.98.804l.331 1.652a6.993 6.993 0 011.929 1.115l1.598-.54a1 1 0 011.186.447l1.18 2.044a1 1 0 01-.205 1.251l-1.267 1.113a7.047 7.047 0 010 2.228l1.267 1.113a1 1 0 01.206 1.25l-1.18 2.045a1 1 0 01-1.187.447l-1.598-.54a6.993 6.993 0 01-1.929 1.115l-.33 1.652a1 1 0 01-.98.804H8.82a1 1 0 01-.98-.804l-.331-1.652a6.993 6.993 0 01-1.929-1.115l-1.598.54a1 1 0 01-1.186-.447l-1.18-2.044a1 1 0 01.205-1.251l1.267-1.114a7.05 7.05 0 010-2.227L1.821 7.773a1 1 0 01-.206-1.25l1.18-2.045a1 1 0 011.187-.447l1.598.54A6.993 6.993 0 017.51 3.456l.33-1.652zM10 13a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd" /></svg>
<span>Settings</span>
</a>
</li>
<svg class="w-5 h-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<li>
<a href="#_" class="inline-flex items-center px-2 py-1.5 space-x-1.5 font-normal rounded-md hover:bg-neutral-100 hover:text-neutral-900 focus:outline-none">
<svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path d="M7 8a3 3 0 100-6 3 3 0 000 6zM14.5 9a2.5 2.5 0 100-5 2.5 2.5 0 000 5zM1.615 16.428a1.224 1.224 0 01-.569-1.175 6.002 6.002 0 0111.908 0c.058.467-.172.92-.57 1.174A9.953 9.953 0 017 18a9.953 9.953 0 01-5.385-1.572zM14.5 16h-.106c.07-.297.088-.611.048-.933a7.47 7.47 0 00-1.588-3.755 4.502 4.502 0 015.874 2.636.818.818 0 01-.36.98A7.465 7.465 0 0114.5 16z" /></svg>
<span>Users</span>
</a>
</li>
<svg class="w-5 h-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<li>
<a class="inline-flex items-center px-2 py-1.5 font-normal rounded cursor-default active-breadcrumb focus:outline-none">
Adam Wathan
</a>
</li>
</ol>
</nav>

View File

@ -0,0 +1,9 @@
<nav class="flex justify-between">
<ol class="inline-flex items-center mb-3 space-x-3 text-sm text-neutral-500 [&_.active-breadcrumb]:text-neutral-500/80 sm:mb-0">
<li class="flex items-center h-full"><a href="#_" class="py-1 hover:text-neutral-900"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M11.47 3.84a.75.75 0 011.06 0l8.69 8.69a.75.75 0 101.06-1.06l-8.689-8.69a2.25 2.25 0 00-3.182 0l-8.69 8.69a.75.75 0 001.061 1.06l8.69-8.69z" /><path d="M12 5.432l8.159 8.159c.03.03.06.058.091.086v6.198c0 1.035-.84 1.875-1.875 1.875H15a.75.75 0 01-.75-.75v-4.5a.75.75 0 00-.75-.75h-3a.75.75 0 00-.75.75V21a.75.75 0 01-.75.75H5.625a1.875 1.875 0 01-1.875-1.875v-6.198a2.29 2.29 0 00.091-.086L12 5.43z" /></svg></a></li>
<span class="mx-2 text-gray-400">/</span>
<li><a href="#_" class="inline-flex items-center py-1 font-normal hover:text-neutral-900 focus:outline-none">Projects</a></li>
<span class="mx-2 text-gray-400">/</span>
<li><a class="inline-flex items-center py-1 font-normal rounded cursor-default active-breadcrumb focus:outline-none">Pines</a></li>
</ol>
</nav>

11
elements/breadcrumbs.html Normal file
View File

@ -0,0 +1,11 @@
<nav class="flex justify-between px-3.5 py-1 border border-neutral-200/60 rounded-md">
<ol class="inline-flex items-center mb-3 space-x-1 text-xs text-neutral-500 [&_.active-breadcrumb]:text-neutral-600 [&_.active-breadcrumb]:font-medium sm:mb-0">
<li class="flex items-center h-full"><a href="#_" class="py-1 hover:text-neutral-900"><svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" ><path d="M2.25 2.25a.75.75 0 000 1.5h1.386c.17 0 .318.114.362.278l2.558 9.592a3.752 3.752 0 00-2.806 3.63c0 .414.336.75.75.75h15.75a.75.75 0 000-1.5H5.378A2.25 2.25 0 017.5 15h11.218a.75.75 0 00.674-.421 60.358 60.358 0 002.96-7.228.75.75 0 00-.525-.965A60.864 60.864 0 005.68 4.509l-.232-.867A1.875 1.875 0 003.636 2.25H2.25zM3.75 20.25a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0zM16.5 20.25a1.5 1.5 0 113 0 1.5 1.5 0 01-3 0z" /></svg></a></li>
<svg class="w-5 h-5 text-gray-400/70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<li><a href="#_" class="inline-flex items-center py-1 font-normal hover:text-neutral-900 focus:outline-none">Checkout</a></li>
<svg class="w-5 h-5 text-gray-400/70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<li><a href="#_" class="inline-flex items-center py-1 font-normal hover:text-neutral-900 focus:outline-none">Payment</a></li>
<svg class="w-5 h-5 text-gray-400/70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<li><a class="inline-flex items-center py-1 font-normal rounded cursor-default active-breadcrumb focus:outline-none">Delivery Address</a></li>
</ol>
</nav>

View File

@ -0,0 +1,23 @@
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none">
Button
</button>

View File

@ -0,0 +1,19 @@
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100">
Button
</button>

View File

@ -0,0 +1,19 @@
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 bg-white border-2 rounded-md text-neutral-900 hover:text-white border-neutral-900 hover:bg-neutral-900">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-600 transition-colors duration-100 bg-white border-2 border-blue-600 rounded-md hover:text-white hover:bg-blue-600">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-600 transition-colors duration-100 bg-white border-2 border-red-600 rounded-md hover:text-white hover:bg-red-600">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-600 transition-colors duration-100 bg-white border-2 border-green-600 rounded-md hover:text-white hover:bg-green-600">
Button
</button>
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 bg-white border-2 border-yellow-500 rounded-md hover:text-white hover:bg-yellow-500">
Button
</button>

3
elements/button.html Normal file
View File

@ -0,0 +1,3 @@
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
Button
</button>

View File

@ -0,0 +1,10 @@
<div class="max-w-sm bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60">
<a href="#_" class="block mb-3">
<h5 class="text-xl font-bold leading-none tracking-tight text-neutral-900">Card Title</h5>
</a>
<p class="mb-4 text-neutral-500">Here are the biggest enterprise technology acquisitions of 2021 so far, in reverse chronological order.</p>
<button class="inline-flex items-center justify-between w-auto h-10 px-4 py-2 text-sm font-medium text-white transition-colors rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none bg-neutral-950 hover:bg-neutral-950/90">
<span>Card Button</span>
<svg class="w-4 h-4 ml-2 -mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div>

View File

@ -0,0 +1,27 @@
<div class="relative max-w-sm overflow-hidden bg-white border rounded-lg shadow-sm border-neutral-200/60">
<img src="https://pbs.twimg.com/profile_banners/716933677/1472653714/1500x500" class="relative z-20 object-cover w-full h-32" />
<div class="absolute top-0 z-50 flex items-center w-full mt-2 translate-y-24 px-7 -translate-x-0">
<div class="w-20 h-20 p-1 bg-white rounded-full">
<img src="https://pbs.twimg.com/profile_images/1362367807887974401/kuJ1OFT1_400x400.jpg" class="w-full h-full rounded-full" />
</div>
<a href="https://twitter.com/adamwathan" target="_blank" class="block mt-6 ml-2">
<h5 class="text-lg font-bold leading-none tracking-tight text-neutral-900">Adam Wathan</h5>
<small class="block mt-1 text-sm font-medium leading-none text-neutral-500">@adamwathan</small>
</a>
<button class="absolute right-0 inline-flex items-center justify-center w-auto px-5 mt-6 text-sm font-medium transition-colors duration-100 rounded-full h-9 mr-7 hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 bg-neutral-900 disabled:pointer-events-none hover:bg-neutral-800 text-neutral-100">
<span>Follow</span>
</button>
</div>
<div class="relative pb-6 p-7">
<p class="mt-12 mb-6 text-neutral-500 text-">Creator of @tailwindcss. Listener of Slayer. Austin 3:16. BTW, Pines UI is super cool!</p>
<div class="flex items-center justify-between pr-2 text-neutral-500">
<div class="relative flex w-16">
<img src="https://pbs.twimg.com/profile_images/1373699471213797385/D4Hbnx09_400x400.jpg" class="relative z-30 w-8 h-8 border-2 border-white rounded-full" />
<img src="https://pbs.twimg.com/profile_images/1609760305763975170/Tx2TVkPI_400x400.jpg" class="z-20 w-8 h-8 -translate-x-4 border-2 border-white rounded-full" />
<img src="https://pbs.twimg.com/profile_images/1637790574768971777/5qS4AOl0_400x400.jpg" class="z-10 w-8 h-8 border-2 border-white rounded-full -translate-x-7" />
</div>
<a href="https://twitter.com/adamwathan/following" target="_blank" class="text-sm hover:underline"><strong class="text-neutral-800">673</strong> Following</a>
<a href="https://twitter.com/adamwathan/followers" target="_blank" class="text-sm hover:underline"><strong class="text-neutral-800">168.6K</strong> Followers</a>
</div>
</div>
</div>

View File

@ -0,0 +1,13 @@
<div class="flex items-center max-w-2xl overflow-hidden bg-white border rounded-lg shadow-sm border-neutral-200/60">
<img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2370&q=80" class="object-cover w-auto h-48 aspect-video" />
<div class="p-8">
<a href="#_" class="block mb-3">
<h5 class="text-xl font-bold leading-none tracking-tight text-neutral-900">Card Title</h5>
</a>
<p class="mb-4 text-sm text-neutral-500">This card element can be used to display a product, post, or any other type of data.</p>
<button class="inline-flex items-center justify-between w-auto h-10 px-4 py-2 text-sm font-medium text-white transition-colors rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none bg-neutral-950 hover:bg-neutral-950/90">
<span>Card Button</span>
<svg class="w-4 h-4 ml-2 -mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div>
</div>

10
elements/card.html Normal file
View File

@ -0,0 +1,10 @@
<div class="rounded-lg overflow-hidden border border-neutral-200/60 bg-white text-neutral-700 shadow-sm w-[380px]">
<div class="relative">
<img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2370&q=80" class="w-full h-auto" />
</div>
<div class="p-7">
<h2 class="mb-2 text-lg font-bold leading-none tracking-tight">Product Name</h2>
<p class="mb-5 text-neutral-500">This card element can be used to display a product, post, or any other type of data.</p>
<button class="inline-flex items-center justify-center w-full h-10 px-4 py-2 text-sm font-medium text-white transition-colors rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none bg-neutral-950 hover:bg-neutral-950/90">View Product</button>
</div>
</div>

View File

@ -0,0 +1,8 @@
<div class="flex items-start mb-6">
<div class="flex items-center h-5">
<input name="remember" id="remember" type="checkbox" class="w-4 h-4 rounded border-neutral-300 bg-neutral-50 focus:ring-3 focus:ring-blue-300" required>
</div>
<div class="ml-3 text-sm">
<label for="remember" class="text-neutral-900">Remember Me</label>
</div>
</div>

View File

@ -0,0 +1,27 @@
<div class="space-y-4">
<p class="text-sm font-medium text-center text-neutral-500">Select a library below</p>
<div class="relative">
<input type="checkbox" id="alpine-checkbox" value="" class="hidden peer" required="">
<label for="alpine-checkbox" class="inline-flex items-center justify-between w-full p-5 bg-white border-2 rounded-lg cursor-pointer group border-neutral-200/70 text-neutral-600 peer-checked:border-blue-600 peer-checked:text-neutral-900 peer-checked:bg-blue-50/50 hover:text-neutral-900">
<div class="flex items-center space-x-5">
<svg class="w-16 h-auto" viewBox="0 0 200 92" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M155.556 0 200 44.25l-44.444 44.249-44.445-44.25L155.556 0Z" fill="currentColor" class="text-[#77C1D2]"></path><path fill-rule="evenodd" clip-rule="evenodd" d="m44.444 0 92.139 91.735H47.694L0 44.249 44.444 0Z" fill="currentColor" class="text-[#2D3441]"></path></svg>
<div class="flex flex-col justify-start">
<div class="w-full text-lg font-semibold">AlpineJS</div>
<div class="w-full text-sm opacity-60">Your new, lightweight, JavaScript framework.</div>
</div>
</div>
</label>
</div>
<div class="relative">
<input type="checkbox" id="tailwind-checkbox" value="" class="hidden peer" required="">
<label for="tailwind-checkbox" class="inline-flex items-center justify-between w-full p-5 bg-white border-2 rounded-lg cursor-pointer group border-neutral-200/70 text-neutral-600 peer-checked:border-blue-600 peer-checked:text-neutral-900 peer-checked:bg-blue-50/50 hover:text-neutral-900">
<div class="flex items-center space-x-5">
<svg class="w-16 h-auto text-[#38BDF8]" viewBox="0 0 200 120" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M100 0C73.333 0 56.667 13.333 50 40c10-13.333 21.667-18.333 35-15 7.607 1.9 13.044 7.422 19.063 13.53C113.867 48.48 125.215 60 150 60c26.667 0 43.333-13.333 50-40-10 13.333-21.667 18.333-35 15-7.607-1.9-13.044-7.422-19.063-13.53C136.133 11.52 124.785 0 100 0ZM50 60C23.333 60 6.667 73.333 0 100c10-13.333 21.667-18.333 35-15 7.607 1.904 13.044 7.422 19.063 13.53C63.867 108.48 75.215 120 100 120c26.667 0 43.333-13.333 50-40-10 13.333-21.667 18.333-35 15-7.607-1.9-13.044-7.422-19.063-13.53C86.133 71.52 74.785 60 50 60Z" fill="currentColor" class=""></path></svg>
<div class="flex flex-col justify-start">
<div class="w-full text-lg font-semibold">Tailwind CSS</div>
<div class="w-full text-sm opacity-60">The ultimate utility-first CSS framework</div>
</div>
</div>
</label>
</div>
</div>

View File

@ -0,0 +1,13 @@
<div class="flex items-start mb-6">
<div class="flex items-center h-5">
<input name="custom-checkbox" id="custom-checkbox" type="checkbox" class="hidden peer" required>
<label for="custom-checkbox" class="peer-checked:[&_svg]:scale-100 text-sm font-medium text-neutral-600 peer-checked:text-blue-600 [&_svg]:scale-0 peer-checked:[&_.custom-checkbox]:border-blue-500 peer-checked:[&_.custom-checkbox]:bg-blue-500 select-none flex items-center space-x-2">
<span class="flex items-center justify-center w-5 h-5 border-2 rounded-md custom-checkbox text-neutral-900">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="w-3 h-3 text-white duration-300 ease-out">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg>
</span>
<span>Custom Checkbox</span>
</label>
</div>
</div>

4
elements/checkbox.html Normal file
View File

@ -0,0 +1,4 @@
<div class="flex items-center mb-4">
<input id="checkbox-id" type="checkbox" class="w-4 h-4 bg-gray-100 border-gray-300 rounded text-neutral-900 focus:ring-neutral-900">
<label for="checkbox-id" class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300">Checkbox</label>
</div>

View File

@ -0,0 +1,130 @@
<div x-data="{
contextMenuOpen: false,
contextMenuToggle: function(event) {
this.contextMenuOpen = true;
event.preventDefault();
this.$refs.contextmenu.classList.add('opacity-0');
let that = this;
$nextTick(function(){
that.calculateContextMenuPosition(event);
that.calculateSubMenuPosition(event);
that.$refs.contextmenu.classList.remove('opacity-0');
});
},
calculateContextMenuPosition (clickEvent) {
if(window.innerHeight < clickEvent.clientY + this.$refs.contextmenu.offsetHeight){
this.$refs.contextmenu.style.top = (window.innerHeight - this.$refs.contextmenu.offsetHeight) + 'px';
} else {
this.$refs.contextmenu.style.top = clickEvent.clientY + 'px';
}
if(window.innerWidth < clickEvent.clientX + this.$refs.contextmenu.offsetWidth){
this.$refs.contextmenu.style.left = (clickEvent.clientX - this.$refs.contextmenu.offsetWidth) + 'px';
} else {
this.$refs.contextmenu.style.left = clickEvent.clientX + 'px';
}
},
calculateSubMenuPosition (clickEvent) {
let submenus = document.querySelectorAll('[data-submenu]');
let contextMenuWidth = this.$refs.contextmenu.offsetWidth;
for(let i = 0; i < submenus.length; i++){
if(window.innerWidth < (clickEvent.clientX + contextMenuWidth + submenus[i].offsetWidth)){
submenus[i].classList.add('left-0', '-translate-x-full');
submenus[i].classList.remove('right-0', 'translate-x-full');
} else {
submenus[i].classList.remove('left-0', '-translate-x-full');
submenus[i].classList.add('right-0', 'translate-x-full');
}
if(window.innerHeight < (submenus[i].previousElementSibling.getBoundingClientRect().top + submenus[i].offsetHeight)){
let heightDifference = (window.innerHeight - submenus[i].previousElementSibling.getBoundingClientRect().top) - submenus[i].offsetHeight;
submenus[i].style.top = heightDifference + 'px';
} else {
submenus[i].style.top = '';
}
}
}
}"
x-init="
$watch('contextMenuOpen', function(value){
if(value === true){ document.body.classList.add('overflow-hidden') }
else { document.body.classList.remove('overflow-hidden') }
});
window.addEventListener('resize', function(event) { contextMenuOpen = false; });
"
@contextmenu="contextMenuToggle(event)" class="relative z-50 flex h-[150px] w-[300px] text-sm items-center justify-center rounded-md border border-neutral-300 border-dashed text-neutral-800"">
<span class="cursor-default text-neutral-400">Right click here</span>
<template x-teleport="body">
<div x-show="contextMenuOpen" @click.away="contextMenuOpen=false" x-ref="contextmenu" class="z-50 min-w-[8rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white text-sm fixed p-1 shadow-md w-64" x-cloak>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 10.5v6m3-3H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" /></svg>
<span>New Folder</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></svg>
<span>Get Info</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px stroke-current left-2" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="none"><path d="M20.2507 8.25V5.75C20.2507 4.64543 19.3553 3.75 18.2507 3.75H5.74902C4.64445 3.75 3.74902 4.64543 3.74902 5.75V8.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 20.25L12 3.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.75 20.25L15.25 20.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<span>Rename</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px stroke-current left-2" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="none"><path d="M3.75 20.25V5.75C3.75 4.09315 5.09315 2.75 6.75 2.75H12.9225C13.453 2.75 13.9617 2.96075 14.3368 3.33588L19.6643 8.66423C20.0393 9.0393 20.25 9.54796 20.25 10.0783V17.25C20.25 18.9069 18.9069 20.25 17.25 20.25H14.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13.75 2.92993V7.24993C13.75 8.3545 14.6454 9.24993 15.75 9.24993H20.07" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M9.75 5H10.25M9.75 8H10.25M9.75 11H10.25M9.75 14H10.25M7.75 3.5L8.25 3.5M7.75 6.5H8.25M7.75 9.5H8.25M7.75 12.5H8.25M7.75 15.5H8.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M7.2627 21.25H10.75C11.0931 21.25 11.3343 20.9124 11.223 20.5879L10.655 18.9305C10.413 18.2244 9.74895 17.75 9.00244 17.75C8.2532 17.75 7.58738 18.2278 7.34748 18.9376L6.78902 20.5899C6.67946 20.914 6.92054 21.25 7.2627 21.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<span>Compress "Untitled.pdf"</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" /></svg>
<span>Duplicate</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" /></svg>
<span>Quick Look</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px stroke-current left-2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="none"><path d="M7.75 7.757V6.75a3 3 0 0 1 3-3h6.5a3 3 0 0 1 3 3v6.5a3 3 0 0 1-3 3h-.992" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3.75 10.75a3 3 0 0 1 3-3h6.5a3 3 0 0 1 3 3v6.5a3 3 0 0 1-3 3h-6.5a3 3 0 0 1-3-3v-6.5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
<span>Copy</span>
</div>
<div class="relative group">
<div class="flex cursor-default select-none items-center rounded px-2 hover:bg-blue-600 hover:text-white py-1.5 outline-none pl-8">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /></svg>
<span>Share</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-48">
<div @click="contextMenuOpen=false" class="relative pl-8 flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z" /></svg>
<span>Upload File</span>
</div>
<div @click="contextMenuOpen=false" class="relative pl-8 flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" /></svg>
<span>Email File</span>
</div>
</div>
</div>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-blue-600 hover:text-white outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" /><path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6z" /></svg>
<span>Tags</span>
<span class="flex items-center h-full pl-3 mt-px space-x-2">
<span class="w-2.5 h-2.5 bg-red-400 rounded-full"></span>
<span class="w-2.5 h-2.5 bg-orange-400 rounded-full"></span>
<span class="w-2.5 h-2.5 bg-yellow-400 rounded-full"></span>
<span class="w-2.5 h-2.5 bg-green-400 rounded-full"></span>
<span class="w-2.5 h-2.5 bg-blue-400 rounded-full"></span>
<span class="w-2.5 h-2.5 bg-purple-400 rounded-full"></span>
<span class="w-2.5 h-2.5 bg-gray-300 rounded-full"></span>
</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-red-600 hover:text-white text-red-600 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<svg class="absolute w-4 h-4 -mt-px left-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" /></svg>
<span>Move To Trash</span>
</div>
</div>
</template>
</div>

View File

@ -0,0 +1,94 @@
<div x-data="{
contextMenuOpen: false,
contextMenuToggle: function(event) {
this.contextMenuOpen = true;
event.preventDefault();
this.$refs.contextmenu.classList.add('opacity-0');
let that = this;
$nextTick(function(){
that.calculateContextMenuPosition(event);
that.calculateSubMenuPosition(event);
that.$refs.contextmenu.classList.remove('opacity-0');
});
},
calculateContextMenuPosition (clickEvent) {
if(window.innerHeight < clickEvent.clientY + this.$refs.contextmenu.offsetHeight){
this.$refs.contextmenu.style.top = (window.innerHeight - this.$refs.contextmenu.offsetHeight) + 'px';
} else {
this.$refs.contextmenu.style.top = clickEvent.clientY + 'px';
}
if(window.innerWidth < clickEvent.clientX + this.$refs.contextmenu.offsetWidth){
this.$refs.contextmenu.style.left = (clickEvent.clientX - this.$refs.contextmenu.offsetWidth) + 'px';
} else {
this.$refs.contextmenu.style.left = clickEvent.clientX + 'px';
}
},
calculateSubMenuPosition (clickEvent) {
let submenus = document.querySelectorAll('[data-submenu]');
let contextMenuWidth = this.$refs.contextmenu.offsetWidth;
for(let i = 0; i < submenus.length; i++){
if(window.innerWidth < (clickEvent.clientX + contextMenuWidth + submenus[i].offsetWidth)){
submenus[i].classList.add('left-0', '-translate-x-full');
submenus[i].classList.remove('right-0', 'translate-x-full');
} else {
submenus[i].classList.remove('left-0', '-translate-x-full');
submenus[i].classList.add('right-0', 'translate-x-full');
}
if(window.innerHeight < (submenus[i].previousElementSibling.getBoundingClientRect().top + submenus[i].offsetHeight)){
let heightDifference = (window.innerHeight - submenus[i].previousElementSibling.getBoundingClientRect().top) - submenus[i].offsetHeight;
submenus[i].style.top = heightDifference + 'px';
} else {
submenus[i].style.top = '';
}
}
}
}"
x-init="
$watch('contextMenuOpen', function(value){
if(value === true){ document.body.classList.add('overflow-hidden') }
else { document.body.classList.remove('overflow-hidden') }
});
window.addEventListener('resize', function(event) { contextMenuOpen = false; });
"
@contextmenu="contextMenuToggle(event)" class="relative z-50 flex h-[150px] w-[300px] text-sm items-center justify-center rounded-md border border-neutral-300 border-dashed text-neutral-800"">
<span class="cursor-default text-neutral-400">Right click here</span>
<template x-teleport="body">
<div x-show="contextMenuOpen" @click.away="contextMenuOpen=false" x-ref="contextmenu" class="z-50 min-w-[8rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white text-sm fixed p-1 shadow-md w-64" x-cloak>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>New Folder</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘N</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Get Info</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘I</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Change Background...</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div class="relative group">
<div class="flex cursor-default select-none items-center rounded px-2 hover:bg-neutral-100 py-1.5 outline-none pl-8">
<span>Sort By</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-48">
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Kind</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Date Last Opened</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Date Added</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Date Modified</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Date Created</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Tags</div>
</div>
</div>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Show View Options</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘R</span>
</div>
</div>
</template>
</div>

113
elements/context-menu.html Normal file
View File

@ -0,0 +1,113 @@
<div x-data="{
contextMenuOpen: false,
contextMenuToggle: function(event) {
this.contextMenuOpen = true;
event.preventDefault();
this.$refs.contextmenu.classList.add('opacity-0');
let that = this;
$nextTick(function(){
that.calculateContextMenuPosition(event);
that.calculateSubMenuPosition(event);
that.$refs.contextmenu.classList.remove('opacity-0');
});
},
calculateContextMenuPosition (clickEvent) {
if(window.innerHeight < clickEvent.clientY + this.$refs.contextmenu.offsetHeight){
this.$refs.contextmenu.style.top = (window.innerHeight - this.$refs.contextmenu.offsetHeight) + 'px';
} else {
this.$refs.contextmenu.style.top = clickEvent.clientY + 'px';
}
if(window.innerWidth < clickEvent.clientX + this.$refs.contextmenu.offsetWidth){
this.$refs.contextmenu.style.left = (clickEvent.clientX - this.$refs.contextmenu.offsetWidth) + 'px';
} else {
this.$refs.contextmenu.style.left = clickEvent.clientX + 'px';
}
},
calculateSubMenuPosition (clickEvent) {
let submenus = document.querySelectorAll('[data-submenu]');
let contextMenuWidth = this.$refs.contextmenu.offsetWidth;
for(let i = 0; i < submenus.length; i++){
if(window.innerWidth < (clickEvent.clientX + contextMenuWidth + submenus[i].offsetWidth)){
submenus[i].classList.add('left-0', '-translate-x-full');
submenus[i].classList.remove('right-0', 'translate-x-full');
} else {
submenus[i].classList.remove('left-0', '-translate-x-full');
submenus[i].classList.add('right-0', 'translate-x-full');
}
if(window.innerHeight < (submenus[i].previousElementSibling.getBoundingClientRect().top + submenus[i].offsetHeight)){
let heightDifference = (window.innerHeight - submenus[i].previousElementSibling.getBoundingClientRect().top) - submenus[i].offsetHeight;
submenus[i].style.top = heightDifference + 'px';
} else {
submenus[i].style.top = '';
}
}
}
}"
x-init="
$watch('contextMenuOpen', function(value){
if(value === true){ document.body.classList.add('overflow-hidden') }
else { document.body.classList.remove('overflow-hidden') }
});
window.addEventListener('resize', function(event) { contextMenuOpen = false; });
"
@contextmenu="contextMenuToggle(event)" class="relative z-50 flex h-[150px] w-[300px] text-sm items-center justify-center rounded-md border border-neutral-300 border-dashed text-neutral-800"">
<span class="cursor-default text-neutral-400">Right click here</span>
<template x-teleport="body">
<div x-show="contextMenuOpen" @click.away="contextMenuOpen=false" x-ref="contextmenu" class="z-50 min-w-[8rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white text-sm fixed p-1 shadow-md w-64" x-cloak>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Back</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘[</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none" data-disabled>
<span>Forward</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘]</span>
</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 outline-none pl-8 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Reload</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘R</span>
</div>
<div class="relative group">
<div class="flex cursor-default select-none items-center rounded px-2 hover:bg-neutral-100 py-1.5 outline-none pl-8">
<span>More Tools</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-48">
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Save Page As...<span class="ml-auto text-xs tracking-widest text-muted-foreground">⇧⌘S</span></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Create Shortcut...</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Name Window...</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Developer Tools</div>
</div>
</div>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div x-data="{ showBookmarks: true }" @click="showBookmarks=!showBookmarks; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="showBookmarks" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
<span>Show Bookmarks Bar</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘⇧B</span>
</div>
<div x-data="{ showFullUrl: false }" @click="showFullUrl=!showFullUrl; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="showFullUrl" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
<span>Show Full URLs</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div>
<div class="px-2 py-1.5 text-sm font-semibold text-foreground pl-8">People</div>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div x-data="{ contextMenuPeople: 'adam' }" class="relative">
<div @click="contextMenuPeople='adam'; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='adam'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Adam Wathan</span>
</div>
<div @click="contextMenuPeople='caleb'; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='caleb'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Caleb Porzio</span>
</div>
</div>
</div>
</template>
</div>

View File

@ -0,0 +1,8 @@
{
"data" : {
"contextMenuOpen" : "If the context menu is open (default: false)",
"contextMenuToggle (event)" : "This function will toggle the context menu to show or hide.",
"calculateContextMenuPosition (clickEvent)" : "This function will calculate the position of the context menu based on the clickEvent position.",
"calculateSubMenuPosition (clickEvent)" : "This function will calculate the position of the sub menu and adjust it if it is off screen."
}
}

View File

@ -0,0 +1,25 @@
<div x-data="{
copyText: '',
copyNotification: false,
copyToClipboard() {
navigator.clipboard.writeText(this.copyText);
this.copyNotification = true;
let that = this;
setTimeout(function(){
that.copyNotification = false;
}, 3000);
}
}" class="relative z-20 flex items-center">
<div x-show="copyNotification" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 translate-x-2" x-transition:enter-end="opacity-100 translate-x-0" x-transition:leave="transition ease-in duration-300" x-transition:leave-start="opacity-100 translate-x-0" x-transition:leave-end="opacity-0 translate-x-2" class="absolute left-0" x-cloak>
<div class="px-3 h-7 -ml-1.5 items-center flex text-xs bg-green-500 border-r border-green-500 -translate-x-full text-white rounded">
<span>Copied!</span>
<div class="absolute right-0 inline-block h-full -mt-px overflow-hidden translate-x-3 -translate-y-2 top-1/2">
<div class="w-3 h-3 origin-top-left transform rotate-45 bg-green-500 border border-transparent"></div>
</div>
</div>
</div>
<button @click="copyToClipboard();" class="flex items-center justify-center h-8 text-xs bg-white border rounded-md cursor-pointer w-9 border-neutral-200/60 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none text-neutral-500 hover:text-neutral-600 group">
<svg x-show="copyNotification" class="w-4 h-4 text-green-500 stroke-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" x-cloak><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></svg>
<svg x-show="!copyNotification" class="w-4 h-4 stroke-current" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="none"><path d="M7.75 7.757V6.75a3 3 0 0 1 3-3h6.5a3 3 0 0 1 3 3v6.5a3 3 0 0 1-3 3h-.992" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3.75 10.75a3 3 0 0 1 3-3h6.5a3 3 0 0 1 3 3v6.5a3 3 0 0 1-3 3h-6.5a3 3 0 0 1-3-3v-6.5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
</button>
</div>

View File

@ -0,0 +1,19 @@
<div x-data="{
copyText: '',
copyNotification: false,
copyToClipboard() {
navigator.clipboard.writeText(this.copyText);
this.copyNotification = true;
let that = this;
setTimeout(function(){
that.copyNotification = false;
}, 3000);
}
}" class="relative z-20 flex items-center">
<button @click="copyToClipboard();" class="flex flex-col items-center justify-center h-auto px-3 w-16 pt-2 font-medium pb-1.5 text-[0.65rem] uppercase bg-white rounded-md cursor-pointer border border-neutral-200/60 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none text-neutral-500 hover:text-neutral-600 group">
<svg x-show="!copyNotification" class="flex-shrink-0 w-5 h-5 mb-1 stroke-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z" /></svg>
<span x-show="!copyNotification">Copy</span>
<svg x-show="copyNotification" class="flex-shrink-0 w-5 h-5 mb-1 text-green-500 stroke-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" x-cloak><path stroke-linecap="round" stroke-linejoin="round" d="M11.35 3.836c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m8.9-4.414c.376.023.75.05 1.124.08 1.131.094 1.976 1.057 1.976 2.192V16.5A2.25 2.25 0 0118 18.75h-2.25m-7.5-10.5H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V18.75m-7.5-10.5h6.375c.621 0 1.125.504 1.125 1.125v9.375m-8.25-3l1.5 1.5 3-3.75" /></svg>
<span x-show="copyNotification" class="tracking-tight text-green-500" x-cloak>Copied</span>
</button>
</div>

View File

@ -0,0 +1,19 @@
<div x-data="{
copyText: '',
copyNotification: false,
copyToClipboard() {
navigator.clipboard.writeText(this.copyText);
this.copyNotification = true;
let that = this;
setTimeout(function(){
that.copyNotification = false;
}, 3000);
}
}" class="relative z-20 flex items-center">
<button @click="copyToClipboard();" class="flex items-center justify-center w-auto h-8 px-3 py-1 text-xs bg-white border rounded-md cursor-pointer border-neutral-200/60 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none text-neutral-500 hover:text-neutral-600 group">
<span x-show="!copyNotification">Copy to Clipboard</span>
<svg x-show="!copyNotification" class="w-4 h-4 ml-1.5 stroke-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z" /></svg>
<span x-show="copyNotification" class="tracking-tight text-green-500" x-cloak>Copied to Clipboard</span>
<svg x-show="copyNotification" class="w-4 h-4 ml-1.5 text-green-500 stroke-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" x-cloak><path stroke-linecap="round" stroke-linejoin="round" d="M11.35 3.836c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m8.9-4.414c.376.023.75.05 1.124.08 1.131.094 1.976 1.057 1.976 2.192V16.5A2.25 2.25 0 0118 18.75h-2.25m-7.5-10.5H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V18.75m-7.5-10.5h6.375c.621 0 1.125.504 1.125 1.125v9.375m-8.25-3l1.5 1.5 3-3.75" /></svg>
</button>
</div>

View File

@ -0,0 +1,154 @@
<div x-data="{
datePickerOpen: false,
datePickerValue: '',
datePickerFormat: 'M d, Y',
datePickerMonth: '',
datePickerYear: '',
datePickerDay: '',
datePickerDaysInMonth: [],
datePickerBlankDaysInMonth: [],
datePickerMonthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
datePickerDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
datePickerDayClicked(day) {
let selectedDate = new Date(this.datePickerYear, this.datePickerMonth, day);
this.datePickerDay = day;
this.datePickerValue = this.datePickerFormatDate(selectedDate);
this.datePickerIsSelectedDate(day);
this.datePickerOpen = false;
},
datePickerPreviousMonth(){
if (this.datePickerMonth == 0) {
this.datePickerYear--;
this.datePickerMonth = 12;
}
this.datePickerMonth--;
this.datePickerCalculateDays();
},
datePickerNextMonth(){
if (this.datePickerMonth == 11) {
this.datePickerMonth = 0;
this.datePickerYear++;
} else {
this.datePickerMonth++;
}
this.datePickerCalculateDays();
},
datePickerIsSelectedDate(day) {
const d = new Date(this.datePickerYear, this.datePickerMonth, day);
return this.datePickerValue === this.datePickerFormatDate(d) ? true : false;
},
datePickerIsToday(day) {
const today = new Date();
const d = new Date(this.datePickerYear, this.datePickerMonth, day);
return today.toDateString() === d.toDateString() ? true : false;
},
datePickerCalculateDays() {
let daysInMonth = new Date(this.datePickerYear, this.datePickerMonth + 1, 0).getDate();
// find where to start calendar day of week
let dayOfWeek = new Date(this.datePickerYear, this.datePickerMonth).getDay();
let blankdaysArray = [];
for (var i = 1; i <= dayOfWeek; i++) {
blankdaysArray.push(i);
}
let daysArray = [];
for (var i = 1; i <= daysInMonth; i++) {
daysArray.push(i);
}
this.datePickerBlankDaysInMonth = blankdaysArray;
this.datePickerDaysInMonth = daysArray;
},
datePickerFormatDate(date) {
let formattedDay = this.datePickerDays[date.getDay()];
let formattedDate = ('0' + date.getDate()).slice(-2); // appends 0 (zero) in single digit date
let formattedMonth = this.datePickerMonthNames[date.getMonth()];
let formattedMonthShortName = this.datePickerMonthNames[date.getMonth()].substring(0, 3);
let formattedMonthInNumber = ('0' + (parseInt(date.getMonth()) + 1)).slice(-2);
let formattedYear = date.getFullYear();
if (this.datePickerFormat === 'M d, Y') {
return `${formattedMonthShortName} ${formattedDate}, ${formattedYear}`;
}
if (this.datePickerFormat === 'MM-DD-YYYY') {
return `${formattedMonthInNumber}-${formattedDate}-${formattedYear}`;
}
if (this.datePickerFormat === 'DD-MM-YYYY') {
return `${formattedDate}-${formattedMonthInNumber}-${formattedYear}`;
}
if (this.datePickerFormat === 'YYYY-MM-DD') {
return `${formattedYear}-${formattedMonthInNumber}-${formattedDate}`;
}
if (this.datePickerFormat === 'D d M, Y') {
return `${formattedDay} ${formattedDate} ${formattedMonthShortName} ${formattedYear}`;
}
return `${formattedMonth} ${formattedDate}, ${formattedYear}`;
},
}" x-init="
currentDate = new Date();
if (datePickerValue) {
currentDate = new Date(Date.parse(datePickerValue));
}
datePickerMonth = currentDate.getMonth();
datePickerYear = currentDate.getFullYear();
datePickerDay = currentDate.getDay();
datePickerValue = datePickerFormatDate( currentDate );
datePickerCalculateDays();
" x-cloak>
<div class="container px-4 py-2 mx-auto md:py-10">
<div class="w-64 mb-5">
<label for="datepicker" class="block mb-1 text-sm font-medium text-neutral-500">Select Date</label>
<div class="relative w-[17rem]">
<input x-ref="datePickerInput" type="text" @click="datePickerOpen=!datePickerOpen" x-model="datePickerValue" x-on:keydown.escape="datePickerOpen=false" class="flex w-full h-10 px-3 py-2 text-sm bg-white border-2 text-neutral-600 border-neutral-600 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-800 focus:text-neutral-800 focus:outline-none focus:ring-0 disabled:cursor-not-allowed disabled:opacity-50" placeholder="Select date" readonly />
<div @click="datePickerOpen=!datePickerOpen; if(datePickerOpen){ $refs.datePickerInput.focus() }" :class="{ 'text-neutral-600 hover:text-neutral-800' : !datePickerOpen, 'text-neutral-800' : datePickerOpen }" class="absolute top-0 right-0 px-3 py-2 cursor-pointer">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg>
</div>
<div
x-show="datePickerOpen"
x-transition
@click.away="datePickerOpen = false"
class="absolute top-0 left-0 max-w-lg p-4 mt-12 antialiased bg-white border-2 border-neutral-800 shadow w-[17rem] border-neutral-200/70">
<div class="flex items-center justify-between mb-2">
<div>
<span x-text="datePickerMonthNames[datePickerMonth]" class="text-lg font-bold text-gray-800"></span>
<span x-text="datePickerYear" class="ml-1 text-lg font-normal text-gray-600"></span>
</div>
<div>
<button @click="datePickerPreviousMonth()" type="button" class="inline-flex p-1 transition duration-100 ease-in-out cursor-pointer focus:outline-none focus:shadow-outline hover:bg-gray-100">
<svg class="inline-flex w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" /></svg>
</button>
<button @click="datePickerNextMonth()" type="button" class="inline-flex p-1 transition duration-100 ease-in-out cursor-pointer focus:outline-none focus:shadow-outline hover:bg-gray-100">
<svg class="inline-flex w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" /></svg>
</button>
</div>
</div>
<div class="grid grid-cols-7 mb-3">
<template x-for="(day, index) in datePickerDays" :key="index">
<div class="px-0.5">
<div x-text="day" class="text-xs font-medium text-center text-gray-800"></div>
</div>
</template>
</div>
<div class="grid grid-cols-7">
<template x-for="blankDay in datePickerBlankDaysInMonth">
<div class="p-1 text-sm text-center border border-transparent"></div>
</template>
<template x-for="(day, dayIndex) in datePickerDaysInMonth" :key="dayIndex">
<div class="px-0.5 mb-1 aspect-square">
<div
x-text="day"
@click="datePickerDayClicked(day)"
:class="{
'bg-neutral-200': datePickerIsToday(day) == true,
'text-gray-600 hover:bg-neutral-200': datePickerIsToday(day) == false && datePickerIsSelectedDate(day) == false,
'bg-neutral-800 text-white hover:bg-opacity-75': datePickerIsSelectedDate(day) == true
}"
class="flex items-center justify-center text-sm leading-none text-center cursor-pointer h-7 w-7"></div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>

154
elements/date-picker.html Normal file
View File

@ -0,0 +1,154 @@
<div x-data="{
datePickerOpen: false,
datePickerValue: '',
datePickerFormat: 'M d, Y',
datePickerMonth: '',
datePickerYear: '',
datePickerDay: '',
datePickerDaysInMonth: [],
datePickerBlankDaysInMonth: [],
datePickerMonthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
datePickerDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
datePickerDayClicked(day) {
let selectedDate = new Date(this.datePickerYear, this.datePickerMonth, day);
this.datePickerDay = day;
this.datePickerValue = this.datePickerFormatDate(selectedDate);
this.datePickerIsSelectedDate(day);
this.datePickerOpen = false;
},
datePickerPreviousMonth(){
if (this.datePickerMonth == 0) {
this.datePickerYear--;
this.datePickerMonth = 12;
}
this.datePickerMonth--;
this.datePickerCalculateDays();
},
datePickerNextMonth(){
if (this.datePickerMonth == 11) {
this.datePickerMonth = 0;
this.datePickerYear++;
} else {
this.datePickerMonth++;
}
this.datePickerCalculateDays();
},
datePickerIsSelectedDate(day) {
const d = new Date(this.datePickerYear, this.datePickerMonth, day);
return this.datePickerValue === this.datePickerFormatDate(d) ? true : false;
},
datePickerIsToday(day) {
const today = new Date();
const d = new Date(this.datePickerYear, this.datePickerMonth, day);
return today.toDateString() === d.toDateString() ? true : false;
},
datePickerCalculateDays() {
let daysInMonth = new Date(this.datePickerYear, this.datePickerMonth + 1, 0).getDate();
// find where to start calendar day of week
let dayOfWeek = new Date(this.datePickerYear, this.datePickerMonth).getDay();
let blankdaysArray = [];
for (var i = 1; i <= dayOfWeek; i++) {
blankdaysArray.push(i);
}
let daysArray = [];
for (var i = 1; i <= daysInMonth; i++) {
daysArray.push(i);
}
this.datePickerBlankDaysInMonth = blankdaysArray;
this.datePickerDaysInMonth = daysArray;
},
datePickerFormatDate(date) {
let formattedDay = this.datePickerDays[date.getDay()];
let formattedDate = ('0' + date.getDate()).slice(-2); // appends 0 (zero) in single digit date
let formattedMonth = this.datePickerMonthNames[date.getMonth()];
let formattedMonthShortName = this.datePickerMonthNames[date.getMonth()].substring(0, 3);
let formattedMonthInNumber = ('0' + (parseInt(date.getMonth()) + 1)).slice(-2);
let formattedYear = date.getFullYear();
if (this.datePickerFormat === 'M d, Y') {
return `${formattedMonthShortName} ${formattedDate}, ${formattedYear}`;
}
if (this.datePickerFormat === 'MM-DD-YYYY') {
return `${formattedMonthInNumber}-${formattedDate}-${formattedYear}`;
}
if (this.datePickerFormat === 'DD-MM-YYYY') {
return `${formattedDate}-${formattedMonthInNumber}-${formattedYear}`;
}
if (this.datePickerFormat === 'YYYY-MM-DD') {
return `${formattedYear}-${formattedMonthInNumber}-${formattedDate}`;
}
if (this.datePickerFormat === 'D d M, Y') {
return `${formattedDay} ${formattedDate} ${formattedMonthShortName} ${formattedYear}`;
}
return `${formattedMonth} ${formattedDate}, ${formattedYear}`;
},
}" x-init="
currentDate = new Date();
if (datePickerValue) {
currentDate = new Date(Date.parse(datePickerValue));
}
datePickerMonth = currentDate.getMonth();
datePickerYear = currentDate.getFullYear();
datePickerDay = currentDate.getDay();
datePickerValue = datePickerFormatDate( currentDate );
datePickerCalculateDays();
" x-cloak>
<div class="container px-4 py-2 mx-auto md:py-10">
<div class="w-64 mb-5">
<label for="datepicker" class="block mb-1 text-sm font-medium text-neutral-500">Select Date</label>
<div class="relative w-[17rem]">
<input x-ref="datePickerInput" type="text" @click="datePickerOpen=!datePickerOpen" x-model="datePickerValue" x-on:keydown.escape="datePickerOpen=false" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md text-neutral-600 border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50" placeholder="Select date" readonly />
<div @click="datePickerOpen=!datePickerOpen; if(datePickerOpen){ $refs.datePickerInput.focus() }" class="absolute top-0 right-0 px-3 py-2 cursor-pointer text-neutral-400 hover:text-neutral-500">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg>
</div>
<div
x-show="datePickerOpen"
x-transition
@click.away="datePickerOpen = false"
class="absolute top-0 left-0 max-w-lg p-4 mt-12 antialiased bg-white border rounded-lg shadow w-[17rem] border-neutral-200/70">
<div class="flex items-center justify-between mb-2">
<div>
<span x-text="datePickerMonthNames[datePickerMonth]" class="text-lg font-bold text-gray-800"></span>
<span x-text="datePickerYear" class="ml-1 text-lg font-normal text-gray-600"></span>
</div>
<div>
<button @click="datePickerPreviousMonth()" type="button" class="inline-flex p-1 transition duration-100 ease-in-out rounded-full cursor-pointer focus:outline-none focus:shadow-outline hover:bg-gray-100">
<svg class="inline-flex w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" /></svg>
</button>
<button @click="datePickerNextMonth()" type="button" class="inline-flex p-1 transition duration-100 ease-in-out rounded-full cursor-pointer focus:outline-none focus:shadow-outline hover:bg-gray-100">
<svg class="inline-flex w-6 h-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" /></svg>
</button>
</div>
</div>
<div class="grid grid-cols-7 mb-3">
<template x-for="(day, index) in datePickerDays" :key="index">
<div class="px-0.5">
<div x-text="day" class="text-xs font-medium text-center text-gray-800"></div>
</div>
</template>
</div>
<div class="grid grid-cols-7">
<template x-for="blankDay in datePickerBlankDaysInMonth">
<div class="p-1 text-sm text-center border border-transparent"></div>
</template>
<template x-for="(day, dayIndex) in datePickerDaysInMonth" :key="dayIndex">
<div class="px-0.5 mb-1 aspect-square">
<div
x-text="day"
@click="datePickerDayClicked(day)"
:class="{
'bg-neutral-200': datePickerIsToday(day) == true,
'text-gray-600 hover:bg-neutral-200': datePickerIsToday(day) == false && datePickerIsSelectedDate(day) == false,
'bg-neutral-800 text-white hover:bg-opacity-75': datePickerIsSelectedDate(day) == true
}"
class="flex items-center justify-center text-sm leading-none text-center rounded-full cursor-pointer h-7 w-7"></div>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>

21
elements/date-picker.json Normal file
View File

@ -0,0 +1,21 @@
{
"data" : {
"datePickerOpen" : "If the date picker is open (true or false)",
"datePickerValue" : "The default date value. If left empty the current date will be used",
"datePickerFormat" : "You can choose a few different formats to display the date. See all available formats in the datePickerFormatDate() method.",
"datePickerMonth" : "Numerical value of the current month (0-11)",
"datePickerYear" : "Numerical value of the current year",
"datePickerDay" : "Numerical value of the current day",
"datePickerDaysInMonth" : "Array containing the number of days in the selected month",
"datePickerBlankDaysInMonth" : "Array containing the number of blank days before the first day of the month",
"datePickerMonthNames" : "Array containing the names of the months",
"datePickerDays" : "Array containing the names of the days",
"datePickerDayClicked(day)" : "When a day is clicked on the datepicker set the new date value",
"datePickerPreviousMonth()" : "Go to the previous month",
"datePickerNextMonth()" : "Go to the next month",
"datePickerIsSelectedDate(day)" : "Check if the day is the selected date",
"datePickerIsToday(day)" : "Check if the day is today",
"datePickerCalculateDays()" : "Calculate the number of days in the month",
"datePickerFormatDate(date)" : "Format the date to the selected format"
}
}

View File

@ -0,0 +1,66 @@
<div x-data="{
dropdownOpen: false
}"
class="relative">
<button @click="dropdownOpen=true" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Open</button>
<div x-show="dropdownOpen"
@click.away="dropdownOpen=false"
x-transition:enter="ease-out duration-200"
x-transition:enter-start="-translate-y-2"
x-transition:enter-end="translate-y-0"
class="absolute top-0 z-50 w-56 mt-12 -translate-x-1/2 left-1/2"
x-cloak>
<div class="p-1 mt-1 text-sm bg-white border rounded-md shadow-md border-neutral-200/70 text-neutral-700">
<a href="#_" @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>New Tab</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘T</span>
</a>
<a href="#_" @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>New Window</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘N</span>
</a>
<div @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none" data-disabled>
<span>New Private Window</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⇧⌘N</span>
</div>
<div class="relative w-full group">
<div class="flex cursor-default select-none items-center rounded px-2 hover:bg-neutral-100 py-1.5 outline-none">
<span>More Tools</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-48">
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Save Page As...<span class="ml-auto text-xs tracking-widest text-muted-foreground">⇧⌘S</span></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Create Shortcut...</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Name Window...</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Developer Tools</div>
</div>
</div>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div x-data="{ showBookmarks: true }" @click="showBookmarks=!showBookmarks; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="showBookmarks" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
<span>Show Bookmarks Bar</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘⇧B</span>
</div>
<div x-data="{ showFullUrl: false }" @click="showFullUrl=!showFullUrl; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="showFullUrl" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
<span>Show Full URLs</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div x-data="{ contextMenuPeople: 'adam' }" class="relative">
<div @click="contextMenuPeople='adam'; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='adam'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Adam Wathan</span>
</div>
<div @click="contextMenuPeople='caleb'; contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='caleb'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Caleb Porzio</span>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,99 @@
<div x-data="{
dropdownOpen: false
}"
class="relative">
<button @click="dropdownOpen=true" class="inline-flex items-center justify-center h-12 py-2 pl-3 pr-12 text-sm font-medium transition-colors bg-white border rounded-md text-neutral-700 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none disabled:opacity-50 disabled:pointer-events-none">
<img src="https://cdn.devdojo.com/images/may2023/adam.jpeg" class="object-cover w-8 h-8 border rounded-full border-neutral-200" />
<span class="flex flex-col items-start flex-shrink-0 h-full ml-2 leading-none translate-y-px">
<span>Adam Wathan</span>
<span class="text-xs font-light text-neutral-400">@adamwathan</span>
</span>
<svg class="absolute right-0 w-5 h-5 mr-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" /></svg>
</button>
<div x-show="dropdownOpen"
@click.away="dropdownOpen=false"
x-transition:enter="ease-out duration-200"
x-transition:enter-start="-translate-y-2"
x-transition:enter-end="translate-y-0"
class="absolute top-0 z-50 w-56 mt-12 -translate-x-1/2 left-1/2"
x-cloak>
<div class="p-1 mt-1 bg-white border rounded-md shadow-md border-neutral-200/70 text-neutral-700">
<div class="px-2 py-1.5 text-sm font-semibold">My Account</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
<span>Profile</span>
<span class="ml-auto text-xs tracking-widest opacity-60">⇧⌘P</span>
</a>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><rect width="20" height="14" x="2" y="5" rx="2"></rect><line x1="2" x2="22" y1="10" y2="10"></line></svg>
<span>Billing</span><span class="ml-auto text-xs tracking-widest opacity-60">⌘B</span>
</a>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"></path><circle cx="12" cy="12" r="3"></circle></svg>
<span>Settings</span>
<span class="ml-auto text-xs tracking-widest opacity-60">⌘S</span>
</a>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><rect width="20" height="16" x="2" y="4" rx="2" ry="2"></rect><path d="M6 8h.001"></path><path d="M10 8h.001"></path><path d="M14 8h.001"></path><path d="M18 8h.001"></path><path d="M8 12h.001"></path><path d="M12 12h.001"></path><path d="M16 12h.001"></path><path d="M7 16h10"></path></svg>
<span>Keyboard shortcuts</span>
<span class="ml-auto text-xs tracking-widest opacity-60">⌘K</span>
</a>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
<span>Team</span>
</div>
<div class="relative group">
<div class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><line x1="19" x2="19" y1="8" y2="14"></line><line x1="22" x2="16" y1="11" y2="11"></line></svg>
<span>Invite users</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-40">
<div @click="dropdownOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="16" x="2" y="4" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></svg>
<span>Email</span>
</div>
<div @click="dropdownOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
<span>Message</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="dropdownOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" x2="12" y1="8" y2="16"></line><line x1="8" x2="16" y1="12" y2="12"></line></svg>
<span>More...</span>
</div>
</div>
</div>
</div>
<div class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><line x1="12" x2="12" y1="5" y2="19"></line><line x1="5" x2="19" y1="12" y2="12"></line></svg>
<span>New Team</span>
<span class="ml-auto text-xs tracking-widest opacity-60">⌘+T</span>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"></path><path d="M9 18c-4.51 2-5-2-7-2"></path></svg>
<span>GitHub</span>
</a>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4"></circle><line x1="4.93" x2="9.17" y1="4.93" y2="9.17"></line><line x1="14.83" x2="19.07" y1="14.83" y2="19.07"></line><line x1="14.83" x2="19.07" y1="9.17" y2="4.93"></line><line x1="14.83" x2="18.36" y1="9.17" y2="5.64"></line><line x1="4.93" x2="9.17" y1="19.07" y2="14.83"></line></svg>
<span>Support</span>
</a>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50" data-disabled>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path></svg>
<span>API</span>
</a>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<a href="#_" class="relative flex cursor-default select-none hover:bg-neutral-100 items-center rounded px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 mr-2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" x2="9" y1="12" y2="12"></line></svg>
<span>Log out</span>
<span class="ml-auto text-xs tracking-widest opacity-60">⇧⌘Q</span>
</a>
</div>
</div>
</div>

View File

@ -0,0 +1,63 @@
<div x-data="{ previewFullScreenMenu: false }">
<button @click="previewFullScreenMenu=true" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Preview</button>
<template x-teleport="body">
<div x-show="previewFullScreenMenu" class="fixed inset-0 z-[99] w-screen h-screen">
<!-- Blur Overlay -->
<div class="fixed inset-0 z-10 w-screen h-screen bg-white bg-opacity-70 backdrop-blur-sm"></div>
<button @click="previewFullScreenMenu=false" class="fixed top-0 right-0 z-30 inline-flex items-center justify-center h-10 px-4 py-2 mt-3 mr-3 text-xs font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Close Fullscreen Menu</button>
<!-- Fullscreen Menu -->
<div x-data="{ fullscreenMenu: false }" @keydown.escape.window="fullscreenMenu=false" class="fixed inset-0 z-20 w-screen h-screen overflow-hidden" x-cloak>
<button class="absolute top-0 left-0 z-30 flex items-center justify-center w-12 h-12 mt-4 ml-4 transition duration-300 transform -translate-y-px bg-black rounded-full cursor-pointer group" @click="fullscreenMenu=!fullscreenMenu">
<div :class="{ '-rotate-180 -translate-y-px' : fullscreenMenu }" class="w-6 h-auto transition duration-500 ease-out transform cursor-pointer">
<div :class="{ 'rotate-45 duration-300' : fullscreenMenu, 'group-hover:-translate-y-[1px] duration-500' : !fullscreenMenu }" class="h-[2px] bg-white w-full rounded-full transform transition ease-out"></div>
<div :class="{ 'hidden' : fullscreenMenu }" class="h-[2px] bg-white w-full my-[5px]"></div>
<div :class="{ '-rotate-45 duration-300 -translate-y-0.5' : fullscreenMenu, 'group-hover:translate-y-[1px] duration-300' : !fullscreenMenu }" class="h-[2px] bg-white w-full rounded-full transform transition ease-out duration-500"></div>
</div>
</button>
<div :class="{ 'opacity-0 invisible' : !fullscreenMenu, 'opacity-100' : fullscreenMenu }" class="fixed inset-0 z-10 w-screen h-screen transition duration-300 transform bg-white ease"></div>
<nav :class="{ 'invisible' : !fullscreenMenu }" class="fixed inset-0 z-20 flex flex-col items-start justify-start w-screen h-full py-24 pl-5 space-y-5 text-5xl font-bold uppercase transition duration-300 text-neutral-900 ease">
<a href="#_"
x-show="fullscreenMenu"
x-transition:enter="transition delay-0 ease-out duration-500"
x-transition:enter-start="-translate-x-full opacity-0"
x-transition:enter-end="translate-x-cloak-0 opacity-100"
:class="{ '-translate-x-full' : !fullscreenMenu }" class="relative inline-block w-auto h-auto font-extrabold text-left cursor-pointer hover:text-black group">
<span>Home</span>
<span class="absolute bottom-0 left-0 w-0 h-1 duration-300 ease-out bg-black group-hover:w-full"></span>
</a>
<a href="#_"
x-show="fullscreenMenu"
x-transition:enter="transition delay-[150ms] ease-out duration-500"
x-transition:enter-start="-translate-x-full opacity-0"
x-transition:enter-end="translate-x-cloak-0 opacity-100"
:class="{ '-translate-x-full' : !fullscreenMenu }" class="relative inline-block w-auto h-auto font-extrabold text-left cursor-pointer hover:text-black group">
<span>Features</span>
<span class="absolute bottom-0 left-0 w-0 h-1 duration-300 ease-out bg-black group-hover:w-full"></span>
</a>
<a href="#_"
x-show="fullscreenMenu"
x-transition:enter="transition delay-[300ms] ease-out duration-500"
x-transition:enter-start="-translate-x-full opacity-0"
x-transition:enter-end="translate-x-cloak-0 opacity-100"
:class="{ '-translate-x-full' : !fullscreenMenu }" class="relative inline-block w-auto h-auto font-extrabold text-left cursor-pointer hover:text-black group">
<span>Pricing</span>
<span class="absolute bottom-0 left-0 w-0 h-1 duration-300 ease-out bg-black group-hover:w-full"></span>
</a>
<a href="#_"
x-show="fullscreenMenu"
x-transition:enter="transition delay-[450ms] ease-out duration-500"
x-transition:enter-start="-translate-x-full opacity-0"
x-transition:enter-end="translate-x-cloak-0 opacity-100"
:class="{ '-translate-x-full' : !fullscreenMenu }" class="relative inline-block w-auto h-auto font-extrabold text-left cursor-pointer hover:text-black group">
<span>About</span>
<span class="absolute bottom-0 left-0 w-0 h-1 duration-300 ease-out bg-black group-hover:w-full"></span>
</a>
</nav>
</div>
<!-- End Fullscreen Menu -->
</div>
</template>
</div>

View File

@ -0,0 +1,38 @@
<div x-data="{ previewFullScreenMenu: false }">
<button @click="previewFullScreenMenu=true" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Preview</button>
<template x-teleport="body">
<div x-show="previewFullScreenMenu" class="fixed inset-0 z-[99] w-screen h-screen">
<!-- Blur Overlay -->
<div class="fixed inset-0 z-10 w-screen h-screen bg-white bg-opacity-70 backdrop-blur-sm"></div>
<button @click="previewFullScreenMenu=false" class="fixed top-0 right-0 z-30 inline-flex items-center justify-center h-10 px-4 py-2 mt-3 mr-3 text-xs font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Close Fullscreen Menu</button>
<!-- Fullscreen Menu -->
<div x-data="{ fullscreenMenu: false }" @keydown.escape.window="fullscreenMenu=false" class="fixed inset-0 z-20 w-screen h-screen overflow-hidden" x-cloak>
<div :class="{ 'border-neutral-200/70' : !fullscreenMenu, 'border-transparent' : fullscreenMenu }" class="fixed z-20 flex flex-col items-center justify-center w-16 h-full py-5 text-black transform bg-white border-r">
<div class="relative w-6 h-5 transition duration-300 transform cursor-pointer group" @click="fullscreenMenu=!fullscreenMenu">
<div :class="{ 'rotate-45 translate-y-[6px] duration-300' : fullscreenMenu, 'group-hover:-translate-y-0.5 duration-300' : !fullscreenMenu }" class="h-[3px] bg-black w-full transform transition ease-out"></div>
<div :class="{ 'hidden' : fullscreenMenu }" class="h-[3px] bg-black w-full my-1"></div>
<div :class="{ '-rotate-45 translate-y-[3px] duration-300' : fullscreenMenu, 'group-hover:translate-y-0.5 duration-300' : !fullscreenMenu }" class="h-[3px] bg-black w-full transform transition ease-out"></div>
</div>
</div>
<div :class="{ '-translate-x-full' : !fullscreenMenu }" class="fixed inset-0 z-10 z-50 flex flex-col items-start justify-center w-screen h-screen py-10 pl-16 space-y-5 font-bold transition duration-300 transform bg-white ease">
<svg onclick="window.location='#_'" preserveAspectRatio="xMinYMin meet" viewBox="0 0 56 18" class="w-full h-full pl-10 text-left uppercase cursor-pointer hover:text-blue-600">
<text x="0" y="15" class="block w-full" text-anchor="start" fill="currentColor">Home</text>
</svg>
<svg onclick="window.location='#_'" preserveAspectRatio="xMinYMin meet" viewBox="0 0 56 18" class="w-full h-full pl-10 text-left uppercase cursor-pointer hover:text-blue-600">
<text x="0" y="15" class="block w-full" fill="currentColor">Features</text>
</svg>
<svg onclick="window.location='#_'" preserveAspectRatio="xMinYMin meet" viewBox="0 0 56 18" class="w-full h-full pl-10 text-left uppercase cursor-pointer hover:text-blue-600">
<text x="0" y="15" class="block w-full" fill="currentColor">Pricing</text>
</svg>
<svg onclick="window.location='#_'" preserveAspectRatio="xMinYMin meet" viewBox="0 0 56 18" class="w-full h-full pl-10 text-left uppercase cursor-pointer hover:text-blue-600">
<text x="0" y="15" class="block w-full" fill="currentColor">About</text>
</svg>
</div>
</div>
<!-- End Fullscreen Menu -->
</div>
</template>
</div>

View File

@ -0,0 +1,37 @@
<div x-data="{ fullscreenMenu: false }" class="relative inset-0 w-full h-full">
<div class="absolute top-0 left-0 w-full h-full">
<button class="absolute top-0 z-30 w-6 h-5 mt-5 mr-5 transition duration-300 transform -translate-x-1/2 cursor-pointer left-1/2 group" @click="fullscreenMenu=!fullscreenMenu">
<div :class="{ 'rotate-45 translate-y-[2px] duration-300' : fullscreenMenu, 'group-hover:-translate-y-[1px] duration-300' : !fullscreenMenu }" class="h-[2px] bg-black w-full rounded-full transform transition ease-out"></div>
<div :class="{ 'hidden' : fullscreenMenu }" class="h-[2px] bg-black w-full my-[5px]"></div>
<div :class="{ '-rotate-45 duration-300' : fullscreenMenu, 'group-hover:translate-y-[1px] duration-300' : !fullscreenMenu }" class="h-[2px] bg-black w-full rounded-full transform transition ease-out"></div>
</button>
<div x-show="fullscreenMenu" class="absolute inset-0 z-20 flex items-center justify-center w-screen h-screen bg-gray-50 text-neutral-500" x-cloak>
<ul class="space-y-2 text-center">
<li>
<a href="#_" class="relative inline-flex font-medium duration-300 ease-out hover:text-neutral-800 group">
<span>Home</span>
<span class="absolute bottom-0 left-0 w-0 h-0.5 duration-300 ease-out group-hover:w-full bg-neutral-800"></span>
</a>
</li>
<li>
<a href="#_" class="relative inline-flex font-medium duration-300 ease-out hover:text-neutral-800 group">
<span>Features</span>
<span class="absolute bottom-0 left-0 w-0 h-0.5 duration-300 ease-out group-hover:w-full bg-neutral-800"></span>
</a>
</li>
<li>
<a href="#_" class="relative inline-flex font-medium duration-300 ease-out hover:text-neutral-800 group">
<span>Pricing</span>
<span class="absolute bottom-0 left-0 w-0 h-0.5 duration-300 ease-out group-hover:w-full bg-neutral-800"></span>
</a>
</li>
<li>
<a href="#_" class="relative inline-flex font-medium duration-300 ease-out hover:text-neutral-800 group">
<span>About</span>
<span class="absolute bottom-0 left-0 w-0 h-0.5 duration-300 ease-out group-hover:w-full bg-neutral-800"></span>
</a>
</li>
</ul>
</div>
</div>
</div>

View File

@ -0,0 +1,12 @@
<div x-data="{ fullscreenMenu: false }" class="relative inset-0 w-full h-full">
<div class="absolute top-0 left-0 w-full h-full">
<button class="absolute top-0 left-0 z-30 w-6 h-5 mt-5 ml-5 transition duration-300 transform cursor-pointer group" @click="fullscreenMenu=!fullscreenMenu">
<div :class="{ 'rotate-45 translate-y-[2px] duration-300' : fullscreenMenu, 'group-hover:-translate-y-[1px] duration-300' : !fullscreenMenu }" class="h-[2px] bg-black w-full rounded-full transform transition ease-out"></div>
<div :class="{ 'hidden' : fullscreenMenu }" class="h-[2px] bg-black w-full my-[5px]"></div>
<div :class="{ '-rotate-45 duration-300' : fullscreenMenu, 'group-hover:translate-y-[1px] duration-300' : !fullscreenMenu }" class="h-[2px] bg-black w-full rounded-full transform transition ease-out"></div>
</button>
<div x-show="fullscreenMenu" class="absolute inset-0 z-20 flex items-center justify-center w-screen h-screen text-sm bg-gray-50 text-neutral-500" x-cloak>
Add your menu here
</div>
</div>
</div>

195
elements/menubar.html Normal file
View File

@ -0,0 +1,195 @@
<div x-data="{
menuBarOpen: false,
menuBarMenu: ''
}"
@click.away="menuBarOpen=false"
class="relative top-0 left-0 z-50 w-auto transition-all duration-150 ease-out"
>
<div class="relative top-0 left-0 z-40 w-auto h-10 transition duration-200 ease-out">
<div class="w-full h-full p-1 bg-white border rounded-md border-neutral-200/80">
<div class="flex justify-between w-full h-full select-none text-neutral-900">
<!-- File Button -->
<div class="relative h-full cursor-default">
<button @click="menuBarOpen=true; menuBarMenu='file'" @mouseover="menuBarMenu='file'" :class="{ 'bg-neutral-100' : menuBarOpen && menuBarMenu == 'file'}" class="rounded text-sm cursor-default flex items-center leading-tight justify-center px-3 py-1.5 h-full hover:bg-neutral-100">
File
</button>
<div
x-show="menuBarOpen && menuBarMenu=='file'"
x-transition:enter="transition ease-linear duration-100"
x-transition:enter-start="-translate-y-1 opacity-90"
x-transition:enter-end="translate-y-0 opacity-100"
class="absolute top-0 z-50 min-w-[8rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white mt-10 text-sm p-1 shadow-md w-48 -translate-x-0.5"
x-cloak>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>New Tab</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘T</span>
</button>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>New Window</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘N</span>
</button>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none" data-disabled>
<span>New Incognito Window</span>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button class="relative w-full group">
<div class="flex cursor-default select-none items-center rounded px-2 hover:bg-neutral-100 py-1.5 outline-none">
<span>Share</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu="" class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-32">
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Email link</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Messages</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Notes</div>
</div>
</div>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Print</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘P</span>
</button>
</div>
</div>
<!-- End File Button -->
<!-- Edit Button -->
<div class="relative h-full cursor-default">
<button @click="menuBarOpen=true; menuBarMenu='edit'" @mouseover="menuBarMenu='edit'" :class="{ 'bg-neutral-100' : menuBarOpen && menuBarMenu == 'edit'}" class="rounded text-sm cursor-default flex items-center leading-tight justify-center px-3 py-1.5 h-full hover:bg-neutral-100">
Edit
</button>
<div
x-show="menuBarOpen && menuBarMenu=='edit'"
x-transition:enter="transition ease-linear duration-100"
x-transition:enter-start="-translate-y-1 opacity-90"
x-transition:enter-end="translate-y-0 opacity-100"
class="absolute top-0 z-50 min-w-[8rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white mt-10 text-sm p-1 shadow-md w-48 -translate-x-0.5"
x-cloak>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Undo</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘Z</span>
</button>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Redo</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⇧⌘Z</span>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button class="relative w-full group">
<div class="flex cursor-default select-none items-center rounded px-2 hover:bg-neutral-100 py-1.5 outline-none">
<span>Find</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4 ml-auto"><polyline points="9 18 15 12 9 6"></polyline></svg>
</div>
<div data-submenu="" class="absolute top-0 right-0 invisible mr-1 duration-200 ease-out translate-x-full opacity-0 group-hover:mr-0 group-hover:visible group-hover:opacity-100">
<div class="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white p-1 shadow-md animate-in slide-in-from-left-1 w-32">
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Search the web</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Find...</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Find Next</div>
<div @click="contextMenuOpen=false" class="relative flex cursor-default select-none items-center rounded px-2 py-1.5 hover:bg-neutral-100 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50">Find Previous</div>
</div>
</div>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Cut</span>
</button>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Copy</span>
</button>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Paste</span>
</button>
</div>
</div>
<!-- End Edit Button -->
<!-- View Button -->
<div class="relative h-full cursor-default">
<button @click="menuBarOpen=true; menuBarMenu='view'" @mouseover="menuBarMenu='view'" :class="{ 'bg-neutral-100' : menuBarOpen && menuBarMenu == 'view'}" class="rounded text-sm cursor-default flex items-center leading-tight justify-center px-3 py-1.5 h-full hover:bg-neutral-100">
View
</button>
<div
x-show="menuBarOpen && menuBarMenu=='view'"
x-transition:enter="transition ease-linear duration-100"
x-transition:enter-start="-translate-y-1 opacity-90"
x-transition:enter-end="translate-y-0 opacity-100"
class="absolute top-0 z-50 min-w-[15rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white mt-10 text-sm p-1 shadow-md w-48 -translate-x-0.5"
x-cloak>
<button @click="menuBarOpen=false; alwaysShowBookmarks=!alwaysShowBookmarks;" x-data="{ alwaysShowBookmarks: false }" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span x-show="alwaysShowBookmarks" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
<span>Always Show Bookmarks Bar</span>
</button>
<button @click="menuBarOpen=false; alwaysShowFullURL=!alwaysShowFullURL" x-data="{ alwaysShowFullURL: true }" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span x-show="alwaysShowFullURL" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
<span>Always Show Full URLs</span>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Reload</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⌘R</span>
</button>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none" data-disabled>
<span>Force Reload</span>
<span class="ml-auto text-xs tracking-widest text-neutral-400 group-hover:text-neutral-600">⇧⌘R</span>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Toggle Fullscreen</span>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Hide Sidebar</span>
</button>
</div>
</div>
<!-- End View Button -->
<!-- Profiles Button -->
<div class="relative h-full cursor-default">
<button @click="menuBarOpen=true; menuBarMenu='profiles'" @mouseover="menuBarMenu='profiles'" :class="{ 'bg-neutral-100' : menuBarOpen && menuBarMenu == 'profiles'}" class="rounded text-sm cursor-default flex items-center leading-tight justify-center px-3 py-1.5 h-full hover:bg-neutral-100">
Profiles
</button>
<div
x-show="menuBarOpen && menuBarMenu=='profiles'"
x-transition:enter="transition ease-linear duration-100"
x-transition:enter-start="-translate-y-1 opacity-90"
x-transition:enter-end="translate-y-0 opacity-100"
class="absolute top-0 z-50 min-w-[8rem] text-neutral-800 rounded-md border border-neutral-200/70 bg-white mt-10 text-sm p-1 shadow-md w-48 -translate-x-0.5"
x-cloak>
<div x-data="{ contextMenuPeople: 'taylor' }" class="relative w-full">
<button @click="contextMenuPeople='taylor'; contextMenuOpen=false" class="relative w-full flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='taylor'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Taylor Otwell</span>
</button>
<button @click="contextMenuPeople='adam'; contextMenuOpen=false" class="relative w-full flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='adam'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Adam Wathan</span>
</button>
<button @click="contextMenuPeople='caleb'; contextMenuOpen=false" class="relative w-full flex cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 hover:bg-neutral-100 outline-none data-[disabled]:opacity-50">
<span x-show="contextMenuPeople=='caleb'" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 fill-current"><circle cx="12" cy="12" r="10"></circle></svg></span>
<span>Caleb Porzio</span>
</button>
</div>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Edit...</span>
</button>
<div class="h-px my-1 -mx-1 bg-neutral-200"></div>
<button @click="menuBarOpen=false" class="relative flex justify-between w-full pl-8 cursor-default select-none group items-center rounded px-2 py-1.5 hover:bg-neutral-100 hover:text-neutral-900 outline-none data-[disabled]:opacity-50 data-[disabled]:pointer-events-none">
<span>Add Profile...</span>
</button>
</div>
</div>
<!-- End Profiles Button -->
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,52 @@
<div x-data="{
modalOpen: false,
}"
x-init="
$watch('modalOpen', function(value){
if(value === true){
document.body.classList.add('overflow-hidden');
}else{
document.body.classList.remove('overflow-hidden');
}
})
"
@keydown.escape.window="modalOpen = false"
:class="{ 'z-40': modalOpen }" class="relative w-auto h-auto">
<button @click="modalOpen=true" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Open</button>
<template x-teleport="body">
<div x-show="modalOpen" class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" x-cloak>
<div x-show="modalOpen"
x-transition:enter="ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@click="modalOpen=false" class="absolute inset-0 w-full h-full bg-white backdrop-blur-sm bg-opacity-70"></div>
<div x-show="modalOpen"
x-trap.inert.noscroll="show"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="relative w-full py-6 bg-white border shadow-lg px-7 border-neutral-200 sm:max-w-lg sm:rounded-lg">
<div class="flex items-center justify-between pb-3">
<h3 class="text-lg font-semibold">Modal Title</h3>
<button @click="modalOpen=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
<div class="relative w-auto pb-8">
<p>This is placeholder text. Replace it with your own content.</p>
</div>
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
<button @click="modalOpen=false" type="button" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors border rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-100 focus:ring-offset-2">Cancel</button>
<button @click="modalOpen=false" type="button" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium text-white transition-colors border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 bg-neutral-950 hover:bg-neutral-900">Continue</button>
</div>
</div>
</div>
</template>
</div>

View File

@ -0,0 +1,51 @@
<div x-data="{
modalOpen: false,
}"
x-init="
$watch('modalOpen', function(value){
if(value === true){
document.body.classList.add('overflow-hidden');
}else{
document.body.classList.remove('overflow-hidden');
}
})
"
@keydown.escape.window="modalOpen = false"
:class="{ 'z-40': modalOpen }" class="relative w-auto h-auto">
<button @click="modalOpen=true" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Open</button>
<template x-teleport="body">
<div x-show="modalOpen" class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" x-cloak>
<div x-show="modalOpen"
x-transition:enter="ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@click="modalOpen=false" class="absolute inset-0 w-full h-full bg-gray-900 bg-opacity-50 backdrop-blur-sm"></div>
<div x-show="modalOpen"
x-trap.inert.noscroll="show"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
class="relative w-full py-6 bg-white border shadow-lg px-7 border-neutral-400 sm:max-w-lg sm:rounded-lg">
<div class="flex items-center justify-between pb-3">
<h3 class="text-lg font-semibold">Modal Title</h3>
<button @click="modalOpen=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
<div class="relative w-auto pb-8">
<p>This is placeholder text. Replace it with your own content.</p>
</div>
<div class="flex flex-col-reverse sm:flex-row sm:justify-between sm:space-x-2">
<button @click="modalOpen=false" type="button" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors border rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-100 focus:ring-offset-2">Previous</button>
<button @click="modalOpen=false" type="button" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium text-white transition-colors border border-transparent rounded-md focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-2 bg-neutral-950 hover:bg-neutral-900">Next</button>
</div>
</div>
</div>
</template>
</div>

47
elements/modal.html Normal file
View File

@ -0,0 +1,47 @@
<div x-data="{
modalOpen: false,
}"
x-init="
$watch('modalOpen', function(value){
if(value === true){
document.body.classList.add('overflow-hidden');
}else{
document.body.classList.remove('overflow-hidden');
}
})
"
@keydown.escape.window="modalOpen = false"
class="relative z-50 w-auto h-auto">
<button @click="modalOpen=true" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors bg-white border rounded-md hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-neutral-200/60 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none">Open</button>
<template x-teleport="body">
<div x-show="modalOpen" class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" x-cloak>
<div x-show="modalOpen"
x-transition:enter="ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@click="modalOpen=false" class="absolute inset-0 w-full h-full bg-black bg-opacity-40"></div>
<div x-show="modalOpen"
x-trap.inert.noscroll="show"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
class="relative w-full py-6 bg-white px-7 sm:max-w-lg sm:rounded-lg">
<div class="flex items-center justify-between pb-2">
<h3 class="text-lg font-semibold">Modal Title</h3>
<button @click="modalOpen=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
<div class="relative w-auto">
<p>This is placeholder text. Replace it with your own content.</p>
</div>
</div>
</div>
</template>
</div>

View File

@ -0,0 +1,117 @@
<nav x-data="{
navigationMenuOpen: false,
navigationMenuCloseTimeout: null,
navibationMenuCloseDelay: 300,
navigationMenu: '',
navigationMenuLeave() {
let that = this;
this.navigationMenuCloseTimeout = setTimeout(() => {
that.navigationMenuClose();
}, this.navibationMenuCloseDelay);
},
navigationMenuReposition(navElement) {
this.navigationMenuClearCloseTimeout();
this.$refs.navigationDropdown.style.left = navElement.offsetLeft + 'px';
this.$refs.navigationDropdown.style.marginLeft = (navElement.offsetWidth/2) + 'px';
},
navigationMenuClearCloseTimeout(){
clearTimeout(this.navigationMenuCloseTimeout);
},
navigationMenuClose(){
this.navigationMenuOpen = false;
this.navigationMenu = '';
}
}"
class="relative z-10 w-auto">
<div class="relative">
<ul class="flex items-center justify-center flex-1 p-1 space-x-1 list-none border rounded-md text-neutral-700 group border-neutral-200/80">
<li>
<button
:class="{ 'bg-neutral-100' : navigationMenu=='getting-started', 'hover:bg-neutral-100' : navigationMenu!='getting-started' }" @mouseover="navigationMenuOpen=true; navigationMenuReposition($el); navigationMenu='getting-started'" @mouseleave="navigationMenuLeave()" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md hover:text-neutral-900 focus:outline-none disabled:opacity-50 disabled:pointer-events-none group w-max">
<span>Getting started</span>
<svg :class="{ '-rotate-180' : navigationMenuOpen==true && navigationMenu == 'getting-started' }" class="relative top-[1px] ml-1 h-3 w-3 ease-out duration-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"></polyline></svg>
</button>
</li>
<li>
<button
:class="{ 'bg-neutral-100' : navigationMenu=='learn-more', 'hover:bg-neutral-100' : navigationMenu!='learn-more' }" @mouseover="navigationMenuOpen=true; navigationMenuReposition($el); navigationMenu='learn-more'" @mouseleave="navigationMenuLeave()" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md hover:text-neutral-900 focus:outline-none disabled:opacity-50 disabled:pointer-events-none bg-background hover:bg-neutral-100 group w-max">
<span>Learn More</span>
<svg :class="{ '-rotate-180' : navigationMenuOpen==true && navigationMenu == 'learn-more' }" class="relative top-[1px] ml-1 h-3 w-3 ease-out duration-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"></polyline></svg>
</button>
</li>
<li>
<a href="#_" class="inline-flex items-center justify-center h-10 px-4 py-2 text-sm font-medium transition-colors rounded-md hover:text-neutral-900 focus:outline-none disabled:opacity-50 disabled:pointer-events-none bg-background hover:bg-neutral-100 group w-max">
Documentation
</a>
</li>
</ul>
</div>
<div x-ref="navigationDropdown" x-show="navigationMenuOpen"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-100"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
@mouseover="navigationMenuClearCloseTimeout()" @mouseleave="navigationMenuLeave()"
class="absolute top-0 pt-3 duration-200 ease-out -translate-x-1/2 translate-y-11" x-cloak>
<div class="flex justify-center w-auto h-auto overflow-hidden bg-white border rounded-md shadow-sm border-neutral-200/70">
<div x-show="navigationMenu == 'getting-started'" class="flex items-stretch justify-center w-full max-w-2xl p-6 gap-x-3">
<div class="flex-shrink-0 w-48 rounded pt-28 pb-7 bg-gradient-to-br from-neutral-800 to-black">
<div class="relative px-7 space-y-1.5 text-white">
<svg class="block w-auto h-9" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M67.683 89.217h44.634l30.9 53.218H36.783l30.9-53.218Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M77.478 120.522h21.913v46.956H77.478v-46.956Zm-34.434-29.74 45.59-78.26 46.757 78.26H43.044Z" fill="currentColor"/></svg>
<span class="block font-bold">Pines UI</span>
<span class="block text-sm opacity-60">An Alpine and Tailwind UI library</span>
</div>
</div>
<div class="w-72">
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Introduction</span>
<span class="block font-light leading-5 opacity-50">Re-usable elements built using Alpine JS and Tailwind CSS.</span>
</a>
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">How to use</span>
<span class="block leading-5 opacity-50">Couldn't be easier. It's is as simple as copy, paste, and preview.</span>
</a>
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Contributing</span>
<span class="block leading-5 opacity-50">Feel free to contribute your expertise. All these elements are open-source.</span>
</a>
</div>
</div>
<div x-show="navigationMenu == 'learn-more'" class="flex items-stretch justify-center w-full p-6">
<div class="w-72">
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Tailwind CSS</span>
<span class="block font-light leading-5 opacity-50">A utility first CSS framework for building amazing websites.</span>
</a>
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Laravel</span>
<span class="block font-light leading-5 opacity-50">The perfect all-in-one framework for building amazing apps.</span>
</a>
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Pines UI</span>
<span class="block leading-5 opacity-50">An Alpine JS and Tailwind CSS UI library for awesome people. </span>
</a>
</div>
<div class="w-72">
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">ApineJS</span>
<span class="block font-light leading-5 opacity-50">A framework without the complex setup or heavy dependencies.</span>
</a>
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Livewire</span>
<span class="block leading-5 opacity-50">A seamless integration of server-side and client-side interactions.</span>
</a>
<a href="#_" @click="navigationMenuClose()" class="block px-3.5 py-3 text-sm rounded hover:bg-neutral-100">
<span class="block mb-1 font-medium text-black">Tails</span>
<span class="block leading-5 opacity-50">The ultimate Tailwind CSS design tool that helps you craft beautiful websites.</span>
</a>
</div>
</div>
</div>
</div>
</nav>

View File

@ -0,0 +1,52 @@
<div class="flex items-center justify-between w-full h-16 px-3 border-t border-neutral-200">
<p class="pl-2 text-sm text-gray-700">Showing <span class="font-medium">1</span> to <span class="font-medium">10</span> of <span class="font-medium">89</span> results</p>
<nav>
<ul class="flex items-center text-sm leading-tight bg-white border border-neutral-200/70 rounded h-[34px] text-neutral-500">
<li class="h-full">
<a href="#" class="relative inline-flex items-center h-full px-3 rounded-l group hover:bg-blue-600 hover:text-white">
<span>Previous</span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 text-white bg-blue-600 group">
<span>1</span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:bg-blue-600 hover:text-white">
<span>2</span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:bg-blue-600 hover:text-white">
<span>3</span>
</a>
</li>
<li class="hidden h-full md:block">
<div class="relative inline-flex items-center h-full px-2.5 bg-neutral-100 group">
<span>...</span>
</div>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:bg-blue-600 hover:text-white">
<span>6</span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:bg-blue-600 hover:text-white">
<span>7</span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:bg-blue-600 hover:text-white">
<span>8</span>
</a>
</li>
<li class="h-full">
<a href="#" class="relative inline-flex items-center h-full px-3 rounded-r group hover:bg-blue-600 hover:text-white">
<span>Next</span>
</a>
</li>
</ul>
</nav>
</div>

58
elements/pagination.html Normal file
View File

@ -0,0 +1,58 @@
<div class="flex items-center justify-between w-full h-16 px-3 border-t border-neutral-200">
<p class="pl-2 text-sm text-gray-700">Showing <span class="font-medium">1</span> to <span class="font-medium">10</span> of <span class="font-medium">89</span> results</p>
<nav>
<ul class="flex items-center text-sm leading-tight bg-white border divide-x rounded h-9 text-neutral-500 divide-neutral-200 border-neutral-200">
<li class="h-full">
<a href="#" class="relative inline-flex items-center h-full px-3 ml-0 rounded-l group hover:text-neutral-900">
<span>Previous</span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 text-neutral-900 group bg-gray-50">
<span>1</span>
<span class="box-content absolute bottom-0 left-0 w-full h-px -mx-px translate-y-px border-l border-r bg-neutral-900 border-neutral-900"></span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:text-neutral-900">
<span>2</span>
<span class="box-content absolute bottom-0 w-0 h-px -mx-px duration-200 ease-out translate-y-px border-transparent bg-neutral-900 group-hover:border-l group-hover:border-r group-hover:border-neutral-900 left-1/2 group-hover:left-0 group-hover:w-full"></span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:text-neutral-900">
<span>3</span>
<span class="box-content absolute bottom-0 w-0 h-px -mx-px duration-200 ease-out translate-y-px border-transparent bg-neutral-900 group-hover:border-l group-hover:border-r group-hover:border-neutral-900 left-1/2 group-hover:left-0 group-hover:w-full"></span>
</a>
</li>
<li class="hidden h-full md:block">
<div class="relative inline-flex items-center h-full px-2.5 group">
<span>...</span>
</div>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:text-neutral-900">
<span>6</span>
<span class="box-content absolute bottom-0 w-0 h-px -mx-px duration-200 ease-out translate-y-px border-transparent bg-neutral-900 group-hover:border-l group-hover:border-r group-hover:border-neutral-900 left-1/2 group-hover:left-0 group-hover:w-full"></span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:text-neutral-900">
<span>7</span>
<span class="box-content absolute bottom-0 w-0 h-px -mx-px duration-200 ease-out translate-y-px border-transparent bg-neutral-900 group-hover:border-l group-hover:border-r group-hover:border-neutral-900 left-1/2 group-hover:left-0 group-hover:w-full"></span>
</a>
</li>
<li class="hidden h-full md:block">
<a href="#" class="relative inline-flex items-center h-full px-3 group hover:text-neutral-900">
<span>8</span>
<span class="box-content absolute bottom-0 w-0 h-px -mx-px duration-200 ease-out translate-y-px border-transparent bg-neutral-900 group-hover:border-l group-hover:border-r group-hover:border-neutral-900 left-1/2 group-hover:left-0 group-hover:w-full"></span>
</a>
</li>
<li class="h-full">
<a href="#" class="relative inline-flex items-center h-full px-3 rounded-r group hover:text-neutral-900">
<span>Next</span>
</a>
</li>
</ul>
</nav>
</div>

67
elements/popover.html Normal file
View File

@ -0,0 +1,67 @@
<div x-data="{
popoverOpen: false,
popoverHeight: 0,
popoverPosition: 'bottom',
popoverOffset: 8,
popoverArrow: true,
popoverHeightCalculate() {
this.$refs.popover.classList.add('invisible');
this.popoverOpen=true;
let that=this;
$nextTick(function(){
that.popoverHeight = that.$refs.popover.offsetHeight;
that.popoverOpen=false;
that.$refs.popover.classList.remove('invisible');
that.$refs.popoverInner.setAttribute('x-transition', '');
});
},
popoverPositionCalculate(){
console.log(this.$refs.popoverButton.getBoundingClientRect().top)
if(window.innerHeight < (this.$refs.popoverButton.getBoundingClientRect().top + this.$refs.popoverButton.offsetHeight + this.popoverOffset + this.popoverHeight)){
this.popoverPosition = 'top';
} else {
this.popoverPosition = 'bottom';
}
}
}"
x-init="
that = this;
window.addEventListener('resize', function(){
popoverPositionCalculate();
});
$watch('popoverOpen', function(value){
if(value){ popoverPositionCalculate(); }
});
"
class="relative">
<button x-ref="popoverButton" @click="popoverOpen=!popoverOpen" class="flex items-center justify-center w-10 h-10 bg-white border rounded-full shadow-sm cursor-pointer hover:bg-neutral-100 active:bg-white border-neutral-200/70">
<svg class="w-4 h-4" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.5 3C4.67157 3 4 3.67157 4 4.5C4 5.32843 4.67157 6 5.5 6C6.32843 6 7 5.32843 7 4.5C7 3.67157 6.32843 3 5.5 3ZM3 5C3.01671 5 3.03323 4.99918 3.04952 4.99758C3.28022 6.1399 4.28967 7 5.5 7C6.71033 7 7.71978 6.1399 7.95048 4.99758C7.96677 4.99918 7.98329 5 8 5H13.5C13.7761 5 14 4.77614 14 4.5C14 4.22386 13.7761 4 13.5 4H8C7.98329 4 7.96677 4.00082 7.95048 4.00242C7.71978 2.86009 6.71033 2 5.5 2C4.28967 2 3.28022 2.86009 3.04952 4.00242C3.03323 4.00082 3.01671 4 3 4H1.5C1.22386 4 1 4.22386 1 4.5C1 4.77614 1.22386 5 1.5 5H3ZM11.9505 10.9976C11.7198 12.1399 10.7103 13 9.5 13C8.28967 13 7.28022 12.1399 7.04952 10.9976C7.03323 10.9992 7.01671 11 7 11H1.5C1.22386 11 1 10.7761 1 10.5C1 10.2239 1.22386 10 1.5 10H7C7.01671 10 7.03323 10.0008 7.04952 10.0024C7.28022 8.8601 8.28967 8 9.5 8C10.7103 8 11.7198 8.8601 11.9505 10.0024C11.9668 10.0008 11.9833 10 12 10H13.5C13.7761 10 14 10.2239 14 10.5C14 10.7761 13.7761 11 13.5 11H12C11.9833 11 11.9668 10.9992 11.9505 10.9976ZM8 10.5C8 9.67157 8.67157 9 9.5 9C10.3284 9 11 9.67157 11 10.5C11 11.3284 10.3284 12 9.5 12C8.67157 12 8 11.3284 8 10.5Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
</button>
<div x-ref="popover"
x-show="popoverOpen"
x-init="popoverHeightCalculate()"
x-trap.inert="popoverOpen"
@click.away="popoverOpen=false;"
@keydown.escape.window="popoverOpen=false"
:class="{ 'top-0 mt-12' : popoverPosition == 'bottom', 'bottom-0 mb-12' : popoverPosition == 'top' }"
class="absolute w-[300px] max-w-lg -translate-x-1/2 left-1/2" x-cloak>
<div x-ref="popoverInner" x-show="popoverOpen" class="w-full p-4 bg-white border rounded-md shadow-sm border-neutral-200/70">
<div x-show="popoverArrow && popoverPosition == 'bottom'" class="absolute top-0 inline-block w-5 mt-px overflow-hidden -translate-x-2 -translate-y-2.5 left-1/2"><div class="w-2.5 h-2.5 origin-bottom-left transform rotate-45 bg-white border-t border-l rounded-sm"></div></div>
<div x-show="popoverArrow && popoverPosition == 'top'" class="absolute bottom-0 inline-block w-5 mb-px overflow-hidden -translate-x-2 translate-y-2.5 left-1/2"><div class="w-2.5 h-2.5 origin-top-left transform -rotate-45 bg-white border-b border-l rounded-sm"></div></div>
<div class="grid gap-4">
<div class="space-y-2">
<h4 class="font-medium leading-none">Dimensions</h4>
<p class="text-sm text-muted-foreground">Set the dimensions for the layer.</p>
</div>
<div class="grid gap-2">
<div class="grid items-center grid-cols-3 gap-4"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="width">Width</label><input class="flex w-full h-8 col-span-2 px-3 py-2 text-sm bg-transparent border rounded-md border-input ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" id="width" value="100%"></div>
<div class="grid items-center grid-cols-3 gap-4"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="maxWidth">Max. width</label><input class="flex w-full h-8 col-span-2 px-3 py-2 text-sm bg-transparent border rounded-md border-input ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" id="maxWidth" value="300px"></div>
<div class="grid items-center grid-cols-3 gap-4"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="height">Height</label><input class="flex w-full h-8 col-span-2 px-3 py-2 text-sm bg-transparent border rounded-md border-input ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" id="height" value="25px"></div>
<div class="grid items-center grid-cols-3 gap-4"><label class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="maxHeight">Max. height</label><input class="flex w-full h-8 col-span-2 px-3 py-2 text-sm bg-transparent border rounded-md border-input ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" id="maxHeight" value="none"></div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,10 @@
<input
type="range" min="0" max="100" value="50" step="any"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-blue-600 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-2.5 [&::-moz-range-thumb]:h-2.5 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-blue-600 [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-2.5 [&::-ms-thumb]:h-2.5 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-neutral-200 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-blue-400 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-blue-400 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-999px_0px_0px_990px_#4e97ff]
">

97
elements/select.html Normal file
View File

@ -0,0 +1,97 @@
<div x-data="{
selectedValue: '',
selectableItems: [
{
title: 'Milk',
value: 'milk',
disabled: false
},
{
title: 'Eggs',
value: 'eggs',
disabled: false
},
{
title: 'Cheese',
value: 'cheese',
disabled: false
},
{
title: 'Bread',
value: 'bread',
disabled: false
},
{
title: 'Apples',
value: 'apples',
disabled: false
},
{
title: 'Bananas',
value: 'bananas',
disabled: false
},
{
title: 'Yogurt',
value: 'yogurt',
disabled: false
},
{
title: 'Sugar',
value: 'sugar',
disabled: false
},
{
title: 'Salt',
value: 'salt',
disabled: false
},
{
title: 'Coffee',
value: 'coffee',
disabled: false
},
{
title: 'Tea',
value: 'tea',
disabled: false
}
],
selectableItemsOpen: false,
}"
class="relative w-64">
<button @click="selectableItemsOpen=!selectableItemsOpen" class="relative flex items-center justify-between w-full py-2 pl-3 pr-10 text-left bg-white border rounded-md shadow-sm cursor-default border-neutral-200/70 focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm">
<span x-text="selectedValue ? selectedValue.title : 'Select Item'" class="truncate"></span>
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="w-5 h-5 text-gray-400"><path fill-rule="evenodd" d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z" clip-rule="evenodd"></path></svg>
</span>
</button>
<ul x-show="selectableItemsOpen"
@click.away="selectableItemsOpen = false"
x-transition:enter="transition ease-out duration-50"
x-transition:enter-start="opacity-0 -translate-y-1"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-out duration-50"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0 -translate-y-1"
class="absolute w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-md max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
x-cloak>
<template x-for="item in selectableItems" :key="item.value">
<li
@click="selectedValue=item; selectableItemsOpen=false"
x-text="item.title"
:disabled="item-disabled"
class="relative py-2 pl-4 pr-10 text-gray-700 cursor-default select-none hover:bg-neutral-100 hover:text-gray-900">
<span class="block font-medium truncate" x-text="item.title"></span>
<span x-show="selectedValue==item.value" class="absolute inset-y-0 right-0 flex items-center pr-3 text-amber-600">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></svg>
</span>
</li>
</template>
</ul>
</div>

20
elements/switch.html Normal file
View File

@ -0,0 +1,20 @@
<div x-data="{ switchOn: false }" class="flex items-center justify-center space-x-2" x-id="['switch']">
<input type="hidden" name="switch" :value="switchOn">
<button
x-ref="switchButton"
type="button"
@click="switchOn = ! switchOn"
:class="switchOn ? 'bg-blue-600' : 'bg-neutral-200'"
class="relative inline-flex h-6 py-0.5 ml-4 focus:outline-none rounded-full w-10"
x-cloak>
<span :class="switchOn ? 'translate-x-[18px]' : 'translate-x-0.5'" class="w-5 h-5 duration-200 ease-in-out bg-white rounded-full shadow-md" aria-hidden="true"></span>
</button>
<label @click="$refs.switchButton.click(); $refs.switchButton.focus()" :id="$id('switch')"
:class="{ 'text-blue-600': switchOn, 'text-gray-400': ! switchOn }"
class="text-sm select-none"
x-cloak>
Enable Feature
</label>
</div>

View File

@ -0,0 +1,63 @@
<div
x-data
x-init="
function generateTableOfContents() {
// Get all the headings in the document
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
// If there are no headings, exit the function
if (headings.length === 0) {
return;
}
// Create an unordered list to hold the table of contents
const tocList = document.createElement('ul');
// Keep track of the previous heading level to determine if we need to create sub-lists
let previousLevel = parseInt(headings[0].tagName.substring(1));
let currentList = tocList;
// Loop through each heading and create a table of contents entry
for (let i = 0; i < headings.length; i++) {
const heading = headings[i];
const level = parseInt(heading.tagName.substring(1));
// Create a link to the heading
const link = document.createElement('a');
link.href = '#' + heading.id;
link.textContent = heading.textContent;
// Create a list item to hold the link
const listItem = document.createElement('li');
listItem.appendChild(link);
// Determine if we need to create a sub-list
if (level > previousLevel) {
const sublist = document.createElement('ul');
currentList.lastChild.appendChild(sublist);
currentList = sublist;
} else if (level < previousLevel) {
currentList = currentList.parentNode.parentNode;
}
currentList.appendChild(listItem);
previousLevel = level;
}
// Add the table of contents to the page
const tocContainer = document.querySelector('#toc');
tocContainer.appendChild(tocList);
}
"
class="relative flex flex-col">
<div class="relative">
<p class="mb-2 font-semibold tracking-tight">Table of Contents</p>
<ul>
<li class="text-sm transition-colors hover:text-text-neutral-700 text-neutral-500"><a href="#_">asdf</a></li>
<li class="text-sm transition-colors hover:text-text-neutral-700 text-neutral-500"><a href="#_">asdf</a></li>
</ul>
</div>
</div>

13
elements/tabs.html Normal file
View File

@ -0,0 +1,13 @@
<div x-data="{
repositionTabMarker(el){
this.$refs.marker.style.width=el.offsetWidth + 'px';
this.$refs.marker.style.height=el.offsetHeight + 'px';
this.$refs.marker.style.left=el.offsetLeft + 'px';
}
}" x-init="repositionTabMarker($el.firstElementChild);" class="relative inline-grid items-center justify-center w-auto h-10 grid-cols-2 p-1 text-gray-500 bg-gray-100 rounded-lg select-none">
<button type="button" @click="repositionTabMarker($el); preview=true;" class="relative z-20 inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap ring-offset-background">Preview</button>
<button type="button" @click="repositionTabMarker($el); preview=false" class="relative z-20 inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap ring-offset-background">Code</button>
<div x-ref="marker" class="absolute left-0 z-10 w-1/2 h-full duration-300 ease-out" style="width: 76px; height: 32px; left: 4px;">
<div class="w-full h-full bg-white rounded-md shadow-sm"></div>
</div>
</div>

View File

@ -0,0 +1,41 @@
<h1 x-data="{
startingAnimation: { opacity: 0, y: 50, rotation: '25deg' },
endingAnimation: { opacity: 1, y: 0, rotation: '0deg', stagger: 0.02, duration: 0.7, ease: 'back' },
addCNDScript: true,
splitCharactersIntoSpans(element) {
text = element.innerHTML;
modifiedHTML = [];
for (var i = 0; i < text.length; i++) {
attributes = '';
if(text[i].trim()){ attributes = 'class=\'inline-block\''; }
modifiedHTML.push('<span ' + attributes + '>' + text[i] + '</span>');
}
element.innerHTML = modifiedHTML.join('');
},
addScriptToHead(url) {
script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
},
animateText() {
$el.classList.remove('invisible');
gsap.fromTo($el.children, this.startingAnimation, this.endingAnimation);
}
}"
x-init="
splitCharactersIntoSpans($el);
if(addCNDScript){
addScriptToHead('https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js');
}
gsapInterval2 = setInterval(function(){
if(typeof gsap !== 'undefined'){
animateText();
clearInterval(gsapInterval2);
}
}, 5);
"
class="invisible block pb-0.5 overflow-hidden text-3xl font-bold custom-font"
>
Pines UI Library
</h1>

View File

@ -0,0 +1,41 @@
<h1 x-data="{
startingAnimation: { opacity: 0 },
endingAnimation: { opacity: 1, stagger: 0.08, duration: 2.7, ease: 'power4.easeOut' },
addCNDScript: true,
splitCharactersIntoSpans(element) {
text = element.innerHTML;
modifiedHTML = [];
for (var i = 0; i < text.length; i++) {
attributes = '';
if(text[i].trim()){ attributes = 'class=\'inline-block\''; }
modifiedHTML.push('<span ' + attributes + '>' + text[i] + '</span>');
}
element.innerHTML = modifiedHTML.join('');
},
addScriptToHead(url) {
script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
},
animateText() {
$el.classList.remove('invisible');
gsap.fromTo($el.children, this.startingAnimation, this.endingAnimation);
}
}"
x-init="
splitCharactersIntoSpans($el);
if(addCNDScript){
addScriptToHead('https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js');
}
gsapInterval3 = setInterval(function(){
if(typeof gsap !== 'undefined'){
animateText();
clearInterval(gsapInterval3);
}
}, 5);
"
class="invisible block pb-0.5 overflow-hidden text-3xl font-bold custom-font"
>
Pines UI Library
</h1>

View File

@ -0,0 +1,41 @@
<h1 x-data="{
startingAnimation: { opacity: 0, scale: 4 },
endingAnimation: { opacity: 1, scale: 1, stagger: 0.07, duration: 1, ease: 'expo.out' },
addCNDScript: true,
splitCharactersIntoSpans(element) {
text = element.innerHTML;
modifiedHTML = [];
for (var i = 0; i < text.length; i++) {
attributes = '';
if(text[i].trim()){ attributes = 'class=\'inline-block\''; }
modifiedHTML.push('<span ' + attributes + '>' + text[i] + '</span>');
}
element.innerHTML = modifiedHTML.join('');
},
addScriptToHead(url) {
script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
},
animateText() {
$el.classList.remove('invisible');
gsap.fromTo($el.children, this.startingAnimation, this.endingAnimation);
}
}"
x-init="
splitCharactersIntoSpans($el);
if(addCNDScript){
addScriptToHead('https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js');
}
gsapInterval = setInterval(function(){
if(typeof gsap !== 'undefined'){
animateText();
clearInterval(gsapInterval);
}
}, 5);
"
class="invisible block text-3xl font-bold custom-font"
>
Pines UI Library
</h1>

3
elements/text-input.html Normal file
View File

@ -0,0 +1,3 @@
<input type="text"
placeholder="Name"
class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50" />

View File

@ -0,0 +1,22 @@
<div
x-data="{
tooltipVisible: false,
tooltipText: 'Tooltip text',
tooltipArrow: false,
tooltipPosition: 'left',
}"
x-init="$refs.content.addEventListener('mouseenter', () => { tooltipVisible = true; }); $refs.content.addEventListener('mouseleave', () => { tooltipVisible = false; });"
class="relative">
<div x-ref="tooltip" x-show="tooltipVisible" :class="{ 'top-0 left-1/2 -translate-x-1/2 -mt-0.5 -translate-y-full' : tooltipPosition == 'top', 'top-1/2 -translate-y-1/2 -ml-0.5 left-0 -translate-x-full' : tooltipPosition == 'left', 'bottom-0 left-1/2 -translate-x-1/2 -mb-0.5 translate-y-full' : tooltipPosition == 'bottom', 'top-1/2 -translate-y-1/2 -mr-0.5 right-0 translate-x-full' : tooltipPosition == 'right' }" class="absolute w-auto text-sm" x-cloak>
<div x-show="tooltipVisible" x-transition class="relative px-2 py-1 text-white bg-blue-600 rounded-md bg-opacity-90">
<p x-text="tooltipText" class="flex-shrink-0 block text-xs whitespace-nowrap"></p>
<div x-ref="tooltipArrow" x-show="tooltipArrow" :class="{ 'bottom-0 -translate-x-1/2 left-1/2 w-2.5 translate-y-full' : tooltipPosition == 'top', 'right-0 -translate-y-1/2 top-1/2 h-2.5 -mt-px translate-x-full' : tooltipPosition == 'left', 'top-0 -translate-x-1/2 left-1/2 w-2.5 -translate-y-full' : tooltipPosition == 'bottom', 'left-0 -translate-y-1/2 top-1/2 h-2.5 -mt-px -translate-x-full' : tooltipPosition == 'right' }" class="absolute inline-flex items-center justify-center overflow-hidden">
<div :class="{ 'origin-top-left -rotate-45' : tooltipPosition == 'top', 'origin-top-left rotate-45' : tooltipPosition == 'left', 'origin-bottom-left rotate-45' : tooltipPosition == 'bottom', 'origin-top-right -rotate-45' : tooltipPosition == 'right' }" class="w-1.5 h-1.5 transform bg-blue-600 bg-opacity-90"></div>
</div>
</div>
</div>
<div x-ref="content" class="px-3 py-1 text-xs rounded-full cursor-pointer text-neutral-500 bg-neutral-100">hover me</div>
</div>

View File

@ -0,0 +1,29 @@
<div
x-data="{
tooltipVisible: false,
tooltipText: 'Tooltip text',
tooltipArrow: true,
tooltipPosition: 'right',
}"
x-init="$refs.content.addEventListener('mouseenter', () => { tooltipVisible = true; }); $refs.content.addEventListener('mouseleave', () => { tooltipVisible = false; });"
class="relative">
<div x-ref="tooltip" x-show="tooltipVisible" :class="{ 'top-0 left-1/2 -translate-x-1/2 -mt-0.5 -translate-y-full' : tooltipPosition == 'top', 'top-1/2 -translate-y-1/2 -ml-0.5 left-0 -translate-x-full' : tooltipPosition == 'left', 'bottom-0 left-1/2 -translate-x-1/2 -mb-0.5 translate-y-full' : tooltipPosition == 'bottom', 'top-1/2 -translate-y-1/2 -mr-0.5 right-0 translate-x-full' : tooltipPosition == 'right' }" class="absolute w-auto text-sm" x-cloak>
<div x-show="tooltipVisible"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90 -translate-x-2"
x-transition:enter-end="opacity-100 scale-100 translate-x-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 scale-100 translate-x-0"
x-transition:leave-end="opacity-0 scale-90 -translate-x-2"
class="relative px-2 py-1 text-white rounded bg-gradient-to-t from-blue-600 to-purple-600 bg-opacity-90">
<p x-text="tooltipText" class="flex-shrink-0 block text-xs whitespace-nowrap"></p>
<div x-ref="tooltipArrow" x-show="tooltipArrow" :class="{ 'bottom-0 -translate-x-1/2 left-1/2 w-2.5 translate-y-full' : tooltipPosition == 'top', 'right-0 -translate-y-1/2 top-1/2 h-2.5 -mt-px translate-x-full' : tooltipPosition == 'left', 'top-0 -translate-x-1/2 left-1/2 w-2.5 -translate-y-full' : tooltipPosition == 'bottom', 'left-0 -translate-y-1/2 top-1/2 h-2.5 -mt-px -translate-x-full' : tooltipPosition == 'right' }" class="absolute inline-flex items-center justify-center overflow-hidden">
<div :class="{ 'origin-top-left -rotate-45' : tooltipPosition == 'top', 'origin-top-left rotate-45' : tooltipPosition == 'left', 'origin-bottom-left rotate-45' : tooltipPosition == 'bottom', 'origin-top-right -rotate-45' : tooltipPosition == 'right' }" class="w-1.5 h-1.5 transform bg-indigo-600 bg-opacity-90"></div>
</div>
</div>
</div>
<div x-ref="content" class="px-3 py-1 text-xs rounded-full cursor-pointer text-neutral-500 bg-neutral-100">hover me</div>
</div>

22
elements/tooltip.html Normal file
View File

@ -0,0 +1,22 @@
<div
x-data="{
tooltipVisible: false,
tooltipText: 'Tooltip text',
tooltipArrow: true,
tooltipPosition: 'top',
}"
x-init="$refs.content.addEventListener('mouseenter', () => { tooltipVisible = true; }); $refs.content.addEventListener('mouseleave', () => { tooltipVisible = false; });"
class="relative">
<div x-ref="tooltip" x-show="tooltipVisible" :class="{ 'top-0 left-1/2 -translate-x-1/2 -mt-0.5 -translate-y-full' : tooltipPosition == 'top', 'top-1/2 -translate-y-1/2 -ml-0.5 left-0 -translate-x-full' : tooltipPosition == 'left', 'bottom-0 left-1/2 -translate-x-1/2 -mb-0.5 translate-y-full' : tooltipPosition == 'bottom', 'top-1/2 -translate-y-1/2 -mr-0.5 right-0 translate-x-full' : tooltipPosition == 'right' }" class="absolute w-auto text-sm" x-cloak>
<div x-show="tooltipVisible" x-transition class="relative px-2 py-1 text-white bg-black rounded bg-opacity-90">
<p x-text="tooltipText" class="flex-shrink-0 block text-xs whitespace-nowrap"></p>
<div x-ref="tooltipArrow" x-show="tooltipArrow" :class="{ 'bottom-0 -translate-x-1/2 left-1/2 w-2.5 translate-y-full' : tooltipPosition == 'top', 'right-0 -translate-y-1/2 top-1/2 h-2.5 -mt-px translate-x-full' : tooltipPosition == 'left', 'top-0 -translate-x-1/2 left-1/2 w-2.5 -translate-y-full' : tooltipPosition == 'bottom', 'left-0 -translate-y-1/2 top-1/2 h-2.5 -mt-px -translate-x-full' : tooltipPosition == 'right' }" class="absolute inline-flex items-center justify-center overflow-hidden">
<div :class="{ 'origin-top-left -rotate-45' : tooltipPosition == 'top', 'origin-top-left rotate-45' : tooltipPosition == 'left', 'origin-bottom-left rotate-45' : tooltipPosition == 'bottom', 'origin-top-right -rotate-45' : tooltipPosition == 'right' }" class="w-1.5 h-1.5 transform bg-black bg-opacity-90"></div>
</div>
</div>
</div>
<div x-ref="content" class="px-3 py-1 text-xs rounded-full cursor-pointer text-neutral-500 bg-neutral-100">hover me</div>
</div>

View File

@ -0,0 +1,71 @@
<div
x-data="{
text: '',
textArray : ['Alpine JS is Amazing', 'It is Truly Awesome!', 'You Have to Try It!'],
textIndex: 0,
charIndex: 0,
pauseEnd: 1500,
cursorSpeed: 550,
pauseStart: 20,
typeSpeed: 110,
direction: 'forward',
}"
x-init="$nextTick(() => {
let typingInterval = setInterval(startTyping, $data.typeSpeed);
function startTyping(){
let current = $data.textArray[ $data.textIndex ];
// check to see if we hit the end of the string
if($data.charIndex > current.length){
$data.direction = 'backward';
clearInterval(typingInterval);
setTimeout(function(){
typingInterval = setInterval(startTyping, $data.typeSpeed);
}, $data.pauseEnd);
}
$data.text = current.substring(0, $data.charIndex);
if($data.direction == 'forward')
{
$data.charIndex += 1;
}
else
{
if($data.charIndex == 0)
{
$data.direction = 'forward';
clearInterval(typingInterval);
setTimeout(function(){
$data.textIndex += 1;
if($data.textIndex >= $data.textArray.length)
{
$data.textIndex = 0;
}
typingInterval = setInterval(startTyping, $data.typeSpeed);
}, $data.pauseStart);
}
$data.charIndex -= 1;
}
}
setInterval(function(){
if($refs.cursor.classList.contains('hidden'))
{
$refs.cursor.classList.remove('hidden');
}
else
{
$refs.cursor.classList.add('hidden');
}
}, $data.cursorSpeed);
})"
class="flex items-center justify-center mx-auto text-center max-w-7xl">
<div class="relative flex items-center justify-center h-auto">
<p class="text-2xl font-black leading-tight" x-text="text"></p>
<span class="absolute right-0 w-2 -mr-2 bg-black h-3/4" x-ref="cursor"></span>
</div>
</div>

View File

@ -0,0 +1,267 @@
<div x-data="{
player: null,
sources: {
mp4: 'https://cdn.devdojo.com/pines/videos/coast.mp4',
webm: 'https://cdn.devdojo.com/pines/videos/coast.webm',
ogg: 'https://cdn.devdojo.com/pines/videos/coast.ogg'
},
playing: false,
controls: true,
muted: false,
fullscreen: false,
ended: false,
mouseleave: false,
controlsHideTimeout: null,
autoHideControlsDelay: 3000,
previewImage: null,
poster: null,
videoDuration: 0,
timeDurationString: '00:00',
timeElapsedString: '00:00',
showTime: false,
volume: 1,
volumeBeforeMute: 1,
videoPlayerReady: false,
timelineSeek(e) {
time = this.formatTime(Math.round(e.target.value));
this.timeElapsedString = `${time.minutes}:${time.seconds}`;
},
metaDataLoaded(event) {
console.log(event.target.duration);
console.log('super!');
this.videoDuration = event.target.duration;
this.$refs.videoProgress.setAttribute('max', this.videoDuration);
time = this.formatTime(Math.round(this.videoDuration));
this.timeDurationString = `${time.minutes}:${time.seconds}`;
this.showTime = true;
this.videoPlayerReady = true;
},
togglePlay(e) {
if (this.$refs.player.paused || this.$refs.player.ended) {
this.playing = true;
this.$refs.player.play();
} else {
this.$refs.player.pause();
this.playing = false;
}
},
toggleMute(){
this.muted = !this.muted;
this.$refs.player.muted = this.muted;
if(this.muted){
this.volumeBeforeMute = this.volume;
this.volume = 0;
} else {
this.volume = this.volumeBeforeMute;
}
},
timeUpdatedInterval() {
if (!this.$refs.videoProgress.getAttribute('max'))
this.$refs.videoProgress.setAttribute('max', $refs.player.duration);
this.$refs.videoProgress.value = this.$refs.player.currentTime;
time = this.formatTime(Math.round(this.$refs.player.currentTime));
this.timeElapsedString = `${time.minutes}:${time.seconds}`;
},
updateVolume(e) {
this.volume = e.target.value;
this.$refs.player.volume = this.volume;
if(this.volume == 0){
this.muted = true;
}
if(this.muted && this.volume > 0){
this.muted = false;
}
},
timelineClicked(e) {
rect = this.$refs.videoProgress.getBoundingClientRect();
pos = (e.pageX - rect.left) / this.$refs.videoProgress.offsetWidth;
this.$refs.player.currentTime = pos * this.$refs.player.duration;
},
handleFullscreen() {
if (document.fullscreenElement !== null) {
// The document is in fullscreen mode
document.exitFullscreen();
} else {
// The document is not in fullscreen mode
this.$refs.videoContainer.requestFullscreen();
}
},
mousemoveVideo() {
if(this.playing){
this.resetControlsTimeout();
} else {
this.controls=true;
clearTimeout(this.controlsHideTimeout);
}
},
videoEnded() {
this.ended = true;
this.playing = false;
this.$refs.player.currentTime = 0;
},
resetControlsTimeout() {
this.controls = true;
clearTimeout(this.controlsHideTimeout);
let that = this;
this.controlsHideTimeout = setTimeout(function(){
that.controls=false
}, this.autoHideControlsDelay);
},
formatTime(timeInSeconds) {
result = new Date(timeInSeconds * 1000).toISOString().substr(11, 8);
return {
minutes: result.substr(3, 2),
seconds: result.substr(6, 2),
};
}
}"
x-init="
supportsVideo = document.createElement('video').canPlayType;
if (!supportsVideo) {
alert('This browser does not support the video element');
}
$refs.player.load();
// Hide the default player controls
$refs.player.controls = false;
$watch('playing', (value) => {
if (value) {
ended = false;
controlsHideTimeout = setTimeout(() => {
controls = false;
}, autoHideControlsDelay);
} else {
clearTimeout(controlsHideTimeout);
controls = true;
}
});
if (!document?.fullscreenEnabled) {
$refs.fullscreenButton.style.display = 'none';
}
document.addEventListener('fullscreenchange', (e) => {
fullscreen = !!document.fullscreenElement;
});
"
x-ref="videoContainer"
@mouseleave="mouseleave=true"
@mousemove="mousemoveVideo"
class="relative h-[360px] overflow-hidden rounded-md aspect-video">
<video
x-ref="player"
@loadedmetadata="metaDataLoaded"
@timeupdate="timeUpdatedInterval"
@ended="videoEnded"
preload="metadata"
:poster="poster"
class="relative z-10 object-cover w-full h-full bg-black"
crossorigin="anonymous"
>
<source :src="sources.mp4" type="video/mp4" />
<source :src="sources.webm" type="video/webm" />
<source :src="sources.ogg" type="video/ogg" />
</video>
<div x-show="videoPlayerReady" class="absolute inset-0 w-full h-full">
<div x-ref="videoBackground" @click="togglePlay()" class="absolute inset-0 z-30 flex items-center justify-center w-full h-full bg-black bg-opacity-0">
<div
x-show="playing"
x-transition:enter="transition ease-out duration-1000"
x-transition:enter-start="scale-50 opacity-100"
x-transition:enter-end="scale-100 opacity-0"
class="flex items-center justify-center w-20 h-20 bg-black rounded-full opacity-0 bg-opacity-20"
x-cloak>
<svg class="w-10 h-10 translate-x-0.5 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.42737 3.41611C6.46665 2.24586 4.00008 3.67188 4.00007 5.9427L4 18.0572C3.99999 20.329 6.46837 21.7549 8.42907 20.5828L18.5698 14.5207C20.4775 13.3802 20.4766 10.6076 18.568 9.46853L8.42737 3.41611Z" fill="currentColor"></path></svg>
</div>
<div
x-show="!playing && !ended"
x-transition:enter="transition ease-out duration-1000"
x-transition:enter-start="scale-50 opacity-100"
x-transition:enter-end="scale-100 opacity-0"
class="flex items-center justify-center w-20 h-20 bg-black rounded-full opacity-0 bg-opacity-20"
x-cloak>
<svg class="w-10 h-10 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C8.55228 3 9 3.44772 9 4L9 20C9 20.5523 8.55228 21 8 21C7.44772 21 7 20.5523 7 20L7 4C7 3.44772 7.44772 3 8 3ZM16 3C16.5523 3 17 3.44772 17 4V20C17 20.5523 16.5523 21 16 21C15.4477 21 15 20.5523 15 20V4C15 3.44772 15.4477 3 16 3Z" fill="currentColor"></path></svg>
</div>
</div>
<div x-show="controls"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="absolute bottom-0 left-0 z-20 w-full h-1/2 opacity-20 bg-gradient-to-b from-transparent to-black" x-cloak>
</div>
<div x-show="controls"
@click="resetControlsTimeout"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="absolute bottom-0 left-0 z-40 w-full h-12" x-cloak>
<div class="absolute bottom-0 z-30 w-full px-2.5 -translate-y-10">
<div class="relative w-full h-2 rounded-full">
<input
x-ref="videoProgress"
@click="timelineClicked"
@input="timelineSeek(event)"
type="range" min="0" max="100" value="0" step="any"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-2.5 [&::-webkit-slider-thumb]:h-2.5 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-2.5 [&::-moz-range-thumb]:h-2.5 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-white [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-2.5 [&::-ms-thumb]:h-2.5 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-white [&::-webkit-slider-runnable-track]:bg-opacity-30 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-blue-500 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-blue-500 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-995px_0px_0px_990px_#036aff]
">
</div>
</div>
<ul class="absolute bottom-0 left-0 z-20 flex items-center w-full text-white">
<li class="inline">
<button @click="togglePlay()" class="flex items-center justify-center w-10 h-10 duration-150 ease-out opacity-80 hover:opacity-100" type="button">
<svg x-show="!playing" class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.42737 3.41611C6.46665 2.24586 4.00008 3.67188 4.00007 5.9427L4 18.0572C3.99999 20.329 6.46837 21.7549 8.42907 20.5828L18.5698 14.5207C20.4775 13.3802 20.4766 10.6076 18.568 9.46853L8.42737 3.41611Z" fill="currentColor" x-cloak></path></svg>
<svg x-show="playing" class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C8.55228 3 9 3.44772 9 4L9 20C9 20.5523 8.55228 21 8 21C7.44772 21 7 20.5523 7 20L7 4C7 3.44772 7.44772 3 8 3ZM16 3C16.5523 3 17 3.44772 17 4V20C17 20.5523 16.5523 21 16 21C15.4477 21 15 20.5523 15 20V4C15 3.44772 15.4477 3 16 3Z" fill="currentColor" x-cloak></path></svg>
</button>
</li>
<li class="flex items-center">
<button @click="toggleMute()" type="button" class="flex items-center justify-center w-6 h-10 duration-150 ease-out opacity-80 hover:opacity-100">
<svg x-show="!muted" class="w-[18px] h-[18px]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" x-cloak><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 001.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06zM18.584 5.106a.75.75 0 011.06 0c3.808 3.807 3.808 9.98 0 13.788a.75.75 0 11-1.06-1.06 8.25 8.25 0 000-11.668.75.75 0 010-1.06z" /><path d="M15.932 7.757a.75.75 0 011.061 0 6 6 0 010 8.486.75.75 0 01-1.06-1.061 4.5 4.5 0 000-6.364.75.75 0 010-1.06z" /></svg>
<svg x-show="muted" class="w-[18px] h-[18px]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" x-cloak><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 001.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06zM17.78 9.22a.75.75 0 10-1.06 1.06L18.44 12l-1.72 1.72a.75.75 0 001.06 1.06l1.72-1.72 1.72 1.72a.75.75 0 101.06-1.06L20.56 12l1.72-1.72a.75.75 0 00-1.06-1.06l-1.72 1.72-1.72-1.72z" /></svg>
</button>
<div class="relative h-1.5 w-12 mx-1 rounded-full">
<input
x-ref="volume"
@input="updateVolume(event)"
type="range" min="0" max="1" :value="volume" step="0.01"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-2 [&::-webkit-slider-thumb]:h-2 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-2 [&::-moz-range-thumb]:h-2 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-white [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-2 [&::-ms-thumb]:h-2 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-white [&::-webkit-slider-runnable-track]:bg-opacity-30 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-white [&::-moz-range-progress]:bg-opacity-80 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-white [&::-ms-fill-lower]:bg-opacity-80 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-995px_0px_0px_990px_rgba(255,_255,_255,_0.8)]
">
</div>
</li>
<li x-show="showTime" class="mx-2.5 font-mono text-xs opacity-80 hover:opacity-100" x-cloak>
<time x-ref="timeElapsed" x-text="timeElapsedString">00:00</time>
<span> / </span>
<time x-ref="timeDuration" x-text="timeDurationString">00:00</time>
</li>
<li class="ml-auto">
<button x-ref="fullscreenButton" @click="handleFullscreen" class="flex items-center justify-center w-10 h-10 duration-150 ease-out scale-90 opacity-80 hover:opacity-100 hover:scale-100" type="button">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6.72685 5C5.77328 5 5 5.77318 5 6.72727V9C5 9.55228 4.55228 10 4 10C3.44772 10 3 9.55228 3 9V6.72727C3 4.6689 4.66842 3 6.72685 3H9C9.55228 3 10 3.44772 10 4C10 4.55228 9.55228 5 9 5H6.72685ZM14 4C14 3.44772 14.4477 3 15 3H17.2727C19.3312 3 21 4.66876 21 6.72727V9C21 9.55228 20.5523 10 20 10C19.4477 10 19 9.55228 19 9V6.72727C19 5.77333 18.2267 5 17.2727 5H15C14.4477 5 14 4.55228 14 4ZM4 14C4.55228 14 5 14.4477 5 15V17.2727C5 18.2268 5.77328 19 6.72685 19H9C9.55228 19 10 19.4477 10 20C10 20.5523 9.55228 21 9 21H6.72685C4.66842 21 3 19.3311 3 17.2727V15C3 14.4477 3.44772 14 4 14ZM20 14C20.5523 14 21 14.4477 21 15V17.2727C21 19.3312 19.3312 21 17.2727 21H15C14.4477 21 14 20.5523 14 20C14 19.4477 14.4477 19 15 19H17.2727C18.2267 19 19 18.2267 19 17.2727V15C19 14.4477 19.4477 14 20 14Z" fill="currentColor"></path></svg>
</button>
</li>
</ul>
</div>
</div>
</div>

View File

@ -0,0 +1,267 @@
<div x-data="{
player: null,
sources: {
mp4: 'https://cdn.devdojo.com/pines/videos/coast.mp4',
webm: 'https://cdn.devdojo.com/pines/videos/coast.webm',
ogg: 'https://cdn.devdojo.com/pines/videos/coast.ogg'
},
playing: false,
controls: true,
muted: false,
fullscreen: false,
ended: false,
mouseleave: false,
controlsHideTimeout: null,
autoHideControlsDelay: 3000,
previewImage: null,
poster: null,
videoDuration: 0,
timeDurationString: '00:00',
timeElapsedString: '00:00',
showTime: false,
volume: 1,
volumeBeforeMute: 1,
videoPlayerReady: false,
videoPlayerReady: false,
timelineSeek(e) {
time = this.formatTime(Math.round(e.target.value));
this.timeElapsedString = `${time.minutes}:${time.seconds}`;
},
metaDataLoaded(event) {
console.log(event.target.duration);
console.log('super!');
this.videoDuration = event.target.duration;
this.$refs.videoProgress.setAttribute('max', this.videoDuration);
time = this.formatTime(Math.round(this.videoDuration));
this.timeDurationString = `${time.minutes}:${time.seconds}`;
this.showTime = true;
this.videoPlayerReady = true;
},
togglePlay(e) {
if (this.$refs.player.paused || this.$refs.player.ended) {
this.playing = true;
this.$refs.player.play();
} else {
this.$refs.player.pause();
this.playing = false;
}
},
toggleMute(){
this.muted = !this.muted;
this.$refs.player.muted = this.muted;
if(this.muted){
this.volumeBeforeMute = this.volume;
this.volume = 0;
} else {
this.volume = this.volumeBeforeMute;
}
},
timeUpdatedInterval() {
if (!this.$refs.videoProgress.getAttribute('max'))
this.$refs.videoProgress.setAttribute('max', $refs.player.duration);
this.$refs.videoProgress.value = this.$refs.player.currentTime;
time = this.formatTime(Math.round(this.$refs.player.currentTime));
this.timeElapsedString = `${time.minutes}:${time.seconds}`;
},
updateVolume(e) {
this.volume = e.target.value;
this.$refs.player.volume = this.volume;
if(this.volume == 0){
this.muted = true;
}
if(this.muted && this.volume > 0){
this.muted = false;
}
},
timelineClicked(e) {
rect = this.$refs.videoProgress.getBoundingClientRect();
pos = (e.pageX - rect.left) / this.$refs.videoProgress.offsetWidth;
this.$refs.player.currentTime = pos * this.$refs.player.duration;
},
handleFullscreen() {
if (document.fullscreenElement !== null) {
// The document is in fullscreen mode
document.exitFullscreen();
} else {
// The document is not in fullscreen mode
this.$refs.videoContainer.requestFullscreen();
}
},
mousemoveVideo() {
if(this.playing){
this.resetControlsTimeout();
} else {
this.controls=true;
clearTimeout(this.controlsHideTimeout);
}
},
videoEnded() {
this.ended = true;
this.playing = false;
this.$refs.player.currentTime = 0;
},
resetControlsTimeout() {
this.controls = true;
clearTimeout(this.controlsHideTimeout);
let that = this;
this.controlsHideTimeout = setTimeout(function(){
that.controls=false
}, this.autoHideControlsDelay);
},
formatTime(timeInSeconds) {
result = new Date(timeInSeconds * 1000).toISOString().substr(11, 8);
return {
minutes: result.substr(3, 2),
seconds: result.substr(6, 2),
};
}
}"
x-init="
supportsVideo = document.createElement('video').canPlayType;
if (!supportsVideo) {
alert('This browser does not support the video element');
}
$refs.player.load();
// Hide the default player controls
$refs.player.controls = false;
$watch('playing', (value) => {
if (value) {
ended = false;
controlsHideTimeout = setTimeout(() => {
controls = false;
}, autoHideControlsDelay);
} else {
clearTimeout(controlsHideTimeout);
controls = true;
}
});
if (!document?.fullscreenEnabled) {
$refs.fullscreenButton.style.display = 'none';
}
document.addEventListener('fullscreenchange', (e) => {
fullscreen = !!document.fullscreenElement;
});
"
x-ref="videoContainer"
@mouseleave="mouseleave=true"
@mousemove="mousemoveVideo"
class="relative h-[360px] overflow-hidden rounded-md aspect-video" x-cloak>
<video
x-ref="player"
@loadedmetadata="metaDataLoaded"
@timeupdate="timeUpdatedInterval"
@ended="videoEnded"
preload="metadata"
:poster=""
class="relative z-10 object-cover w-full h-full bg-black"
crossorigin="anonymous"
>
<source :src="sources.mp4" type="video/mp4" />
<source :src="sources.webm" type="video/webm" />
<source :src="sources.ogg" type="video/ogg" />
</video>
<div x-show="videoPlayerReady" class="absolute inset-0 w-full h-full">
<div x-ref="videoBackground" @click="togglePlay()" class="absolute inset-0 z-30 flex items-center justify-center w-full h-full bg-black bg-opacity-0">
<div
x-show="playing"
x-transition:enter="transition ease-out duration-1000"
x-transition:enter-start="scale-50 opacity-100"
x-transition:enter-end="scale-100 opacity-0"
class="flex items-center justify-center w-20 h-20 bg-black rounded-full opacity-0 bg-opacity-20"
x-cloak>
<svg class="w-10 h-10 translate-x-0.5 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.42737 3.41611C6.46665 2.24586 4.00008 3.67188 4.00007 5.9427L4 18.0572C3.99999 20.329 6.46837 21.7549 8.42907 20.5828L18.5698 14.5207C20.4775 13.3802 20.4766 10.6076 18.568 9.46853L8.42737 3.41611Z" fill="currentColor"></path></svg>
</div>
<div
x-show="!playing && !ended"
x-transition:enter="transition ease-out duration-1000"
x-transition:enter-start="scale-50 opacity-100"
x-transition:enter-end="scale-100 opacity-0"
class="flex items-center justify-center w-20 h-20 bg-black rounded-full opacity-0 bg-opacity-20"
x-cloak>
<svg class="w-10 h-10 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C8.55228 3 9 3.44772 9 4L9 20C9 20.5523 8.55228 21 8 21C7.44772 21 7 20.5523 7 20L7 4C7 3.44772 7.44772 3 8 3ZM16 3C16.5523 3 17 3.44772 17 4V20C17 20.5523 16.5523 21 16 21C15.4477 21 15 20.5523 15 20V4C15 3.44772 15.4477 3 16 3Z" fill="currentColor"></path></svg>
</div>
</div>
<div x-show="controls"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="absolute bottom-0 left-0 z-20 w-full h-1/2 opacity-20 bg-gradient-to-b from-transparent to-black" x-cloak>
</div>
<div x-show="controls"
@click="resetControlsTimeout"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="absolute bottom-0 left-0 z-40 w-full h-12" x-cloak>
<ul class="absolute bottom-0 left-0 z-20 flex items-center w-full text-white">
<li class="inline">
<button @click="togglePlay()" class="flex items-center justify-center w-10 h-10 duration-150 ease-out opacity-80 hover:opacity-100" type="button">
<svg x-show="!playing" class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.42737 3.41611C6.46665 2.24586 4.00008 3.67188 4.00007 5.9427L4 18.0572C3.99999 20.329 6.46837 21.7549 8.42907 20.5828L18.5698 14.5207C20.4775 13.3802 20.4766 10.6076 18.568 9.46853L8.42737 3.41611Z" fill="currentColor" x-cloak></path></svg>
<svg x-show="playing" class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C8.55228 3 9 3.44772 9 4L9 20C9 20.5523 8.55228 21 8 21C7.44772 21 7 20.5523 7 20L7 4C7 3.44772 7.44772 3 8 3ZM16 3C16.5523 3 17 3.44772 17 4V20C17 20.5523 16.5523 21 16 21C15.4477 21 15 20.5523 15 20V4C15 3.44772 15.4477 3 16 3Z" fill="currentColor" x-cloak></path></svg>
</button>
</li>
<li class="w-full">
<div class="relative w-full h-2 rounded-full">
<input
x-ref="videoProgress"
@click="timelineClicked"
@input="timelineSeek(event)"
type="range" min="0" max="100" value="0" step="any"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-2.5 [&::-webkit-slider-thumb]:h-2.5 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-2.5 [&::-moz-range-thumb]:h-2.5 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-white [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-2.5 [&::-ms-thumb]:h-2.5 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-white [&::-webkit-slider-runnable-track]:bg-opacity-30 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-gray-900 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-gray-900 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-995px_0px_0px_990px_#101827]
">
</div>
</li>
<li x-show="showTime" class="mx-2.5 flex-shrink-0 font-mono text-xs opacity-80 hover:opacity-100">
<time x-ref="timeElapsed" x-text="timeElapsedString">00:00</time>
<span> / </span>
<time x-ref="timeDuration" x-text="timeDurationString">00:00</time>
</li>
<li class="flex items-center group">
<button @click="toggleMute()" type="button" class="flex items-center justify-center w-6 h-10 duration-150 ease-out opacity-80 hover:opacity-100">
<svg x-show="!muted" class="w-[18px] h-[18px]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" x-cloak><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 001.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06zM18.584 5.106a.75.75 0 011.06 0c3.808 3.807 3.808 9.98 0 13.788a.75.75 0 11-1.06-1.06 8.25 8.25 0 000-11.668.75.75 0 010-1.06z" /><path d="M15.932 7.757a.75.75 0 011.061 0 6 6 0 010 8.486.75.75 0 01-1.06-1.061 4.5 4.5 0 000-6.364.75.75 0 010-1.06z" /></svg>
<svg x-show="muted" class="w-[18px] h-[18px]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" x-cloak><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 001.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06zM17.78 9.22a.75.75 0 10-1.06 1.06L18.44 12l-1.72 1.72a.75.75 0 001.06 1.06l1.72-1.72 1.72 1.72a.75.75 0 101.06-1.06L20.56 12l1.72-1.72a.75.75 0 00-1.06-1.06l-1.72 1.72-1.72-1.72z" /></svg>
</button>
<div class="relative h-1.5 w-0 mx-0 group-hover:mx-1 rounded-full group-hover:w-12 invisible group-hover:visible w-0 ease-out duration-300">
<input
x-ref="volume"
@input="updateVolume(event)"
type="range" min="0" max="1" :value="volume" step="0.01"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-2 [&::-webkit-slider-thumb]:h-2 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-2 [&::-moz-range-thumb]:h-2 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-white [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-2 [&::-ms-thumb]:h-2 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-white [&::-webkit-slider-runnable-track]:bg-opacity-30 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-white [&::-moz-range-progress]:bg-opacity-80 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-white [&::-ms-fill-lower]:bg-opacity-80 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-995px_0px_0px_990px_rgba(255,_255,_255,_0.8)]
">
</div>
</li>
<li class="ml-auto">
<button x-ref="fullscreenButton" @click="handleFullscreen" class="flex items-center justify-center w-10 h-10 duration-150 ease-out scale-90 opacity-80 hover:opacity-100 hover:scale-100" type="button">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6.72685 5C5.77328 5 5 5.77318 5 6.72727V9C5 9.55228 4.55228 10 4 10C3.44772 10 3 9.55228 3 9V6.72727C3 4.6689 4.66842 3 6.72685 3H9C9.55228 3 10 3.44772 10 4C10 4.55228 9.55228 5 9 5H6.72685ZM14 4C14 3.44772 14.4477 3 15 3H17.2727C19.3312 3 21 4.66876 21 6.72727V9C21 9.55228 20.5523 10 20 10C19.4477 10 19 9.55228 19 9V6.72727C19 5.77333 18.2267 5 17.2727 5H15C14.4477 5 14 4.55228 14 4ZM4 14C4.55228 14 5 14.4477 5 15V17.2727C5 18.2268 5.77328 19 6.72685 19H9C9.55228 19 10 19.4477 10 20C10 20.5523 9.55228 21 9 21H6.72685C4.66842 21 3 19.3311 3 17.2727V15C3 14.4477 3.44772 14 4 14ZM20 14C20.5523 14 21 14.4477 21 15V17.2727C21 19.3312 19.3312 21 17.2727 21H15C14.4477 21 14 20.5523 14 20C14 19.4477 14.4477 19 15 19H17.2727C18.2267 19 19 18.2267 19 17.2727V15C19 14.4477 19.4477 14 20 14Z" fill="currentColor"></path></svg>
</button>
</li>
</ul>
</div>
</div>
</div>

293
elements/video.html Normal file
View File

@ -0,0 +1,293 @@
<div x-data="{
player: null,
sources: {
mp4: 'https://cdn.devdojo.com/pines/videos/coast.mp4',
webm: 'https://cdn.devdojo.com/pines/videos/coast.webm',
ogg: 'https://cdn.devdojo.com/pines/videos/coast.ogg'
},
playing: false,
controls: true,
muted: false,
muteForced: false,
fullscreen: false,
ended: false,
mouseleave: false,
controlsHideTimeout: null,
autoHideControlsDelay: 3000,
previewImage: null,
poster: null,
videoDuration: 0,
timeDurationString: '00:00',
timeElapsedString: '00:00',
showTime: false,
volume: 1,
volumeBeforeMute: 1,
videoPlayerReady: false,
timelineSeek(e) {
time = this.formatTime(Math.round(e.target.value));
this.timeElapsedString = `${time.minutes}:${time.seconds}`;
},
metaDataLoaded(event) {
console.log(event.target.duration);
console.log('super!');
this.videoDuration = event.target.duration;
this.$refs.videoProgress.setAttribute('max', this.videoDuration);
time = this.formatTime(Math.round(this.videoDuration));
this.timeDurationString = `${time.minutes}:${time.seconds}`;
this.showTime = true;
this.videoPlayerReady = true;
},
togglePlay(e) {
if (this.$refs.player.paused || this.$refs.player.ended) {
this.playing = true;
this.$refs.player.play();
} else {
this.$refs.player.pause();
this.playing = false;
}
},
toggleMute(){
this.muted = !this.muted;
this.$refs.player.muted = this.muted;
if(this.muted){
this.volumeBeforeMute = this.volume;
this.volume = 0;
} else {
this.volume = this.volumeBeforeMute;
}
},
timeUpdatedInterval() {
if (!this.$refs.videoProgress.getAttribute('max'))
this.$refs.videoProgress.setAttribute('max', $refs.player.duration);
this.$refs.videoProgress.value = this.$refs.player.currentTime;
time = this.formatTime(Math.round(this.$refs.player.currentTime));
this.timeElapsedString = `${time.minutes}:${time.seconds}`;
},
updateVolume(e) {
this.volume = e.target.value;
this.$refs.player.volume = this.volume;
if(this.volume == 0){
this.muted = true;
}
if(this.muted && this.volume > 0){
this.muted = false;
}
},
timelineClicked(e) {
rect = this.$refs.videoProgress.getBoundingClientRect();
pos = (e.pageX - rect.left) / this.$refs.videoProgress.offsetWidth;
this.$refs.player.currentTime = pos * this.$refs.player.duration;
},
handleFullscreen() {
if (document.fullscreenElement !== null) {
// The document is in fullscreen mode
document.exitFullscreen();
} else {
// The document is not in fullscreen mode
this.$refs.videoContainer.requestFullscreen();
}
},
mousemoveVideo() {
if(this.playing){
this.resetControlsTimeout();
} else {
this.controls=true;
clearTimeout(this.controlsHideTimeout);
}
},
videoEnded() {
this.ended = true;
this.playing = false;
this.$refs.player.currentTime = 0;
},
resetControlsTimeout() {
this.controls = true;
clearTimeout(this.controlsHideTimeout);
let that = this;
this.controlsHideTimeout = setTimeout(function(){
that.controls=false
}, this.autoHideControlsDelay);
},
formatTime(timeInSeconds) {
result = new Date(timeInSeconds * 1000).toISOString().substr(11, 8);
return {
minutes: result.substr(3, 2),
seconds: result.substr(6, 2),
};
}
}"
x-init="
supportsVideo = document.createElement('video').canPlayType;
if (!supportsVideo) {
alert('This browser does not support the video element');
}
$refs.player.load();
// Hide the default player controls
$refs.player.controls = false;
$watch('playing', (value) => {
if (value) {
ended = false;
controlsHideTimeout = setTimeout(() => {
controls = false;
}, autoHideControlsDelay);
} else {
clearTimeout(controlsHideTimeout);
controls = true;
}
});
if (!document?.fullscreenEnabled) {
$refs.fullscreenButton.style.display = 'none';
}
document.addEventListener('fullscreenchange', (e) => {
fullscreen = !!document.fullscreenElement;
});
"
x-ref="videoContainer"
@mouseleave="mouseleave=true"
@mousemove="mousemoveVideo"
class="relative h-[360px] overflow-hidden rounded-md aspect-video">
<video
x-ref="player"
@loadedmetadata="metaDataLoaded"
@timeupdate="timeUpdatedInterval"
@ended="videoEnded"
preload="metadata"
:poster="poster"
class="relative z-10 object-cover w-full h-full bg-black"
crossorigin="anonymous"
>
<source :src="sources.mp4" type="video/mp4" />
<source :src="sources.webm" type="video/webm" />
<source :src="sources.ogg" type="video/ogg" />
</video>
<div x-show="videoPlayerReady" class="absolute inset-0 w-full h-full">
<div x-ref="videoBackground" @click="togglePlay()" class="absolute inset-0 z-30 flex items-center justify-center w-full h-full bg-black bg-opacity-0 cursor-pointer group">
<div
x-show="playing"
x-transition:enter="transition ease-out duration-1000"
x-transition:enter-start="scale-50 opacity-100"
x-transition:enter-end="scale-100 opacity-0"
class="absolute z-20 flex items-center justify-center w-24 h-24 bg-blue-600 rounded-full opacity-0 bg-opacity-20"
x-cloak>
<svg class="w-10 h-10 translate-x-0.5 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.42737 3.41611C6.46665 2.24586 4.00008 3.67188 4.00007 5.9427L4 18.0572C3.99999 20.329 6.46837 21.7549 8.42907 20.5828L18.5698 14.5207C20.4775 13.3802 20.4766 10.6076 18.568 9.46853L8.42737 3.41611Z" fill="currentColor"></path></svg>
</div>
<div
x-show="!playing && !ended"
x-transition:enter="transition ease-out duration-1000"
x-transition:enter-start="scale-50 opacity-100"
x-transition:enter-end="scale-100 opacity-0"
class="absolute z-20 flex items-center justify-center w-24 h-24 bg-blue-600 rounded-full opacity-0 bg-opacity-20"
x-cloak>
<svg class="w-10 h-10 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 3C8.55228 3 9 3.44772 9 4L9 20C9 20.5523 8.55228 21 8 21C7.44772 21 7 20.5523 7 20L7 4C7 3.44772 7.44772 3 8 3ZM16 3C16.5523 3 17 3.44772 17 4V20C17 20.5523 16.5523 21 16 21C15.4477 21 15 20.5523 15 20V4C15 3.44772 15.4477 3 16 3Z" fill="currentColor"></path></svg>
</div>
<div class="absolute z-10 duration-300 ease-out group-hover:scale-110">
<button
x-show="!playing"
x-transition:enter="transition ease-in delay-200 duration-300"
x-transition:enter-start="opacity-0 scale-75"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-out duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="flex items-center justify-center w-12 h-12 text-white duration-150 ease-out bg-blue-600 rounded-full cursor-pointer bg-opacity-80" type="button">
<svg class="w-5 h-5 translate-x-px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.42737 3.41611C6.46665 2.24586 4.00008 3.67188 4.00007 5.9427L4 18.0572C3.99999 20.329 6.46837 21.7549 8.42907 20.5828L18.5698 14.5207C20.4775 13.3802 20.4766 10.6076 18.568 9.46853L8.42737 3.41611Z" fill="currentColor" x-cloak></path></svg>
</button>
</div>
</div>
<div x-show="controls"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="-translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="-translate-y-full"
class="absolute top-0 left-0 z-20 w-full h-1/4 opacity-20 bg-gradient-to-b from-black to-transparent" x-cloak>
</div>
<div x-show="controls"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="absolute bottom-0 left-0 z-20 w-full h-1/4 opacity-20 bg-gradient-to-b from-transparent to-black" x-cloak>
</div>
<div x-show="controls"
@click="resetControlsTimeout"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="-translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="-translate-y-full"
class="absolute top-0 left-0 z-40 flex items-center w-full h-12 text-white" x-cloak>
<div class="absolute right-0 top-0 mr-0.5 mt-0.5 flex items-center">
<div class="flex items-center h-auto group">
<button @click="toggleMute()" type="button" class="flex items-center justify-center w-6 h-auto duration-150 ease-out opacity-80 hover:opacity-100">
<svg x-show="!muted" class="w-[18px] h-[18px]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" x-cloak><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 001.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06zM18.584 5.106a.75.75 0 011.06 0c3.808 3.807 3.808 9.98 0 13.788a.75.75 0 11-1.06-1.06 8.25 8.25 0 000-11.668.75.75 0 010-1.06z" /><path d="M15.932 7.757a.75.75 0 011.061 0 6 6 0 010 8.486.75.75 0 01-1.06-1.061 4.5 4.5 0 000-6.364.75.75 0 010-1.06z" /></svg>
<svg x-show="muted" class="w-[18px] h-[18px]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" x-cloak><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 001.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06zM17.78 9.22a.75.75 0 10-1.06 1.06L18.44 12l-1.72 1.72a.75.75 0 001.06 1.06l1.72-1.72 1.72 1.72a.75.75 0 101.06-1.06L20.56 12l1.72-1.72a.75.75 0 00-1.06-1.06l-1.72 1.72-1.72-1.72z" /></svg>
</button>
<div class="relative h-1.5 w-0 mx-0 group-hover:mx-1 rounded-full group-hover:w-12 invisible group-hover:visible w-0 ease-out duration-300">
<input
x-ref="volume"
@input="updateVolume(event)"
type="range" min="0" max="1" :value="volume" step="0.01"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-2 [&::-webkit-slider-thumb]:h-2 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-2 [&::-moz-range-thumb]:h-2 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-white [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-2 [&::-ms-thumb]:h-2 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-white [&::-webkit-slider-runnable-track]:bg-opacity-30 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-white [&::-moz-range-progress]:bg-opacity-80 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-white [&::-ms-fill-lower]:bg-opacity-80 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-995px_0px_0px_990px_rgba(255,_255,_255,_0.8)]
">
</div>
</div>
<button x-ref="fullscreenButton" @click="handleFullscreen" class="flex items-center justify-center w-10 h-10 duration-150 ease-out scale-90 opacity-80 hover:opacity-100 hover:scale-100" type="button">
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6.72685 5C5.77328 5 5 5.77318 5 6.72727V9C5 9.55228 4.55228 10 4 10C3.44772 10 3 9.55228 3 9V6.72727C3 4.6689 4.66842 3 6.72685 3H9C9.55228 3 10 3.44772 10 4C10 4.55228 9.55228 5 9 5H6.72685ZM14 4C14 3.44772 14.4477 3 15 3H17.2727C19.3312 3 21 4.66876 21 6.72727V9C21 9.55228 20.5523 10 20 10C19.4477 10 19 9.55228 19 9V6.72727C19 5.77333 18.2267 5 17.2727 5H15C14.4477 5 14 4.55228 14 4ZM4 14C4.55228 14 5 14.4477 5 15V17.2727C5 18.2268 5.77328 19 6.72685 19H9C9.55228 19 10 19.4477 10 20C10 20.5523 9.55228 21 9 21H6.72685C4.66842 21 3 19.3311 3 17.2727V15C3 14.4477 3.44772 14 4 14ZM20 14C20.5523 14 21 14.4477 21 15V17.2727C21 19.3312 19.3312 21 17.2727 21H15C14.4477 21 14 20.5523 14 20C14 19.4477 14.4477 19 15 19H17.2727C18.2267 19 19 18.2267 19 17.2727V15C19 14.4477 19.4477 14 20 14Z" fill="currentColor"></path></svg>
</button>
</div>
</div>
<div x-show="controls"
@click="resetControlsTimeout"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
class="absolute bottom-0 left-0 z-40 w-full h-12" x-cloak>
<div class="absolute bottom-0 z-30 w-full px-2.5 -translate-y-8">
<div class="relative w-full h-1 rounded-full">
<input
x-ref="videoProgress"
@click="timelineClicked"
@input="timelineSeek(event)"
type="range" min="0" max="100" value="0" step="any"
class="w-full h-full appearance-none flex items-center cursor-pointer bg-transparent z-30
[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-0 [&::-webkit-slider-thumb]:w-1.5 [&::-webkit-slider-thumb]:h-1.5 [&::-webkit-slider-thumb]:appearance-none
[&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:w-1.5 [&::-moz-range-thumb]:h-1.5 [&::-moz-range-thumb]:appearance-none
[&::-ms-thumb]:bg-white [&::-ms-thumb]:rounded-full [&::-ms-thumb]:border-0 [&::-ms-thumb]:w-1.5 [&::-ms-thumb]:h-1.5 [&::-ms-thumb]:appearance-none
[&::-webkit-slider-runnable-track]:bg-white [&::-webkit-slider-runnable-track]:bg-opacity-30 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:overflow-hidden [&::-moz-range-track]:bg-neutral-200 [&::-moz-range-track]:rounded-full [&::-ms-track]:bg-neutral-200 [&::-ms-track]:rounded-full
[&::-moz-range-progress]:bg-blue-600 [&::-moz-range-progress]:rounded-full [&::-ms-fill-lower]:bg-blue-600 [&::-ms-fill-lower]:rounded-full [&::-webkit-slider-thumb]:shadow-[-995px_0px_0px_990px_#2463eb]
">
</div>
</div>
<div class="absolute bottom-0 left-0 z-20 flex items-center w-full h-8 text-white">
<div x-show="showTime" class="flex items-center justify-between w-full mx-3 font-mono text-xs opacity-80 hover:opacity-100" x-cloak>
<time x-ref="timeElapsed" x-text="timeElapsedString">00:00</time>
<time x-ref="timeDuration" x-text="timeDurationString">00:00</time>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,31 @@
<div class="not-prose">
<h2 class="pt-0 mb-2 text-3xl font-bold tracking-tight select-none not-prose custom-font">Contribution</h2>
</div>
<p class="text-gray-500">You may contribute to this project by visiting the Github Repo here. We currently do not have issues open, so you'll need to submit a PR with you contribution and we'll get to the PR as soon as we can.</p>
<p class="text-gray-500">If you wish to discuss functionality or any issues you have with Pines, you can visit the DevDojo Discussions/Questions section.</p>
<div class="relative w-full rounded-lg border border-transparent p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 bg-yellow-500 text-white">
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z" clip-rule="evenodd" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Star the Repo</h5>
<div class="text-sm [&;_p]:leading-relaxed">If you want to see this project grow, it would help us out if you <a href="https://github.com/thedevdojo/pines" target="_blank" class="font-medium text-white">starred the repo</a> and shared it with your friends.</div>
</div>
<p class="text-gray-500">Thanks for all your suppor with this project and we look forward to hearing your feedback.</p>
<hr>
<h3>Local Installation</h3>
<p class="text-gray-500">Visit the main repo for the <a href="https://github.com/thedevdojo/pines" target="_blank">Pines UI Library</a>. This repo is simple to setup and get running on your local if you wish to submit a fix or make some additions to the library.</p>
<ol>
<li>Download the contents of the Github repo and store it in a folder.</li>
<li>Make sure you have <a href="https://nodejs.org/" target="_blank">NodeJS</a> installed along with the <a href="https://www.npmjs.com/package/http-server" target="_blank">http-server</a> package.</li>
<li>CD into your folder and run `http-serve`</li>
<li>Visit the localhost URL to see PinesUI</li>
</ol>
<p class="text-gray-500">The installation instructions are also available via the github repo at <a href="https://github.com/thedevdojo/pines" target="_blank">https://github.com/thedevdojo/pines</a></p>

View File

@ -0,0 +1,36 @@
<div class="not-prose">
<h2 class="pt-0 mb-2 text-3xl font-bold tracking-tight select-none not-prose custom-font">How To Use</h2>
</div>
<p class="text-gray-500">Pines, is super easy to use. If your application uses AlpineJS and TailwindCSS, you can copy and paste an element into your page an it will work flawlessly. If you want to test an element on a single HTML page, you can copy/paste this snippet below into any `.html` file:</p>
<pre class="block w-full overflow-scroll text-sm border rounded-md hljs html border-neutral-200"><code class="hljs html">&#x3C;!DOCTYPE html&#x3E;
&#x3C;html lang=&#x22;en&#x22;&#x3E;
&#x3C;head&#x3E;
&#x3C;meta charset=&#x22;UTF-8&#x22;&#x3E;
&#x3C;meta http-equiv=&#x22;X-UA-Compatible&#x22; content=&#x22;IE=edge&#x22;&#x3E;
&#x3C;meta name=&#x22;viewport&#x22; content=&#x22;width=device-width, initial-scale=1.0&#x22;&#x3E;
&#x3C;title&#x3E;Pines UI&#x3C;/title&#x3E;
&#x3C;style&#x3E;[x-cloak]{display:none}&#x3C;/style&#x3E;
&#x3C;!-- Include the Alpine library on your page --&#x3E;
&#x3C;script src=&#x22;//unpkg.com/alpinejs&#x22; defer&#x3E;&#x3C;/script&#x3E;
&#x3C;!-- Include the TailwindCSS library on your page --&#x3E;
&#x3C;script src=&#x22;https://cdn.tailwindcss.com&#x22;&#x3E;&#x3C;/script&#x3E;
&#x3C;/head&#x3E;
&#x3C;body class=&#x22;flex items-start justify-center h-full bg-gray-50&#x22; style=&#x22;display:none;&#x22;&#x3E;
&#x3C;div class=&#x22;flex items-center justify-center w-full max-w-full&#x22;&#x3E;
&#x3C;!-- Element Here --&#x3E;
&#x3C;/div&#x3E;
&#x3C;/body&#x3E;
&#x3C;/html&#x3E;</code></pre>
<div class="relative w-full rounded-lg border border-transparent p-4 [&amp;>svg]:absolute [&amp;>svg]:text-foreground [&amp;>svg]:left-4 [&amp;>svg]:top-4 [&amp;>svg+div]:translate-y-[-3px] [&amp;:has(svg)]:pl-11 bg-blue-600 text-white">
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M6.28 5.22a.75.75 0 010 1.06L2.56 10l3.72 3.72a.75.75 0 01-1.06 1.06L.97 10.53a.75.75 0 010-1.06l4.25-4.25a.75.75 0 011.06 0zm7.44 0a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06L17.44 10l-3.72-3.72a.75.75 0 010-1.06zM11.377 2.011a.75.75 0 01.612.867l-2.5 14.5a.75.75 0 01-1.478-.255l2.5-14.5a.75.75 0 01.866-.612z" clip-rule="evenodd" /></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Paste in your element</h5>
<div class="text-sm [&amp;_p]:leading-relaxed opacity-80">Replace the `&lt;!-- Element Here --&gt;` line with the element snippet and you're ready to rock and roll.</div>
</div>
<hr>
<h3>The Pines Playground</h3>
<p class="text-gray-500">You may also open up the <button class="text-blue-600 underline" onclick="window.dispatchEvent(new CustomEvent('open-playground', { detail: {}}));">Pines Playground</button> and edit any element or design your own. Keep in mind that the data entered into the playground will not be saved, so if you leave the page you may lose any changes. However, it may be the easiest way to make a few modifications to an element or create your own.</p>

View File

@ -0,0 +1,123 @@
<div class="not-prose">
<h2 class="pt-0 mb-2 text-3xl font-bold tracking-tight select-none not-prose custom-font">Introduction</h2>
</div>
<p class="text-gray-500">The team over here at <a href="https://devdojo.com" class="relative text-indigo-600 group"><span>DevDojo</span><span class="absolute bottom-0 left-0 w-0 h-px duration-300 ease-out bg-indigo-500 group-hover:w-full"></span></a> are huge fans of Alpine and Tailwind 🤩 We love it so much that we are open-sourcing our library of UI elements that we've been crafting over the years.</p>
<hr>
<h3>Why Tailwind and Alpine?</h3>
<p class="text-gray-500">When used together, Alpine and Tailwind complement each other and allow developers to build re-usable and functional UI elements with minimal effort. By using <strong>Alpine directives</strong> for functionality and <strong>Tailwind utility classes</strong> for design, we can create beautiful and functional interfaces represented by using <strong>only HTML</strong>.</p>
<h3>An Example</h3>
<p class="text-gray-500">Here is an example of a simple dropdown with minimal code 👇</p>
<div x-data="{ preview: true }" class="relative z-30 w-full mb-5 rounded-md">
<div class="flex items-center justify-between mb-3">
<div
x-data="{
repositionTabMarker(el){
this.$refs.marker.style.width=el.offsetWidth + 'px';
this.$refs.marker.style.height=el.offsetHeight + 'px';
this.$refs.marker.style.left=el.offsetLeft + 'px';
}
}"
x-init="repositionTabMarker($el.firstElementChild);" class="relative inline-grid items-center justify-center w-auto h-10 grid-cols-2 p-1 text-gray-500 bg-gray-100 rounded-lg select-none">
<button type="button" @click="repositionTabMarker($el); preview=true;" class="relative z-20 inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap ring-offset-background">Preview</button>
<button type="button" @click="repositionTabMarker($el); preview=false" class="relative z-20 inline-flex items-center justify-center h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap ring-offset-background">Code</button>
<div x-ref="marker" class="absolute left-0 z-10 w-1/2 h-full duration-300 ease-out" x-cloak>
<div class="w-full h-full bg-white rounded-md shadow-sm"></div>
</div>
</div>
<div x-data="{
copyText: `&lt;div x-data=&quot;{ open: false }&quot; @click.outside=&quot;open=false&quot; class=&quot;relative text-sm&quot;&gt;
&lt;button @click=&quot;open=!open&quot; class=&quot;bg-white rounded-md shadow-sm cursor-pointer&quot;&gt;
&lt;span class=&quot;block px-4 py-2&quot;&gt;Dropdown&lt;/span&gt;
&lt;/button&gt;
&lt;ul x-show=&quot;open&quot; class=&quot;absolute origin-top-left top-0 w-32 p-4 mt-10 bg-white rounded-md shadow-sm&quot; x-transition x-cloak&gt;
&lt;li&gt;Menu Item 1&lt;/li&gt;
&lt;li&gt;Menu Item 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;`,
copyNotification: false,
copyToClipboard() {
navigator.clipboard.writeText(this.copyText);
this.copyNotification = true;
let that = this;
setTimeout(function(){
that.copyNotification = false;
}, 3000);
}
}" class="relative flex items-center space-x-2">
<div
x-show="copyNotification"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-x-2"
x-transition:enter-end="opacity-100 translate-x-0"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 translate-x-0"
x-transition:leave-end="opacity-0 translate-x-2"
class="absolute left-0" x-cloak>
<div class="px-3 h-7 -ml-0.5 items-center flex text-xs bg-green-500 border-r border-green-500 -translate-x-full text-white rounded">
<span>Copied!</span>
<div class="absolute right-0 inline-block h-full -mt-px overflow-hidden translate-x-3 -translate-y-2 top-1/2">
<!-- ← triangle container -->
<!-- triangle ↓ -->
<div class="w-3 h-3 origin-top-left transform rotate-45 bg-green-500 border border-transparent"></div>
</div>
</div>
</div>
<button @click="copyToClipboard();" class="flex items-center justify-center h-8 text-xs rounded-lg cursor-pointer w-9 hover:bg-gray-50 active:bg-gray-100 text-neutral-400 hover:text-neutral-700 group">
<svg class="w-4 h-4 stroke-current" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z" /></svg>
</button>
</div>
</div>
<div class="relative">
<div x-show="preview" class="relative p-10 border rounded-md border-neutral-200 bg-gray-50">
<div class="flex items-center justify-center w-full max-w-md mx-auto not-prose">
<div x-data="{ open: false }" @click.outside="open=false" class="relative text-sm">
<button @click="open=!open" class="bg-white rounded-md shadow-sm cursor-pointer">
<span class="block px-4 py-2">Dropdown</span>
</button>
<ul x-show="open" class="absolute top-0 w-32 p-4 mt-10 origin-top-left bg-white rounded-md shadow-sm" x-transition x-cloak>
<li>Menu Item 1</li>
<li>Menu Item 2</li>
</ul>
</div>
</div>
</div>
<div x-show="!preview" :class="{ 'opacity-0 z-10' : preview, 'z-30': !preview }" class="relative not-prose cursor-text " x-cloak>
<pre class="block w-full overflow-scroll text-sm border rounded-md hljs html border-neutral-200"><code class="hljs html">&lt;div x-data=&quot;{ open: false }&quot; @click.outside=&quot;open=false&quot; class=&quot;relative text-sm&quot;&gt;
&lt;button @click=&quot;open=!open&quot; class=&quot;bg-white rounded-md shadow-sm cursor-pointer&quot;&gt;
&lt;span class=&quot;block px-4 py-2&quot;&gt;Dropdown&lt;/span&gt;
&lt;/button&gt;
&lt;ul x-show=&quot;open&quot; class=&quot;absolute origin-top-left top-0 w-32 p-4 mt-10 bg-white rounded-md shadow-sm&quot; x-transition x-cloak&gt;
&lt;li&gt;Menu Item 1&lt;/li&gt;
&lt;li&gt;Menu Item 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</code></pre>
</div>
</div>
</div>
<div role="alert" class="relative w-full rounded-lg border p-4 [&amp;>svg]:absolute [&amp;>svg]:text-foreground [&amp;>svg]:left-4 [&amp;>svg]:top-4 [&amp;>svg+div]:translate-y-[-3px] [&amp;:has(svg)]:pl-11 bg-background text-foreground">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><polyline points="4 17 10 11 4 5"></polyline><line x1="12" x2="20" y1="19" y2="19"></line></svg>
<h5 class="mb-1 font-medium leading-none tracking-tight">Copy the Code. That's all you need!</h5>
<div class="text-sm [&amp;_p]:leading-relaxed">Simply add the <a href="https://alpinejs.dev" target="_blank" class="font-normal">Alpine</a> & <a href="https://tailwindcss.com" target="_blank" class="font-normal">Tailwind</a> library to your page, paste in the element, and boom 🔮</div>
</div>
<h3>Inspiration</h3>
<p class="text-gray-500">As we design and develop websites, it is essential to recognize the contributions of those who came before us. We stand on the shoulders of giants, learning from their success, and using their knowledge to improve our work. With that said, we have taken inspiration from these handful of Open Source projects below. Be sure to check them out.</p>
<ol>
<li><a href="https://tailwindcss.com" target="_blank" class="font-medium text-blue-600 underline">Tailwind CSS</a></li>
<li><a href="https://alpinejs.dev" target="_blank" class="font-medium text-blue-600 underline">Alpine JS</a></li>
<li><a href="https://www.radix-ui.com/" target="_blank" class="font-medium text-blue-600 underline">Radix UI</a></li>
<li><a href="https://ui.shadcn.com/" target="_blank" class="font-medium text-blue-600 underline">ShadCN UI</a></li>
<li><a href="https://getuikit.com/" target="_blank" class="font-medium text-blue-600 underline">Get UIKit</a></li>
</ol>

27
index.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<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>Pines UI Library</title>
<style>[x-cloak]{display:none}</style>
<!-- Include the Alpine library on your page -->
<script src="//unpkg.com/alpinejs" defer></script>
<!-- Include the TailwindCSS library on your page -->
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
</head>
<body style="display:none">
<div id="list" class="p-10">
<svg class="w-auto h-6 mb-5" viewBox="0 0 355 99" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M119.1 87V66.4h19.8c34.3 0 34.2-49.5 0-49.5-11 0-22 .1-33 .1v70h13.2zm19.8-32.7h-19.8V29.5h19.8c16.8 0 16.9 24.8 0 24.8zm32.6-30.5c0 9.5 14.4 9.5 14.4 0s-14.4-9.5-14.4 0zM184.8 87V37.5h-12.2V87h12.2zm22.8 0V61.8c0-7.5 5.1-13.8 12.6-13.8 7.8 0 11.9 5.7 11.9 13.2V87h12.2V61.1c0-15.5-9.3-24.2-20.9-24.2-6.2 0-11.2 2.5-16.2 7.4l-.8-6.7h-10.9V87h12.1zm72.1 1.3c7.5 0 16-2.6 21.2-8l-7.8-7.7c-2.8 2.9-8.7 4.6-13.2 4.6-8.6 0-13.9-4.4-14.7-10.5h38.5c1.9-20.3-8.4-30.5-24.9-30.5-16 0-26.2 10.8-26.2 25.8 0 15.8 10.1 26.3 27.1 26.3zM292 56.6h-26.6c1.8-6.4 7.2-9.6 13.8-9.6 7 0 12 3.2 12.8 9.6zm41.2 32.1c14.1 0 21.2-7.5 21.2-16.2 0-13.1-11.8-15.2-21.1-15.8-6.3-.4-9.2-2.2-9.2-5.4 0-3.1 3.2-4.9 9-4.9 4.7 0 8.7 1.1 12.2 4.4l6.8-8c-5.7-5-11.5-6.5-19.2-6.5-9 0-20.8 4-20.8 15.4 0 11.2 11.1 14.6 20.4 15.3 7 .4 9.8 1.8 9.8 5.2 0 3.6-4.3 6-8.9 5.9-5.5-.1-13.5-3-17-6.9l-6 8.7c7.2 7.5 15 8.8 22.8 8.8z" id="a"></path></defs><g fill="none" fill-rule="evenodd"><g fill="currentColor"><path d="M19.742 49h28.516L68 83H0l19.742-34z"></path><path d="M26 69h14v30H26V69zM4 50L33.127 0 63 50H4z"></path></g><g fill-rule="nonzero"><use fill="currentColor" xlink:href="#a"></use><use fill="currentColor" xlink:href="#a"></use></g></g></svg>
<a id="back" href="/" class="hidden text-blue-500 underline">&larr; Back</a>
<h2 id="start" class="mb-1 font-bold text-neutral-900">Getting Started</h2>
<ul id="gettingStarted" class="space-y-0.5 font-medium mb-5"></ul>
<h2 id="title" class="mb-1 font-bold text-neutral-900">Elements</h2>
<ul id="elements" class="space-y-0.5 font-medium"></ul>
</div>
<div id="content"></div>
<script src="./main.js"></script>
</body>
</html>

100
main.js Normal file
View File

@ -0,0 +1,100 @@
/**
* When the document is ready check to see if we are on an element or getting started page.
* If we are on an element or getting started page, load the content from the HTML file.
* If not, load the list of elements and getting started items from the JSON file.
*/
document.addEventListener('DOMContentLoaded', function() {
const element = getQueryParameter('element');
const start = getQueryParameter('start');
if(element || start){
document.getElementById('list').remove();
load_file('./data.json', function(text){
let data = JSON.parse(text);
let folderLocation = (element) ? 'elements' : 'getting-started';
let file = (element) ? element : start;
if(element){
document.getElementById('content').className = data.container[element];
} else {
document.getElementById('content').className = 'max-w-3xl p-10 prose';
}
load_file('./' + folderLocation + '/' + file + '.html', function(text){
document.getElementById('content').innerHTML = text;
document.body.style = '';
});
});
} else {
document.getElementById('content').remove();
load_file('./data.json', function(text){
let data = JSON.parse(text);
addItemsToList(data.elements, document.getElementById('elements'), 'element');
addItemsToList(data.start, document.getElementById('gettingStarted'), 'start');
document.body.style = '';
});
}
});
/**
* Get the value of a query parameter from the URL. ?element=accordion or ?start=introduction, etc.
*/
function getQueryParameter(parameter){
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const element = urlParams.get(parameter);
return element;
}
/**
* Add element and getting started items from the JSON file to the html list
*/
function addItemsToList(myObject, myList, param){
for (const key in myObject) {
const listItem = document.createElement('li');
const link = document.createElement('a');
link.className = 'text-blue-500 underline';
link.href = '?' + param + '=' + key;
link.textContent = myObject[key];
listItem.appendChild(link);
myList.appendChild(listItem);
// POSSIBLE TODO: Add click event to load content from HTML file, DYNAMIC PAGE LOAD INSTEAD OF FULL PAGE LOAD
// link.addEventListener('click', function(e){
// e.preventDefault();
// console.log(e.target.href);
// console.log('do magic');
// get_element(e.target.href, function(text){
// const parser = new DOMParser();
// const doc = parser.parseFromString(text, 'text/html');
// const bodyContent = doc.querySelector('body').innerHTML;
// console.log(bodyContent);
// });
// });
}
}
/**
* Load the contents of a file using the Fetch API and passes it to a callback function.
*/
function get_element(filename, callback) {
fetch(filename).then(response => response.text()).then(text => callback(text));
}
/**
* Load the contents of a file using the Fetch API and passes it to a callback function.
*/
function load_file(filename, callback) {
fetch(filename).then(response => response.text()).then(text => callback(text));
}
/**
* Format lowercase string to title case.
*/
function formatString(str) {
let formattedStr = str.replace(/-/g, ' ');
formattedStr = formattedStr.replace(/\b\w/g, (match) => match.toUpperCase());
return formattedStr;
}