🤖 I have created a release *beep* *boop* --- ## [4.4.0](https://github.com/unraid/api/compare/v4.3.1...v4.4.0) (2025-03-25) ### Features * add ReplaceKey functionality to plugin ([#1264](https://github.com/unraid/api/issues/1264)) ([7e6be67](7e6be67f61)) * downgrade page replace key check ([#1263](https://github.com/unraid/api/issues/1263)) ([6a92f61](6a92f61f1a)) * make log viewer component dynamic ([#1242](https://github.com/unraid/api/issues/1242)) ([a356bf0](a356bf03fb)) * ReplaceKey functionality in Registration and Update pages ([#1246](https://github.com/unraid/api/issues/1246)) ([f3e6a00](f3e6a0011e)) * UnraidCheckExec for Check OS Updates via UPC dropdown ([#1265](https://github.com/unraid/api/issues/1265)) ([3a20930](3a20930ead)) ### Bug Fixes * **deps:** update all non-major dependencies ([#1236](https://github.com/unraid/api/issues/1236)) ([9d63e56](9d63e56374)) * **deps:** update all non-major dependencies ([#1247](https://github.com/unraid/api/issues/1247)) ([57a6c49](57a6c49f8a)) * **deps:** update all non-major dependencies ([#1251](https://github.com/unraid/api/issues/1251)) ([ad3906e](ad3906e682)) * **deps:** update all non-major dependencies ([#1253](https://github.com/unraid/api/issues/1253)) ([bbb02e9](bbb02e991c)) * **deps:** update dependency @nestjs/passport to v11 ([#1244](https://github.com/unraid/api/issues/1244)) ([9e54237](9e54237670)) * **deps:** update dependency graphql-subscriptions to v3 ([#1209](https://github.com/unraid/api/issues/1209)) ([c9789ac](c9789ac1f2)) * **deps:** update dependency ini to v5 ([#1217](https://github.com/unraid/api/issues/1217)) ([590ab73](590ab7327f)) * **deps:** update dependency jose to v6 ([#1248](https://github.com/unraid/api/issues/1248)) ([03ece33](03ece335b8)) * **deps:** update dependency marked to v15 ([#1249](https://github.com/unraid/api/issues/1249)) ([8f78b3f](8f78b3f1ca)) * **deps:** update dependency pino-pretty to v13 ([#1250](https://github.com/unraid/api/issues/1250)) ([1892e23](1892e23c22)) * **deps:** update dependency pm2 to v6 ([#1258](https://github.com/unraid/api/issues/1258)) ([d8afc8f](d8afc8f4c9)) * **deps:** update dependency shadcn-vue to v1 ([#1259](https://github.com/unraid/api/issues/1259)) ([cb2020d](cb2020dee6)) * **deps:** update dependency vue-i18n to v11 ([#1261](https://github.com/unraid/api/issues/1261)) ([2c01ba9](2c01ba9610)) * **deps:** update vueuse monorepo to v13 (major) ([#1262](https://github.com/unraid/api/issues/1262)) ([9ce10a7](9ce10a72b2)) * make scripts executable when building the plugin ([#1255](https://github.com/unraid/api/issues/1255)) ([7bc9949](7bc9949110)) * node installation not persisting across reboots ([#1256](https://github.com/unraid/api/issues/1256)) ([3bfcc8e](3bfcc8e8c0)) * update configValid state to ineligible in var.ini and adjust rel… ([#1268](https://github.com/unraid/api/issues/1268)) ([cc85fba](cc85fba207)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Unraid UI
A Vue 3 component library providing a set of reusable, accessible UI components for Unraid development.
Features
- ⚡️ Built with Vue 3 and TypeScript
- 🎭 Storybook documentation
- ✅ Tested components
- 🎪 Built on top of TailwindCSS and Shadcn/UI
Installation
Make sure you have the peer dependencies installed:
npm install vue@^3.3.0 tailwindcss@^3.0.0
Setup
1. Add CSS
Import the component library styles in your main entry file:
import '@unraid/ui/style.css';
2. Configure TailwindCSS
Create a tailwind.config.ts file with the following configuration:
import tailwindConfig from '@unraid/ui/tailwind.config.ts';
import type { Config } from 'tailwindcss';
export default {
presets: [tailwindConfig],
content: [
// ... your content paths
'./components/**/*.{js,vue,ts}',
'./layouts/**/*.vue',
'./pages/**/*.vue',
],
theme: {
extend: {
// your theme extensions
},
},
} satisfies Partial<Config>;
This configuration:
- Uses the Unraid UI library's Tailwind config as a preset
- Properly types your configuration with TypeScript
- Allows you to extend the base theme while maintaining all Unraid UI defaults
Usage
<script setup lang="ts">
import { Button } from '@unraid/ui';
</script>
<template>
<Button variant="primary"> Click me </Button>
</template>
Development
Local Development
Install dependencies:
npm install
Start Storybook development server:
npm run storybook
This will start Storybook at http://localhost:6006
Building
npm run build
Testing
Run tests:
npm run test
Run tests with UI:
npm run test:ui
Generate coverage report:
npm run coverage
Type Checking
npm run typecheck
Scripts
dev: Start development serverbuild: Build for productionpreview: Preview production buildtest: Run teststest:ui: Run tests with UIcoverage: Generate test coverageclean: Remove build artifactstypecheck: Run type checkingstorybook: Start Storybook development serverbuild-storybook: Build Storybook for production
License
Component Development
Installing Shadcn Components
- Install a new component using the Shadcn CLI:
npx shadcn-vue@latest add [component-name]
-
The component will be installed in the root components folder. Move it to the appropriate subfolder based on its type:
- Form components →
src/components/form/ - Layout components →
src/components/layout/ - Common components →
src/components/common/ - Brand components →
src/components/brand/
- Form components →
-
Update any imports in your codebase to reflect the new component location.
Component Variants Pattern
We use the class-variance-authority (CVA) package to manage component variants. Each component that supports variants should follow this pattern:
- Create a variants file (e.g.,
button.variants.ts):
import { cva } from 'class-variance-authority';
export const buttonVariants = cva('base-classes-here', {
variants: {
variant: {
primary: 'variant-specific-classes',
secondary: 'variant-specific-classes',
// ... other variants
},
size: {
sm: 'size-specific-classes',
md: 'size-specific-classes',
lg: 'size-specific-classes',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
});
- Use the variants in your component (e.g.,
Button.vue):
<script setup lang="ts">
import { computed } from "vue";
import { buttonVariants } from "./button.variants";
import { cn } from "@/lib/utils";
export interface ButtonProps {
variant?: "primary" | "secondary" | /* other variants */;
size?: "sm" | "md" | "lg";
class?: string;
}
const props = withDefaults(defineProps<ButtonProps>(), {
variant: "primary",
size: "md",
});
const buttonClass = computed(() => {
return cn(
buttonVariants({ variant: props.variant, size: props.size }),
props.class
);
});
</script>
<template>
<button :class="buttonClass">
<slot />
</button>
</template>
Storybook Development
We use Storybook for component development and documentation. To start the Storybook development server:
npm run storybook
This will start Storybook at http://localhost:6006
When creating stories for your components:
- Place story files in the
storiesdirectory - Name your story files as
ComponentName.stories.ts - Include examples of all variants and states
- Add documentation using JSDoc comments
Example story file:
import type { Meta, StoryObj } from '@storybook/vue3';
import { Button } from '../src/components/common/button';
const meta = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline'],
},
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
},
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
variant: 'primary',
size: 'md',
},
};
export const Secondary: Story = {
args: {
variant: 'secondary',
size: 'md',
},
};