-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e3ef1ec
commit 1477717
Showing
12 changed files
with
471 additions
and
209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,43 @@ | ||
# Vimesh Headless UI | ||
# Vimesh Headless UI | ||
This is Alpine.js implementation of [Tailwind Headless UI](https://headlessui.com/). Built with [Vimesh UI](https://github.com/vimeshjs/vimesh-ui) framework, Vimesh Headless UI has some unique features: | ||
## Ultra lightweight | ||
Vimesh Headless UI has much less code size | ||
|
||
| Component | Vimesh Headless UI | Tailwind Headless UI for Vue | Tailwind Headless UI for React | | ||
| ----------- | -------------------- | -------- | ----- | | ||
| Listbox | 8k | 34k | 30k | | ||
| Combobox | 9k | 25k | 39k | | ||
| Menu | 7k | 18k | 20k | | ||
| Switch | 0.6k | 5k | 6k | | ||
| Tabs | 4k | 12k | 16k | | ||
| Dialog | 2k | 15k | 17k | | ||
| Popover | 6k | 23k | 28k | | ||
| Radio Group | 1k | 11k | 14k | | ||
|
||
Comparing the production version of Vimesh and Tailwind headless dialog example page size, Vimesh is much smaller with more features and less bugs (check the menu display in the popup dialog). | ||
|
||
| Vimesh | Tailwind | | ||
| ---- | ---- | | ||
| ![](./assets/vimesh001.png) | ![](./assets/tailwind001.png) | | ||
| 192k | 425k | | ||
|
||
## Load only used components dynamically | ||
Components are plain html files, which could be hosted anywhere, normally at CDN. They could be shared cross different projects without extra tree shaking magic. For example, the dialog basic example uses two components `hui-dialog` and `hui-menu`. Just load them asynchronously with `x-import`, [Vimesh UI](https://github.com/vimeshjs/vimesh-ui) registers native custom elements and initialize them. | ||
|
||
```html | ||
<template x-component:page="dialog-basic" x-import="hui:dialog,menu" x-data="setupDialogBasicData()" | ||
class="overflow-y-auto"> | ||
... | ||
<hui-dialog :open="isOpen" @close="setIsOpen(false)"> | ||
... | ||
<hui-menu> | ||
</hui-menu> | ||
</hui-dialog> | ||
... | ||
</template> | ||
``` | ||
|
||
## No build, no bundle | ||
What you write is what you get. Organize components to html files under meaningful namespaces. You do not need webpack, rollup, vite etc. | ||
|
||
## Easy to debug |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
<script> | ||
|
||
function setupComboboxCommandPaletteGroupData() { | ||
|
||
let everybody = [ | ||
{ id: 1, img: 'https://github.com/adamwathan.png', name: 'Adam Wathan' }, | ||
{ id: 2, img: 'https://github.com/sschoger.png', name: 'Steve Schoger' }, | ||
{ id: 3, img: 'https://github.com/bradlc.png', name: 'Brad Cornes' }, | ||
{ id: 4, img: 'https://github.com/simonswiss.png', name: 'Simon Vrachliotis' }, | ||
{ id: 5, img: 'https://github.com/robinmalfait.png', name: 'Robin Malfait' }, | ||
{ | ||
id: 6, | ||
img: 'https://pbs.twimg.com/profile_images/1478879681491394569/eV2PyCnm_400x400.jpg', | ||
name: 'James McDonald', | ||
}, | ||
{ id: 7, img: 'https://github.com/reinink.png', name: 'Jonathan Reinink' }, | ||
{ id: 8, img: 'https://github.com/thecrypticace.png', name: 'Jordan Pittman' }, | ||
] | ||
|
||
return { | ||
query: '', | ||
activePerson: everybody[1], | ||
get people() { | ||
return this.query === '' | ||
? everybody | ||
: everybody.filter((person) => | ||
person.name.toLowerCase().includes(this.query.toLowerCase()) | ||
) | ||
}, | ||
|
||
get groups() { | ||
return this.people.reduce((groups, person) => { | ||
let lastNameLetter = person.name.split(' ')[1][0] | ||
|
||
groups.set(lastNameLetter, [...(groups.get(lastNameLetter) || []), person]) | ||
|
||
return groups | ||
}, new Map()) | ||
}, | ||
|
||
get sortedGroups() { | ||
return Array.from(this.groups.entries()).sort(([letterA], [letterZ]) => | ||
letterA.localeCompare(letterZ) | ||
) | ||
}, | ||
|
||
displayValue: () => (item) => item && item.name | ||
} | ||
} | ||
</script> | ||
<template x-component:page="combobox-command-palette-group" x-import="hui:combobox" | ||
x-data="setupComboboxCommandPaletteGroupData()"> | ||
<div class=" flex h-full w-full justify-center bg-gray-50 p-12"> | ||
<div class="mx-auto w-full max-w-lg"> | ||
<div class="space-y-1"> | ||
<hui-combobox x-model="activePerson" | ||
class="w-full overflow-hidden rounded border border-black/5 bg-white bg-clip-padding shadow-sm"> | ||
<div class="flex w-full flex-col"> | ||
<hui-combobox-input @change="query = $event.target.value" | ||
class="w-full rounded-none border-none px-3 py-1 outline-none" placeholder="Search users…" | ||
:display-value="displayValue"></hui-combobox-input> | ||
<div class="flex"> | ||
<hui-combobox-options | ||
class="shadow-xs max-h-60 flex-1 overflow-auto text-base leading-6 focus:outline-none sm:text-sm sm:leading-5"> | ||
<template x-for="[letter, people] of sortedGroups" :key="letter"> | ||
<div> | ||
<div class="bg-gray-100 px-4 py-2" x-text="letter"></div> | ||
<template x-for="person in people"> | ||
<hui-combobox-option :value="person"> | ||
|
||
<div :class="[ | ||
'relative flex cursor-default select-none space-x-4 py-2 pl-3 pr-9 focus:outline-none', | ||
active ? 'bg-indigo-600 text-white' : 'text-gray-900', | ||
]"> | ||
<img :src="person.img" | ||
class="h-6 w-6 overflow-hidden rounded-full" /> | ||
<span | ||
:class="['block truncate', selected ? 'font-semibold' : 'font-normal']" | ||
x-text="person.name"> | ||
</span> | ||
<span x-show="active" :class="[ | ||
'absolute inset-y-0 right-0 flex items-center pr-4', | ||
active ? 'text-white' : 'text-indigo-600', | ||
]"> | ||
<svg class="h-5 w-5" viewBox="0 0 25 24" fill="none"> | ||
<path d="M11.25 8.75L14.75 12L11.25 15.25" | ||
stroke="currentColor" strokeWidth="1.5" | ||
strokeLinecap="round" strokeLinejoin="round" /> | ||
</svg> | ||
</span> | ||
</div> | ||
</hui-combobox-option> | ||
</template> | ||
</div> | ||
</template> | ||
</hui-combobox-options> | ||
<template x-if="people.length === 0"> | ||
<div class="w-full py-4 text-center"> | ||
No person selected | ||
</div> | ||
</template> | ||
<template x-if="people.length > 0 && isOpen && activeOption"> | ||
<div class="border-l"> | ||
<div class="flex flex-col"> | ||
<div class="p-8 text-center"> | ||
<img :src="activeOption.img" | ||
class="mb-4 inline-block h-16 w-16 overflow-hidden rounded-full" /> | ||
<div class="font-bold text-gray-900" x-text="activeOption.name"></div> | ||
<div class="text-gray-700">Obviously cool person</div> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
</div> | ||
</div> | ||
</hui-combobox> | ||
</div> | ||
</div> | ||
</div> | ||
</template> |
Oops, something went wrong.