Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/release/legacy-analyzer.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { filterLegacyCommits } = require('./legacy-commits.cjs')
exports.analyzeCommits = async function (config, context) {
const { analyzeCommits } = await import('@semantic-release/commit-analyzer')
return analyzeCommits(config, { ...context, commits: filterLegacyCommits(context) })
}
11 changes: 11 additions & 0 deletions .github/release/legacy-commits.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { execFileSync } = require('node:child_process')
exports.filterLegacyCommits = function (context) {
return context.commits.filter(commit => {
if (/^[a-z]+\(coderocket(?:[-/][^)]+)?\)!?:/i.test(commit.message)) return false
if (!/^[a-f0-9]{7,40}$/i.test(commit.hash || '')) return true
try {
const files = execFileSync('git', ['diff-tree', '--root', '--no-commit-id', '--name-only', '-r', commit.hash], { cwd: context.cwd, encoding: 'utf8' }).trim().split('\n').filter(Boolean)
return !files.length || !files.every(file => file.startsWith('coderocket/') || /^\.github\/workflows\/coderocket-/.test(file))
} catch { return true }
})
}
5 changes: 5 additions & 0 deletions .github/release/legacy-notes.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { filterLegacyCommits } = require('./legacy-commits.cjs')
exports.generateNotes = async function (config, context) {
const { generateNotes } = await import('@semantic-release/release-notes-generator')
return generateNotes(config, { ...context, commits: filterLegacyCommits(context) })
}
35 changes: 35 additions & 0 deletions .github/workflows/coderocket-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CodeRocket checks
on:
pull_request:
push:
branches: [main, 'codex/coderocket-ui']
paths: ['coderocket/**', '.github/release/**', '.github/workflows/coderocket-ci.yml']
workflow_dispatch:
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
defaults:
run:
working-directory: coderocket
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: '24'
cache: npm
cache-dependency-path: coderocket/package-lock.json
- run: npm ci
- run: npm run build
- run: npm run typecheck
- run: npm test
- run: npm run check:package
- run: npx playwright install --with-deps chromium
- run: npm run test:browser
- uses: actions/upload-artifact@v7
if: failure()
with:
name: coderocket-browser-results
path: coderocket/test-results
retention-days: 7
41 changes: 41 additions & 0 deletions .github/workflows/coderocket-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: CodeRocket release
on:
push:
tags: ['coderocket-v*']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: coderocket-release
cancel-in-progress: false
jobs:
publish:
if: startsWith(github.ref, 'refs/tags/coderocket-v')
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
defaults:
run:
working-directory: coderocket
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: '24'
registry-url: https://registry.npmjs.org
cache: npm
cache-dependency-path: coderocket/package-lock.json
- run: npm ci
- name: Verify tag matches package version
run: node -e "const p=require('./packages/vue/package.json');if(process.env.GITHUB_REF_NAME!=='coderocket-v'+p.version)process.exit(1)"
- run: npm run build && npm run typecheck && npm test && npm run check:package
- name: Publish through npm trusted publishing
run: npm publish -w @coderocketapp/vue --access public --provenance
- name: Prepare downloadable package
run: mkdir -p artifacts && npm pack -w @coderocketapp/vue --pack-destination artifacts
- uses: actions/upload-artifact@v7
with:
name: coderocket-vue
path: coderocket/artifacts/*.tgz
retention-days: 90
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: Release
on:
workflow_dispatch:
push:
paths-ignore:
- "coderocket/**"
- ".github/workflows/coderocket-*.yml"
branches:
- main
- develop
Expand Down
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ node_modules
dist
dist-ssr
coverage
.private/
.env
.env.*
!.env.example
.netlify/
playwright-report/
test-results/
*.local

/cypress/videos/
Expand All @@ -29,4 +36,8 @@ coverage

# vitepress
docs/.vitepress/cache
docs/.vitepress/dist
docs/.vitepress/dist

# CodeRocket documentation and release artifacts
coderocket/apps/docs/.vitepress/cache/
coderocket/artifacts/
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

A date and date range picker for Vue 3, styled with Tailwind CSS.

## CodeRocket UI pilot

[CodeRocket UI](https://ui.coderocket.app/) is the next chapter of this repository: a new MIT Vue library for dates and time, with an optional Availability Pro extension. It is developed independently in [`coderocket/`](./coderocket/) and has its own versions and releases. The existing datepicker below keeps its current API and package.

[Read the announcement](./coderocket/ANNOUNCEMENT.md) · [New documentation](https://ui.coderocket.app/docs/)

## Maintained package

The maintained package is now **`@coderocketapp/vue-tailwind-datepicker`**.
Expand Down
1 change: 1 addition & 0 deletions coderocket/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
9 changes: 9 additions & 0 deletions coderocket/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
**/dist
**/.vitepress/cache
package-lock.json
test-results
playwright-report
artifacts
deliveries
vendor
6 changes: 6 additions & 0 deletions coderocket/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 110,
"htmlWhitespaceSensitivity": "ignore"
}
17 changes: 17 additions & 0 deletions coderocket/ANNOUNCEMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Introducing CodeRocket UI

