# Contributing to @ocelot-social/ui | Ocelot.Social Documentation
Ocelot.Social Documentation

Skip to main content

- Introduction
- Neo4J

- Backend

  - GraphQL
  - neo4j-graphql-js

- Webapp (Frontend)

  - Components
  - HTML
  - SCSS
  - Vue

- Testing Guide

  - End-to-end Tests
  - Webapp (Frontend) Tests
  - Backend Tests
- Deployment
- Contributing
- Feature Specification
- Code of Conduct
- Documentation
- License

# Contributing to @ocelot-social/ui

April 5, 2026
About 2 min

On This Page

- Development Setup
- Creating a New Component
- - File Structure
  - Naming Convention
  - Component Template
- Code Standards
- - TypeScript
  - Props
  - Styling
  - Vue 2/3 Compatibility
- Testing
- - Requirements
  - Writing Tests
  - Running Tests
- Commit Conventions
- Pull Request Checklist
- Example Apps
- Questions?

# Contributing to @ocelot-social/ui

Thank you for contributing to the ocelot.social UI library!

## Development Setup

    # Install dependencies
    npm install

    # Start development server
    npm run dev

    # Run tests
    npm test

    # Run linter
    npm run lint

## Creating a New Component

### File Structure

    src/components/
    └── OsButton/
        ├── OsButton.vue       # Component
        ├── OsButton.spec.ts   # Tests
        └── index.ts           # Export

### Naming Convention

- All components use the `Os` prefix: `OsButton`, `OsCard`, `OsModal`
- Files use PascalCase: `OsButton.vue`

### Component Template

    <script setup lang="ts">
    import { computed } from 'vue-demi'

    import type { Size, Variant } from '@/types'

    interface Props {
      /** Button size */
      size?: Size
      /** Visual variant */
      variant?: Variant
    }

    const props = withDefaults(defineProps<Props>(), {
      size: 'md',
      variant: 'primary',
    })

    const classes = computed(() => [
      'os-button',
      `os-button--${props.size}`,
      `os-button--${props.variant}`,
    ])
    </script>

    <template>
      <button :class="classes">
        <slot />
      </button>
    </template>

## Code Standards

### TypeScript

- `strict: true` is enabled
- All props must be typed
- Use JSDoc comments for documentation

### Props

Use the complete Tailwind-based scales:

Prop | Values
--- | ---
`size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`
`rounded` | `none`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `full`
`shadow` | `none`, `sm`, `md`, `lg`, `xl`, `2xl`
`variant` | `primary`, `secondary`, `danger`, `warning`, `success`, `info`

### Styling

- Use CSS Custom Properties (no hardcoded colors)
- Use Tailwind utility classes
- Dark mode via `dark:` prefix

    <template>
      <button class="bg-[--button-primary-bg] dark:bg-[--button-primary-bg-dark]">
        <slot />
      </button>
    </template>

### Vue 2/3 Compatibility

Always import from `vue-demi`, not `vue`:

    // Correct
    import { ref, computed } from 'vue-demi'

    // Wrong
    import { ref, computed } from 'vue'

## Testing

### Requirements

- 100% code coverage is required
- Tests must pass for both Vue 2.7 and Vue 3

### Writing Tests

    import { mount } from '@vue/test-utils'
    import { describe, expect, it } from 'vitest'

    import OsButton from './OsButton.vue'

    describe('OsButton', () => {
      it('renders slot content', () => {
        const wrapper = mount(OsButton, {
          slots: { default: 'Click me' },
        })
        expect(wrapper.text()).toBe('Click me')
      })

      it('applies size class', () => {
        const wrapper = mount(OsButton, {
          props: { size: 'lg' },
        })
        expect(wrapper.classes()).toContain('os-button--lg')
      })
    })

### Running Tests

    # Run once
    npm test

    # Watch mode
    npm run test:watch

    # With coverage
    npm run test:coverage

## Commit Conventions

We use Conventional Commits for automatic releases:

    # Features (minor version bump)
    feat(button): add loading state

    # Bug fixes (patch version bump)
    fix(modal): correct focus trap behavior

    # Breaking changes (major version bump)
    feat(input)!: rename value prop to modelValue

    # Other types
    docs: update README
    test: add button accessibility tests
    chore: update dependencies
    refactor: simplify dropdown logic

## Pull Request Checklist

Before submitting a PR, ensure:

- [ ] Tests pass (`npm test`)
- [ ] Linter passes (`npm run lint`)
- [ ] Build succeeds (`npm run build`)
- [ ] 100% code coverage maintained
- [ ] New components have Histoire stories
- [ ] Props have JSDoc documentation
- [ ] Commit messages follow Conventional Commits

## Example Apps

Test your changes in the example apps:

    # Vue 3 + Tailwind
    cd examples/vue3-tailwind && npm install && npm run dev

    # Vue 3 + CSS
    cd examples/vue3-css && npm install && npm run dev

    # Vue 2 + Tailwind
    cd examples/vue2-tailwind && npm install && npm run dev

    # Vue 2 + CSS
    cd examples/vue2-css && npm install && npm run dev

## Questions?

- Check the main CONTRIBUTING.md for general guidelines
- Join the Discord for questions
- Open an issue for bugs or feature requests