- Lorem ipsum dolor sit amet, consectetur adipiscing
- elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
- quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
- dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
- sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
- laborum.
-
- The banner is disabled if a local storage key is set.
-
- Click the buttons below to enable/disable and refresh the page.
-
-
-
{
parameters.removeKeyLocalStorage(args.siteId)
}}>Re-Enable Banner
diff --git a/README.md b/README.md
index 0d36744d..d8305a8c 100644
--- a/README.md
+++ b/README.md
@@ -1,207 +1,145 @@
-# HOT Shared UI
-
-
-
-
-
-
- Shared Web Components with theming for use across HOTOSM tools.
-
+# HOT UI
-📖 **Documentation**: https://hotosm.github.io/ui/
+## Shared UI components with HOT theming
-🖥️ **Source Code**: https://github.com/hotosm/ui
+HOT themed UI components to reduce code duplication and make live easier for developers, available as [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) and witn first-class React support
-🎯 **Roadmap / Tasks**: https://github.com/orgs/hotosm/projects/37/views/3
+The main goal of this project is not to re-invent the wheel, or add an extra burden of development and maintenance.
----
+
-
+[![Release](https://github.com/hotosm/ui/actions/workflows/publish.yml/badge.svg?event=release)](https://github.com/hotosm/ui/actions/workflows/publish.yml/)
+[![CDN Deploy](https://github.com/hotosm/ui/actions/workflows/cdn_deploy.yml/badge.svg?branch=main)](https://github.com/hotosm/ui/actions/workflows/cdn_deploy.yml)
+[![Docs](https://github.com/hotosm/ui/actions/workflows/docs.yml/badge.svg)](https://github.com/hotosm/ui/actions/workflows/docs.yml)
+[![Package Version](https://img.shields.io/npm/v/%40hotosm/ui?color=334D058)](https://www.npmjs.com/package/@hotosm/ui)
+[![Downloads](https://img.shields.io/npm/dm/%40hotosm%2Fui)](https://npmtrends.com/@hotosm/ui)
+[![License](https://img.shields.io/github/license/hotosm/ui.svg)](https://github.com/hotosm/ui/blob/main/LICENSE.md)
-Shared UI components with theming for use across HOTOSM tools,
-to reduce code duplication.
+📖 **Documentation**: https://hotosm.github.io/ui/
-The components are
-[Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components),
-currently written in **Lit**, using TypeScript.
+🖥️ **Source Code**: https://github.com/hotosm/ui
-The main goal of this project is not to re-invent the wheel, or add an extra
-burden of development and maintenance.
+🎯 **Roadmap / Tasks**: https://github.com/orgs/hotosm/projects/37/views/3
-Primarily we want to have:
+---
-- Low level components exported from the excellent Shoelace web component
- library, simply re-exported with our default styling / CSS overrides.
-- A few composite components (header, sidebar, etc):
- - Consistent styling across most of our tools where it counts.
- - Reduction in duplicated logic, such as user management, OAuth login, etc.
-- Improved developer experience, reduced development time for new tools, while
- maintaining consistency in look and feel of applications.
+## Quick start
-## Install
+There are two options: NPM and Components Bundle.
-There are two options for install:
+### NPM
-- **NPM**: appropriate for applications that have installable dependencies.
-- **CDN**: appropriate for HTML / Markdown / HTMX.
+Appropriate for applications that have installable dependencies
-### Components Bundle
+`npm install @hotosm/ui`
-- This is the compiled JavaScript bundle generated from the TypeScript code.
-- The components require no additional dependencies and are minified.
-
-#### Via NPM
-
-- Install package `@hotosm/ui` as a dependency in your `package.json`.
-- Import the components.
+Import the library in your project and use the components.
```html
+```
-// Use the components in your templates
-
+```html
+
```
-#### Via CDN
+#### React
+
+```js
+ import { Logo } from '@hotosm/ui/components';
+```
+
+```jsx
+
+```
+
+### Components Bundle
+
+- This is the compiled JavaScript bundle generated from the TypeScript code.
+- The components require no additional dependencies and are minified.
+
+Appropriate for HTML / Markdown / HTMX.
```html
-// Import the styles (or create your own)
-// Import the components
-
-```
-
-The `jsdelivr` CDN only includes package releases, with `@latest` pointing to the
-most recent tagged release.
+
+```
-There is also an S3-based CDN, where `latest` tracks the `main` branch of the repo:
- `https://s3.amazonaws.com/hotosm-ui/latest/dist/components.js`
-
-### ES Modules
-
-- Using the TypeScript ES Modules allows for cherry-picking components, so
-'tree-shaking' can remove the remaining ones you don't use.
-- If you are developing an application that uses `@hotosm/ui` components,
-including a bundler such as rollup/vite/webpack, this is probably the best approach.
-- However, you must first add Shoelace as a `peerDependency` in your `package.json`:
+## Using Extra Shoelace Components
- ```json
- "peerDependencies": {
- "@shoelace-style/shoelace": "^2.15.1"
- }
- ```
+The HOT UI library contains many composite components, such as headers, sidebars,
+tracking banners, etc, and does not re-invent the wheel for low-level components.
- > Ideally the version of Shoelace installed should match the version used in
- > hotosm/ui.
+Shoelace is an UI library that is exported directly from `@hotosm/ui`.
-Example:
+To access the low-level components, such as buttons, dropdowns, modals, etc,
+simply import the component of the same name from the [Shoelace docs]
+():
```js
-import '@hotosm/ui/components/header/header';
+import '@hotosm/ui/components/button/button';
+```
-// Then in your template
-
+```html
+Can't Click Me
```
### React
-Versions of React below v19 require a specific 'wrapper' component to use the
-web components.
-
-Use these instead of the standard `@hotosm/ui/components/xxx`:
-
-```bash
-pnpm install @hotosm/ui
+```js
+import { Button } from '@hotosm/ui/components';
```
-```js
-import { Button } from '@hotosm/ui/react/Header'
-
-const HomePage = ({}) => {
- return (
-
-
-
-
-
- );
-};
-
-export default HomePage;
+```html
+
```
-> Note that while web components must always have a closing tag, this is not
-> required for the React wrappers.
+### Examples
-## Using Extra Shoelace Components
+You can found examples for HTML and also all common frameworks (React, Svelte, Vue) under `/examples`.
-The UI library contains many composite components, such as headers, sidebars,
-tracking banners, etc, and does not re-invent the wheel for low-level components.
+### Development
-Shoelace is an excellent UI library that is exported directly from `@hotosm/ui`.
+HOT UI is developed in TypeScript, using Lit and @lit/react.
-To access the low-level components, such as buttons, dropdowns, modals, etc,
-simply import the component of the same name from the [Shoelace docs]
-():
+Primarily we want to have:
-```js
-import '@hotosm/ui/components/button/button';
+- Low level components exported from the Shoelace web component
+ library, simply re-exported with our default styling / CSS overrides.
+- A few composite components (header, sidebar, etc):
+ - Consistent styling across most of our tools where it counts.
+ - Reduction in duplicated logic, such as user management, OAuth login, etc.
+- Improved developer experience, reduced development time for new tools, while
+ maintaining consistency in look and feel of applications.
-// Then in your template
-Can't Click Me
-```
+### How to contribute
-If you are using a bundler, you must bundle the (icon) assets yourself,
-described in the Shoelace docs.
+- Clone the project `git clone git@github.com:hotosm/ui.git`
+- Install dependencies `pnpm install`
+- Run the storybook `pnpm run dev`
+- Write code!
-### Example of bundling assets
+There's also a React storybook that you can use for testing:
-- To include the Shoelace assets in your final bundle (dist), you could add
- the following to your `package.json`:
+- Run the React storybook `pnpm run dev-react`
-```json
- "scripts": {
- "clean-icons": "rm -rf public/assets/icons",
- "get-icons": "cp -r node_modules/@shoelace-style/shoelace/dist/assets/icons public/",
- "setup-dist": "pnpm run clean-icons && pnpm run get-icons",
- }
-```
+For **styling**, we have 2 important files under `/theme`:
+
+- `hot-sl.css` has a Shoelace theme, re-defining some variables
+- `hot.css` has custom styles for eveything else, specially composited components
+
+### License
-- Now the Shoelace assets will be bundled with your dist, under `/shoelace`.
-- Following the example, also add `public/assets/icons` to your `.gitignore` file.
+HOT UI is free and open source software! you may use any HOT UI project under the terms of the GNU Affero General Public License (AGPL) Version 3.
diff --git a/components/header/header.styles.ts b/components/header/header.styles.ts
new file mode 100644
index 00000000..e98945a0
--- /dev/null
+++ b/components/header/header.styles.ts
@@ -0,0 +1,103 @@
+import { css } from 'lit';
+import { cva } from "class-variance-authority";
+
+export const headerVariants = cva(
+ // Defaults to include in all variants
+ `
+ header
+ `,
+ {
+ variants: {
+ size: {
+ small: "header--size-small",
+ medium: "header--size-medium",
+ large: "header--size-large",
+ },
+ borderBottom: {
+ true: "border-bottom",
+ }
+ },
+ }
+);
+
+export type sizes = "small" | "medium" | "large";
+
+export const styles = css`
+ .header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 var(--sl-spacing-small);
+ }
+
+ .header.border-bottom {
+ border-bottom: var(--hot-divider-border-bottom) solid var(--sl-color-neutral-50);
+ }
+
+ .header--size-small {
+ height: var(--hot-height-small);
+ }
+
+ .header--size-medium {
+ height: var(--hot-height-medium);
+ }
+
+ .header--size-large {
+ height: var(--hot-height-large);
+ }
+
+ .header--link {
+ text-decoration: none;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--sl-spacing-small);
+ }
+
+ .header--title {
+ color: var(--sl-color-neutral-950);
+ font-family: var(--sl-font-sans);
+ font-size: var(--sl-font-size-x-large);
+ }
+
+ .header--tab-group {
+ flex-direction: column;
+ }
+
+ .header--tab::part(base) {
+ font-size: var(--sl-font-size-medium);
+ font-weight: var(--sl-font-weight-normal);
+ color: var(--sl-color-neutral-950);
+ padding: var(--sl-spacing-small) var(--sl-spacing-small);
+ }
+
+ .header--tab-group::part(base) {
+ --track-color: transparent;
+ --indicator-color: var(--sl-color-neutral-950);
+ }
+
+ .header--nav {
+ justify-content: space-between;
+ justify-items: center;
+ gap: var(--sl-spacing-medium);
+ font-weight: var(--sl-font-weight-semibold);
+ }
+
+ .header--nav-mobile {
+ }
+
+ .header--person-circle {
+ font-size: var(--sl-font-size-x-large);
+ }
+
+ .header--drawer {
+ font-size: var(--sl-font-size-x-large)
+ }
+
+ .header--right-section {
+ }
+
+ .header--logo-img {
+ }
+}
+`
diff --git a/components/header/header.ts b/components/header/header.ts
index 3eaa82c4..019d80b1 100644
--- a/components/header/header.ts
+++ b/components/header/header.ts
@@ -1,3 +1,4 @@
+import "../../theme/hot-sl.css";
import "../../theme/hot.css";
import "@shoelace-style/shoelace/dist/components/icon-button/icon-button.js";
@@ -6,8 +7,9 @@ import "@shoelace-style/shoelace/dist/components/tab-group/tab-group.js";
import "@shoelace-style/shoelace/dist/components/tab/tab.js";
import { LitElement, html } from "lit";
-import { property, state } from "lit/decorators.js";
-import { headerVariants, type sizes, styles} from "./styles";
+import { property } from "lit/decorators.js";
+import { headerVariants, type sizes, styles } from './header.styles.js';
+import type { CSSResultGroup } from 'lit';
import registerBundledIcons from "../../components/icons";
@@ -20,26 +22,36 @@ interface MenuItem {
export class Header extends LitElement {
- @property() name = "hot-header";
+ static styles: CSSResultGroup = [styles];
+
+ name = "hot-header";
/** Use a text-based title in the header. */
- @property({ type: String }) title: string = "";
+ @property({ type: String })
+ accessor title: string = "";
/** Display a logo on the left of the header. */
- @property({ type: String }) logo: string | URL = "";
+ @property({ type: String })
+ accessor logo: string | URL = "";
/** Add a drawer icon with a click event to e.g. open a sidebar. */
- @property({ type: Boolean }) drawer: boolean = true;
+ @property({ type: Boolean })
+ accessor drawer: boolean = true;
/** Array of menu items to include as navigation tabs. */
- @property({ type: Array }) tabs: MenuItem[] = [];
+ @property({ type: Array })
+ accessor tabs: MenuItem[] = [];
/** Size of toolbar vertically. */
- @property({ type: String }) size: sizes = "large";
-
- @state() private selectedTab: number = 0;
+ @property({ type: String })
+ accessor size: sizes = "small";
- static styles = styles;
+ /** Border bottom. */
+ @property({ type: Boolean })
+ accessor borderBottom: boolean = true;
+
+ @property()
+ accessor selectedTab: number = 0;
protected render() {
const logoSrc =
@@ -50,26 +62,29 @@ export class Header extends LitElement {
: "";
return html`
-
-
+
+
${logoSrc.length > 0
? html`
`
: html`
- 0}"
>
`}
${this.title.length > 0
? html`
-