Vue Tailwind Datepicker is opening a new chapter: CodeRocket UI, a focused Vue library for dates, time and availability.

The project continues in this repository. Its history, issues and community stay here. The existing `@coderocketapp/vue-tailwind-datepicker` package and documentation remain available, with no automatic migration or API replacement.

The new `@coderocketapp/vue` package provides a fresh MIT foundation: date pickers, date ranges, time fields and headless primitives, with typed values and customisable styling.

Availability Pro is an optional commercial extension for recurring availability, date exceptions and time zones. An optional AI integration prepares suggestions that users can review and confirm. The components work fully without AI.

The initial release is a pilot. We are looking for teams building real scheduling features to try the integration and help shape what comes next.

- Documentation and examples: https://ui.coderocket.app/docs/
- Pro demo and launch offer: https://ui.coderocket.app/#availability
- Original datepicker: https://vue-tailwind-datepicker.com/

Thank you to everyone who has contributed to the datepicker. Its existing MIT license and original attributions are preserved.
57 changes: 57 additions & 0 deletions coderocket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# CodeRocket UI

A fresh Vue foundation for dates, time and availability, developed in the original Vue Tailwind Datepicker repository.

- **Free, MIT:** `@coderocketapp/vue`, date picker, ranges, time picker, headless primitives.
- **Commercial:** Availability Pro, maintained in the private `elreco/coderocket-ui-pro` repository.
- **Legacy:** the root package `@coderocketapp/vue-tailwind-datepicker` keeps its own API and publication workflow.

## Develop

Use Node 24 LTS, then run from this directory:

```sh
npm ci
npm run build:lib
npm run dev
npm run typecheck
npm test
npm run build
npm run check:package -- --nuxt
npx playwright install chromium
npm run test:browser
```

Public site: `apps/site`. VitePress documentation: `apps/docs`, copied under `/docs/` by the build. No Pro source belongs in this workspace. For a local Pro iframe, set `VITE_PRO_DEMO_URL=http://127.0.0.1:4181` before building the site.

## Toolchain choices

Vue 3.5, Vite 8, Tailwind 4, Reka 2 and the framework-independent `@internationalized/date`. Versions are pinned in the lockfile. TypeScript 7 is installed with the official TypeScript 6 compiler-API bridge required by Vue's declaration tooling. VitePress stays on its stable 1.6 release with a patched Vite 7 dependency override; the documentation build and browser tests cover this compatibility choice.

## Releases remain independent

Use the conventional-commit scope `coderocket` for new-product work. The legacy analyzer and release notes exclude this scope and commits touching only this directory or its dedicated workflows. Legacy npm trust remains attached to `release.yml`.

CodeRocket releases use tags `coderocket-v<package version>` and `.github/workflows/coderocket-release.yml`. A tag must match `packages/vue/package.json`. There is no automatic legacy major upgrade.

The first npm publication of `@coderocketapp/vue` must be bootstrapped by its owner, then configure npm trusted publishing for owner `elreco`, repository `vue-tailwind-datepicker`, workflow `coderocket-release.yml`, with no environment. Subsequent matching tags publish via OIDC; never add a long-lived npm token to CI.

## Deploy

Create a separate Netlify project with base directory `coderocket`, configuration `coderocket/netlify.toml`, command `npm ci && npm run build`, publish `apps/site/dist`, Node 24. Set `VITE_PRO_DEMO_URL` to the private repository's deployed demo URL. Connect `ui.coderocket.app` while retaining the existing datepicker project and domain. Enable Netlify Forms detection for `pro-interest` and verify submissions in the dashboard.

Do not overwrite any pre-existing DNS record for this subdomain without checking its current use. No changes to the apex `coderocket.app` are needed.

## Initial commercial validation

The launch offer is €299 excl. VAT for five developers, perpetual use of acquired versions and twelve months of updates/bug support. Validate demand with three paying pilot customers before expanding into resource planning, monthly recurrences or calendar integrations. No automated outreach or sales platform is included.

See `ANNOUNCEMENT.md` for the prepared transition announcement.

## Pilot deployment status

The public site is https://ui.coderocket.app/ and the separately built demo is https://coderocket-availability-pro.netlify.app/. Cloudflare hosts the DNS: `ui` is a DNS-only CNAME to `coderocket-ui.netlify.app`; Netlify manages the HTTPS certificate and renewal. The original Netlify address remains available. OVH is the registrar; its nameservers and all other subdomains stay unchanged.

Private GitHub Actions is currently blocked by the account billing/spending status. All 22 Pro tests, including real Redis concurrency checks, and five browser checks have passed locally. Public GitHub CI passes. AI calls remain disabled until owner-controlled OpenAI/Upstash credentials and the monthly budget approval are configured.

While npm verification is pending, the build serves an installable MIT archive under `/downloads/`. Once npm publication is verified, set `VITE_NPM_RELEASED=true` in the public Netlify project and update the installation notice. Rendered documentation also exposes its authored Markdown and `/llms-full.txt`.
56 changes: 56 additions & 0 deletions coderocket/apps/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { defineConfig } from 'vitepress'
export default defineConfig({
title: 'CodeRocket UI',
description: 'Vue components for dates, time and availability.',
base: '/docs/',
cleanUrls: true,
head: [
[
'link',
{
rel: 'icon',
href: 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">↗</text></svg>',
},
],
],
themeConfig: {
logo: undefined,
siteTitle: 'CodeRocket UI',
search: { provider: 'local' },
nav: [
{ text: 'Website', link: 'https://ui.coderocket.app/' },
{ text: 'Original datepicker', link: 'https://vue-tailwind-datepicker.com/' },
],
socialLinks: [{ icon: 'github', link: 'https://github.com/elreco/vue-tailwind-datepicker' }],
sidebar: [
{
text: 'Start here',
items: [
{ text: 'Introduction', link: '/' },
{ text: 'Installation', link: '/guides/getting-started' },
{ text: 'Customisation', link: '/guides/customisation' },
{ text: 'Nuxt & SSR', link: '/guides/nuxt' },
{ text: 'Migration', link: '/guides/migration' },
],
},
{
text: 'Free components',
items: [
{ text: 'Date picker', link: '/components/date-picker' },
{ text: 'Date ranges', link: '/components/date-range' },
{ text: 'Time picker', link: '/components/time-picker' },
],
},
{
text: 'Availability Pro',
items: [
{ text: 'Overview & integration', link: '/pro/' },
{ text: 'Schedule model', link: '/pro/schedule' },
{ text: 'Optional AI', link: '/pro/ai' },
{ text: 'License', link: '/pro/license' },
],
},
],
footer: { message: 'Open source foundations · MIT', copyright: 'CodeRocket © 2026' },
},
})
25 changes: 25 additions & 0 deletions coderocket/apps/docs/.vitepress/theme/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
:root {
--vp-c-brand-1: #245b47;
--vp-c-brand-2: #34735a;
--vp-c-brand-3: #245b47;
--vp-c-brand-soft: #e8f0e9;
--vp-font-family-base: Inter, ui-sans-serif, system-ui, sans-serif;
}
.VPNavBarTitle .title {
font-weight: 650;
letter-spacing: -0.5px;
}
.vp-doc .cr-ui {
margin: 24px 0;
}
.vp-doc .cr-ui button {
font: inherit;
}
.vp-doc .cr-ui label {
font-size: 13px;
}
.dark {
--vp-c-brand-1: #a1cdb4;
--vp-c-brand-2: #b0dbc2;
--vp-c-brand-3: #245b47;
}
12 changes: 12 additions & 0 deletions coderocket/apps/docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import DefaultTheme from 'vitepress/theme'
import { CrDatePicker, CrDateRangePicker, CrTimePicker } from '@coderocketapp/vue'
import '@coderocketapp/vue/style.css'
import './custom.css'
export default {
...DefaultTheme,
enhanceApp({ app }: { app: any }) {
app.component('CrDatePicker', CrDatePicker)
app.component('CrDateRangePicker', CrDateRangePicker)
app.component('CrTimePicker', CrTimePicker)
},
}
33 changes: 33 additions & 0 deletions coderocket/apps/docs/components/date-picker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Date picker

<script setup>
import { ref } from 'vue'
const value = ref('2026-10-15')
</script>
<CrDatePicker v-model="value" label="Launch date" locale="en-GB" />

```vue
<CrDatePicker
v-model="date"
label="Launch date"
locale="fr-FR"
min="2026-01-01"
max="2026-12-31"
:week-starts-on="1"
/>
```

| Prop | Type / default | Behaviour |
| -------------- | ------------------------ | --------------------------------------------- |
| `modelValue` | `string \| null`, `null` | Gregorian ISO date; emits `update:modelValue` |
| `label` | `string`, `Date` | Accessible field label |
| `locale` | `string`, `en-GB` | Display language; `fr-FR` supported |
| `min`, `max` | ISO date, optional | Inclusive date bounds |
| `placeholder` | ISO date, optional | Initial visible month when empty |
| `weekStartsOn` | `0…6`, `1` | Sunday = 0, Monday = 1 |
| `disabled` | `boolean`, `false` | Prevent interaction |
| `name` | `string`, optional | Hidden form field name |

Selection closes the calendar and returns focus to the trigger. Escape dismisses it. Arrow keys navigate dates; Enter selects. Clear emits `null`. Invalid externally supplied date strings throw an explicit error instead of silently changing your data.

Slots: `trigger` receives `{ value }`; `day` receives `{ date }` as an ISO string.
22 changes: 22 additions & 0 deletions coderocket/apps/docs/components/date-range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Date ranges

<script setup>
import { ref } from 'vue'
const value = ref({start:'2026-10-19',end:'2026-10-23'})
</script>
<CrDateRangePicker v-model="value" label="First sprint" />

```vue
<script setup lang="ts">
import { ref } from 'vue'
import { CrDateRangePicker, type DateRangeValue } from '@coderocketapp/vue'
const period = ref<DateRangeValue | null>(null)
</script>
<template><CrDateRangePicker v-model="period" label="Project period" /></template>
```

Shares `label`, `locale`, `placeholder`, `min`, `max`, `disabled` and `weekStartsOn` with the date picker. `modelValue` is `{ start: 'YYYY-MM-DD', end: 'YYYY-MM-DD' } | null`.

The selected endpoints are inclusive calendar dates. A partial selection remains an internal draft; the component emits only when both endpoints are selected. Closing without completing a range preserves the last complete value. Clear emits `null`.

Use explicit conversion when translating inclusive date ranges to time intervals in your own backend.
Loading
Loading