From ae0643abc5b4e072337800551b6bc04bda5056a8 Mon Sep 17 00:00:00 2001 From: Alexandre LE CORRE Date: Wed, 16 Sep 2026 19:58:40 +0300 Subject: [PATCH 1/6] feat(coderocket): introduce Vue UI pilot with independent docs and releases --- .github/release/legacy-analyzer.cjs | 5 + .github/release/legacy-commits.cjs | 11 + .github/release/legacy-notes.cjs | 5 + .github/workflows/coderocket-ci.yml | 35 + .github/workflows/coderocket-release.yml | 41 + .github/workflows/release.yml | 3 + .gitignore | 13 +- coderocket/.nvmrc | 1 + coderocket/.prettierignore | 9 + coderocket/.prettierrc.json | 6 + coderocket/ANNOUNCEMENT.md | 17 + coderocket/README.md | 49 + coderocket/apps/docs/.vitepress/config.ts | 56 + .../apps/docs/.vitepress/theme/custom.css | 25 + .../apps/docs/.vitepress/theme/index.ts | 12 + .../apps/docs/components/date-picker.md | 33 + coderocket/apps/docs/components/date-range.md | 22 + .../apps/docs/components/time-picker.md | 22 + coderocket/apps/docs/guides/customisation.md | 44 + .../apps/docs/guides/getting-started.md | 39 + coderocket/apps/docs/guides/migration.md | 14 + coderocket/apps/docs/guides/nuxt.md | 20 + coderocket/apps/docs/index.md | 36 + coderocket/apps/docs/package.json | 14 + coderocket/apps/docs/privacy.md | 9 + coderocket/apps/docs/pro/ai.md | 29 + coderocket/apps/docs/pro/index.md | 24 + coderocket/apps/docs/pro/license.md | 13 + coderocket/apps/docs/pro/schedule.md | 40 + coderocket/apps/site/index.html | 20 + coderocket/apps/site/package.json | 14 + coderocket/apps/site/public/thanks.html | 33 + coderocket/apps/site/src/App.vue | 301 ++ coderocket/apps/site/src/main.ts | 5 + coderocket/apps/site/src/style.css | 968 +++++ coderocket/apps/site/tsconfig.json | 5 + coderocket/apps/site/vite.config.ts | 3 + coderocket/examples/nuxt/README.md | 3 + coderocket/examples/nuxt/app/app.vue | 16 + coderocket/examples/nuxt/nuxt.config.ts | 1 + coderocket/examples/nuxt/package.json | 16 + coderocket/examples/vue/App.vue | 16 + coderocket/examples/vue/README.md | 3 + coderocket/examples/vue/index.html | 1 + coderocket/examples/vue/main.ts | 4 + coderocket/examples/vue/package.json | 18 + coderocket/examples/vue/vite.config.ts | 3 + coderocket/netlify.toml | 14 + coderocket/package-lock.json | 3488 +++++++++++++++++ coderocket/package.json | 45 + coderocket/packages/vue/LICENSE | 23 + coderocket/packages/vue/README.md | 25 + coderocket/packages/vue/package.json | 49 + .../vue/src/components/CrDatePicker.vue | 130 + .../vue/src/components/CrDateRangePicker.vue | 154 + .../vue/src/components/CrTimePicker.vue | 51 + coderocket/packages/vue/src/core.ts | 34 + coderocket/packages/vue/src/headless.ts | 38 + coderocket/packages/vue/src/index.ts | 6 + coderocket/packages/vue/src/style.css | 172 + coderocket/packages/vue/tsconfig.json | 15 + coderocket/packages/vue/vite.config.ts | 23 + coderocket/playwright.config.ts | 14 + coderocket/scripts/check-package.mjs | 113 + coderocket/scripts/copy-docs.mjs | 2 + coderocket/scripts/typecheck.cjs | 2 + coderocket/tests/browser/components.spec.ts | 72 + coderocket/tests/components.test.ts | 31 + coderocket/tests/release-isolation.test.ts | 15 + coderocket/vitest.config.ts | 6 + package.json | 4 +- tsconfig.json | 2 + 72 files changed, 6602 insertions(+), 3 deletions(-) create mode 100644 .github/release/legacy-analyzer.cjs create mode 100644 .github/release/legacy-commits.cjs create mode 100644 .github/release/legacy-notes.cjs create mode 100644 .github/workflows/coderocket-ci.yml create mode 100644 .github/workflows/coderocket-release.yml create mode 100644 coderocket/.nvmrc create mode 100644 coderocket/.prettierignore create mode 100644 coderocket/.prettierrc.json create mode 100644 coderocket/ANNOUNCEMENT.md create mode 100644 coderocket/README.md create mode 100644 coderocket/apps/docs/.vitepress/config.ts create mode 100644 coderocket/apps/docs/.vitepress/theme/custom.css create mode 100644 coderocket/apps/docs/.vitepress/theme/index.ts create mode 100644 coderocket/apps/docs/components/date-picker.md create mode 100644 coderocket/apps/docs/components/date-range.md create mode 100644 coderocket/apps/docs/components/time-picker.md create mode 100644 coderocket/apps/docs/guides/customisation.md create mode 100644 coderocket/apps/docs/guides/getting-started.md create mode 100644 coderocket/apps/docs/guides/migration.md create mode 100644 coderocket/apps/docs/guides/nuxt.md create mode 100644 coderocket/apps/docs/index.md create mode 100644 coderocket/apps/docs/package.json create mode 100644 coderocket/apps/docs/privacy.md create mode 100644 coderocket/apps/docs/pro/ai.md create mode 100644 coderocket/apps/docs/pro/index.md create mode 100644 coderocket/apps/docs/pro/license.md create mode 100644 coderocket/apps/docs/pro/schedule.md create mode 100644 coderocket/apps/site/index.html create mode 100644 coderocket/apps/site/package.json create mode 100644 coderocket/apps/site/public/thanks.html create mode 100644 coderocket/apps/site/src/App.vue create mode 100644 coderocket/apps/site/src/main.ts create mode 100644 coderocket/apps/site/src/style.css create mode 100644 coderocket/apps/site/tsconfig.json create mode 100644 coderocket/apps/site/vite.config.ts create mode 100644 coderocket/examples/nuxt/README.md create mode 100644 coderocket/examples/nuxt/app/app.vue create mode 100644 coderocket/examples/nuxt/nuxt.config.ts create mode 100644 coderocket/examples/nuxt/package.json create mode 100644 coderocket/examples/vue/App.vue create mode 100644 coderocket/examples/vue/README.md create mode 100644 coderocket/examples/vue/index.html create mode 100644 coderocket/examples/vue/main.ts create mode 100644 coderocket/examples/vue/package.json create mode 100644 coderocket/examples/vue/vite.config.ts create mode 100644 coderocket/netlify.toml create mode 100644 coderocket/package-lock.json create mode 100644 coderocket/package.json create mode 100644 coderocket/packages/vue/LICENSE create mode 100644 coderocket/packages/vue/README.md create mode 100644 coderocket/packages/vue/package.json create mode 100644 coderocket/packages/vue/src/components/CrDatePicker.vue create mode 100644 coderocket/packages/vue/src/components/CrDateRangePicker.vue create mode 100644 coderocket/packages/vue/src/components/CrTimePicker.vue create mode 100644 coderocket/packages/vue/src/core.ts create mode 100644 coderocket/packages/vue/src/headless.ts create mode 100644 coderocket/packages/vue/src/index.ts create mode 100644 coderocket/packages/vue/src/style.css create mode 100644 coderocket/packages/vue/tsconfig.json create mode 100644 coderocket/packages/vue/vite.config.ts create mode 100644 coderocket/playwright.config.ts create mode 100644 coderocket/scripts/check-package.mjs create mode 100644 coderocket/scripts/copy-docs.mjs create mode 100644 coderocket/scripts/typecheck.cjs create mode 100644 coderocket/tests/browser/components.spec.ts create mode 100644 coderocket/tests/components.test.ts create mode 100644 coderocket/tests/release-isolation.test.ts create mode 100644 coderocket/vitest.config.ts diff --git a/.github/release/legacy-analyzer.cjs b/.github/release/legacy-analyzer.cjs new file mode 100644 index 0000000..c53aa74 --- /dev/null +++ b/.github/release/legacy-analyzer.cjs @@ -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) }) +} diff --git a/.github/release/legacy-commits.cjs b/.github/release/legacy-commits.cjs new file mode 100644 index 0000000..8e3b83e --- /dev/null +++ b/.github/release/legacy-commits.cjs @@ -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 } + }) +} diff --git a/.github/release/legacy-notes.cjs b/.github/release/legacy-notes.cjs new file mode 100644 index 0000000..6a8ec15 --- /dev/null +++ b/.github/release/legacy-notes.cjs @@ -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) }) +} diff --git a/.github/workflows/coderocket-ci.yml b/.github/workflows/coderocket-ci.yml new file mode 100644 index 0000000..4040fe0 --- /dev/null +++ b/.github/workflows/coderocket-ci.yml @@ -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 diff --git a/.github/workflows/coderocket-release.yml b/.github/workflows/coderocket-release.yml new file mode 100644 index 0000000..4f2901f --- /dev/null +++ b/.github/workflows/coderocket-release.yml @@ -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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 169adf6..431bcb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,9 @@ name: Release on: workflow_dispatch: push: + paths-ignore: + - "coderocket/**" + - ".github/workflows/coderocket-*.yml" branches: - main - develop diff --git a/.gitignore b/.gitignore index b210070..429331b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,13 @@ node_modules dist dist-ssr coverage +.private/ +.env +.env.* +!.env.example +.netlify/ +playwright-report/ +test-results/ *.local /cypress/videos/ @@ -29,4 +36,8 @@ coverage # vitepress docs/.vitepress/cache -docs/.vitepress/dist \ No newline at end of file +docs/.vitepress/dist + +# CodeRocket documentation and release artifacts +coderocket/apps/docs/.vitepress/cache/ +coderocket/artifacts/ diff --git a/coderocket/.nvmrc b/coderocket/.nvmrc new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/coderocket/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/coderocket/.prettierignore b/coderocket/.prettierignore new file mode 100644 index 0000000..8202de8 --- /dev/null +++ b/coderocket/.prettierignore @@ -0,0 +1,9 @@ +node_modules +**/dist +**/.vitepress/cache +package-lock.json +test-results +playwright-report +artifacts +deliveries +vendor diff --git a/coderocket/.prettierrc.json b/coderocket/.prettierrc.json new file mode 100644 index 0000000..9496cb2 --- /dev/null +++ b/coderocket/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "semi": false, + "singleQuote": true, + "printWidth": 110, + "htmlWhitespaceSensitivity": "ignore" +} diff --git a/coderocket/ANNOUNCEMENT.md b/coderocket/ANNOUNCEMENT.md new file mode 100644 index 0000000..6cad0d3 --- /dev/null +++ b/coderocket/ANNOUNCEMENT.md @@ -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. diff --git a/coderocket/README.md b/coderocket/README.md new file mode 100644 index 0000000..e960234 --- /dev/null +++ b/coderocket/README.md @@ -0,0 +1,49 @@ +# 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` 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. diff --git a/coderocket/apps/docs/.vitepress/config.ts b/coderocket/apps/docs/.vitepress/config.ts new file mode 100644 index 0000000..de1ac59 --- /dev/null +++ b/coderocket/apps/docs/.vitepress/config.ts @@ -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,↗', + }, + ], + ], + 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' }, + }, +}) diff --git a/coderocket/apps/docs/.vitepress/theme/custom.css b/coderocket/apps/docs/.vitepress/theme/custom.css new file mode 100644 index 0000000..980c270 --- /dev/null +++ b/coderocket/apps/docs/.vitepress/theme/custom.css @@ -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; +} diff --git a/coderocket/apps/docs/.vitepress/theme/index.ts b/coderocket/apps/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..191b6a4 --- /dev/null +++ b/coderocket/apps/docs/.vitepress/theme/index.ts @@ -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) + }, +} diff --git a/coderocket/apps/docs/components/date-picker.md b/coderocket/apps/docs/components/date-picker.md new file mode 100644 index 0000000..ec8379a --- /dev/null +++ b/coderocket/apps/docs/components/date-picker.md @@ -0,0 +1,33 @@ +# Date picker + + + + +```vue + +``` + +| 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. diff --git a/coderocket/apps/docs/components/date-range.md b/coderocket/apps/docs/components/date-range.md new file mode 100644 index 0000000..6a6aad9 --- /dev/null +++ b/coderocket/apps/docs/components/date-range.md @@ -0,0 +1,22 @@ +# Date ranges + + + + +```vue + + +``` + +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. diff --git a/coderocket/apps/docs/components/time-picker.md b/coderocket/apps/docs/components/time-picker.md new file mode 100644 index 0000000..f21cc2b --- /dev/null +++ b/coderocket/apps/docs/components/time-picker.md @@ -0,0 +1,22 @@ +# Time picker + + + + +```vue + +``` + +| Prop | Type / default | +| ------------ | ------------------------------- | +| `modelValue` | `string \| null`, `null` | +| `label` | `string`, localised “Time” | +| `locale` | `string`, `en-GB` | +| `hourCycle` | `12 \| 24`, `24` | +| `disabled` | `boolean`, `false` | +| `name` | optional hidden form field name | + +The stored value is always `HH:mm` with minute precision and a 24-hour clock, regardless of display settings. It has no date, offset or timezone. Incomplete input does not invent a full time. Each segment supports keyboard entry and arrow-key changes. diff --git a/coderocket/apps/docs/guides/customisation.md b/coderocket/apps/docs/guides/customisation.md new file mode 100644 index 0000000..adb34c3 --- /dev/null +++ b/coderocket/apps/docs/guides/customisation.md @@ -0,0 +1,44 @@ +# Make it your own + +## Theme variables + +```css +.my-app .cr-ui { + --cr-accent: #6742a5; + --cr-accent-soft: #f0eafa; + --cr-surface: #fff; + --cr-text: #24202a; + --cr-muted: #6a6373; + --cr-border: #ddd6e6; + --cr-radius: 12px; + --cr-font: 'Your font', system-ui, sans-serif; +} +``` + +Popover content is rendered in a portal outside its original DOM ancestry. Apply theme variables to `.cr-ui` globally, or use your own headless composition when a theme must remain scoped to one subtree. Do not depend only on `.my-app` for portal styling. + +Both date components expose `trigger` (current value) and `day` (ISO date) slots. Keep accessible text in custom triggers and avoid adding nested interactive controls inside calendar day buttons. + +## Headless + +The `@coderocketapp/vue/headless` entry exports Reka calendar, range calendar, popover and time-field primitives without the CodeRocket theme. + +```ts +import { CalendarRoot, CalendarGrid, CalendarCellTrigger } from '@coderocketapp/vue/headless' +import { calendarDate } from '@coderocketapp/vue/core' +``` + +Primitive values are `@internationalized/date` objects. The styled CodeRocket components convert these to plain ISO strings. Follow [Reka's composition documentation](https://reka-ui.com/docs/components/calendar) when building your own controls. + +## Dark mode + +```css +.dark .cr-ui { + --cr-surface: #18251f; + --cr-text: #e9f0eb; + --cr-muted: #a1b4a8; + --cr-border: #385345; + --cr-accent: #397957; + --cr-accent-soft: #233e2e; +} +``` diff --git a/coderocket/apps/docs/guides/getting-started.md b/coderocket/apps/docs/guides/getting-started.md new file mode 100644 index 0000000..2f76c1d --- /dev/null +++ b/coderocket/apps/docs/guides/getting-started.md @@ -0,0 +1,39 @@ +# Installation + +Requires Vue 3.5 or later in the Vue 3 line. Tailwind is optional: the supplied stylesheet is already compiled and does not include a global reset. + +```sh +npm install @coderocketapp/vue +``` + +```ts +import { CrDatePicker, CrDateRangePicker, CrTimePicker } from '@coderocketapp/vue' +import '@coderocketapp/vue/style.css' +``` + +Import the CSS once in your application entry. Components are named exports; there is no global plugin to install. The package is ESM and includes TypeScript declarations. + +## Before the first npm release + +Build and install the local archive: + +```sh +cd coderocket +npm ci +npm run build:lib +npm pack -w @coderocketapp/vue +# In your consuming app: +npm install /absolute/path/to/coderocketapp-vue-0.1.0.tgz +``` + +Do not assume the package is published until the release workflow or npm confirms it. + +## Forms + +`CrDatePicker` and `CrTimePicker` accept a `name` prop and submit an ISO date or clock time through a hidden input. The range component exposes `{ start, end }`; submit those values using your application's form handling. + +Labels should describe the field. Provide a label even if you replace the trigger using a slot. + +## Complete applications + +Download the [Vue example](https://github.com/elreco/vue-tailwind-datepicker/tree/main/coderocket/examples/vue) or the [Nuxt example](https://github.com/elreco/vue-tailwind-datepicker/tree/main/coderocket/examples/nuxt). Each includes its package manifest, application and build configuration. Neither requires Tailwind. diff --git a/coderocket/apps/docs/guides/migration.md b/coderocket/apps/docs/guides/migration.md new file mode 100644 index 0000000..a390776 --- /dev/null +++ b/coderocket/apps/docs/guides/migration.md @@ -0,0 +1,14 @@ +# A new chapter, at your pace + +CodeRocket UI is a new API in the same public repository. It does not replace your installed datepicker automatically. + +| Existing project | New foundation | +| ---------------------------------------- | ------------------------------- | +| `@coderocketapp/vue-tailwind-datepicker` | `@coderocketapp/vue` | +| Existing Day.js and formatting API | ISO dates and local clock times | +| Original stylesheet | `@coderocketapp/vue/style.css` | +| Original documentation | CodeRocket UI documentation | + +Keep using the original component while evaluating the new one in a separate screen. Convert values at your application boundary; a formatted display string is not necessarily an ISO date. Do not replace imports without adapting your models and testing locale behaviour. + +[Original installation guide](https://vue-tailwind-datepicker.com/installation.html) diff --git a/coderocket/apps/docs/guides/nuxt.md b/coderocket/apps/docs/guides/nuxt.md new file mode 100644 index 0000000..d2cccad --- /dev/null +++ b/coderocket/apps/docs/guides/nuxt.md @@ -0,0 +1,20 @@ +# Nuxt and server rendering + +Install `@coderocketapp/vue` and add its CSS once: + +```ts +// nuxt.config.ts +export default defineNuxtConfig({ css: ['@coderocketapp/vue/style.css'] }) +``` + +```vue + + +``` + +Pass explicit initial values and locale so server and browser render the same content. Calendar popovers render when opened; an unopened control does not require a browser-only wrapper. + +Availability Pro additionally requires an explicit `today` ISO date. Compute it once for the request in the schedule's timezone and pass the same value to server and client. Its pure scheduling functions are available through `/core`, without importing Vue. diff --git a/coderocket/apps/docs/index.md b/coderocket/apps/docs/index.md new file mode 100644 index 0000000..0e6ddc1 --- /dev/null +++ b/coderocket/apps/docs/index.md @@ -0,0 +1,36 @@ +# Make time work. + +CodeRocket UI is a Vue library for dates, clock times and availability. Use the ready-to-use components or compose your own interface from headless primitives. + +**The date, range and time components are MIT licensed.** Availability Pro is an optional commercial extension. The library works without AI or a CodeRocket account. + +CodeRocket grows in the existing [Vue Tailwind Datepicker repository](https://github.com/elreco/vue-tailwind-datepicker). The original `@coderocketapp/vue-tailwind-datepicker` package retains its own API and release cycle. + +[Install the library →](./guides/getting-started) + +## A first example + + + + + +Current ISO value: `{{ date }}` + +```vue + + +``` + +## What is stable in the model? + +Dates are Gregorian `YYYY-MM-DD` strings. Clock times are local `HH:mm` strings. A timezone belongs to an availability schedule, not to a date-only selection. Display formatting never changes the stored value. + +The initial release is **0.1**, a pilot release. Pin your dependency until the first stable 1.0 release. diff --git a/coderocket/apps/docs/package.json b/coderocket/apps/docs/package.json new file mode 100644 index 0000000..d793bf5 --- /dev/null +++ b/coderocket/apps/docs/package.json @@ -0,0 +1,14 @@ +{ + "name": "@coderocketapp/docs", + "private": true, + "type": "module", + "scripts": { + "dev": "vitepress dev .", + "build": "vitepress build ." + }, + "dependencies": { + "@coderocketapp/vue": "0.1.0", + "vue": "3.5.42", + "vitepress": "1.6.4" + } +} diff --git a/coderocket/apps/docs/privacy.md b/coderocket/apps/docs/privacy.md new file mode 100644 index 0000000..2e2e9f5 --- /dev/null +++ b/coderocket/apps/docs/privacy.md @@ -0,0 +1,9 @@ +# Privacy + +CodeRocket's contact form collects your name or company, email and project description to respond to your enquiry. Submissions are processed by Netlify Forms and accessed by CodeRocket for that purpose. Please do not send passwords, API keys or confidential customer data. + +The optional AI demonstration sends the text you enter, the displayed schedule, language and reference date to OpenAI to prepare a suggestion. CodeRocket does not store the prompt in application logs. The request disables provider-side response storage where supported; provider security and abuse-monitoring policies may still apply. + +The demo uses an expiring keyed hash of the client IP to enforce quotas in Upstash Redis. Raw IPs and prompts are not stored in our quota database. Hosting providers may keep their own operational access logs. + +No advertising or third-party analytics scripts are included. To request deletion of a contact submission, submit a new contact enquiry identifying the previous submission. Unconverted enquiries are intended to be removed after twelve months; deletion is an operational task, not an automatic feature of this site. diff --git a/coderocket/apps/docs/pro/ai.md b/coderocket/apps/docs/pro/ai.md new file mode 100644 index 0000000..e82d741 --- /dev/null +++ b/coderocket/apps/docs/pro/ai.md @@ -0,0 +1,29 @@ +# Optional AI, your backend + +The availability editor works fully without AI. To add natural-language input, pass an `interpret` function. Never include provider credentials in browser code. + +```ts +import type { AvailabilityInterpreter } from '@coderocketapp/availability-pro' +const interpret: AvailabilityInterpreter = async (text, context) => { + const response = await fetch('/api/availability/interpret', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ text, ...context }), + }) + if (!response.ok) throw new Error('Suggestions are temporarily unavailable.') + return response.json() +} +``` + +The callback returns one of: + +```ts +{ kind:'proposal', schedule:validSchedule, explanation:'What changed' } +{ kind:'clarification', question:'Which holiday dates should be excluded?' } +``` + +The component validates proposals again and displays them before applying any change. The user must confirm. If the schedule changes while a request is in flight, the stale response is rejected. Editing a schedule also dismisses an older unaccepted proposal. + +On your server: authenticate your users, validate input and generated output, enforce your own quotas, and never execute generated code. The callback does not call CodeRocket services. You own the provider selection and API bill. + +Our public demonstration has shared and per-visitor quotas. If its AI is unavailable, manual editing and example schedules remain available. diff --git a/coderocket/apps/docs/pro/index.md b/coderocket/apps/docs/pro/index.md new file mode 100644 index 0000000..0bcc8e1 --- /dev/null +++ b/coderocket/apps/docs/pro/index.md @@ -0,0 +1,24 @@ +# Availability Pro + +A commercial Vue editor for weekly availability, alternating weeks, multiple time windows and date-specific exceptions. The editor, validation and occurrence engine are delivered with TypeScript declarations and source. + +```vue + + +``` + +The editor requires `modelValue` and `today`. Optional props: `locale` (default `en-GB`), `disabled`, and `interpret` for your own AI backend. It emits `update:modelValue` only for valid models, and `validation` with the current error list. Invalid edits remain visible until corrected. + +`preview-footer` receives occurrences and diagnostics. `footer` receives the draft value and its validity. The preview covers 30 days beginning at the later of `today` and the schedule start date. + +No booking storage, payment processing or calendar-provider integration is included. Your application persists schedules and decides how users book appointments. + +[See pricing and request a license](https://ui.coderocket.app/#contact). diff --git a/coderocket/apps/docs/pro/license.md b/coderocket/apps/docs/pro/license.md new file mode 100644 index 0000000..03c1ed7 --- /dev/null +++ b/coderocket/apps/docs/pro/license.md @@ -0,0 +1,13 @@ +# Availability Pro license + +**Launch offer: €299 excluding VAT per team, up to five developers.** Purchases are handled manually by quote and invoice. + +The license permits use of acquired versions in your own applications and in client applications you deliver. It includes source access, perpetual use of acquired versions, twelve months of updates and bug support, without a guaranteed response time. + +It does not permit repackaging or redistributing Pro as a reusable component library, template library or competing development toolkit. Client delivery does not transfer a separate reusable Pro toolkit license. + +The purchased archive includes the full applicable license. MIT dependencies and the free CodeRocket components retain their own licenses. Free components do not become commercial because you use them alongside Pro. + +This page describes the launch offer. Your quote identifies the purchasing entity, developer allowance and start of the update period. Contact us before purchasing if your team or redistribution needs exceed this offer. + +[Discuss your project](https://ui.coderocket.app/#contact). diff --git a/coderocket/apps/docs/pro/schedule.md b/coderocket/apps/docs/pro/schedule.md new file mode 100644 index 0000000..67174f9 --- /dev/null +++ b/coderocket/apps/docs/pro/schedule.md @@ -0,0 +1,40 @@ +# Schedule model + +Version 1 uses a Gregorian start date, optional inclusive end date, an IANA timezone and a weekly pattern. + +```ts +const schedule = { + version: 1, + timeZone: 'Europe/Paris', + startDate: '2026-10-01', + endDate: '2026-10-31', + intervalWeeks: 2, + weekly: [ + { day: 2, slots: [{ start: '09:00', end: '12:00' }] }, + { day: 4, slots: [{ start: '09:00', end: '12:00' }] }, + ], + exceptions: [{ date: '2026-10-15', slots: [] }], +} +``` + +Weekdays use ISO numbering: Monday 1 through Sunday 7. Alternating weeks are anchored to the Monday of the week containing `startDate`. Dates earlier than `startDate` are excluded. + +A date exception replaces the entire day's usual availability, even in a normally inactive week. An empty exception closes the day. Slots are local `HH:mm` values in the schedule timezone; start is inclusive and end exclusive. Adjacent slots are allowed; overlapping, reversed and overnight slots are rejected. Endpoints must be between 00:00 and 23:59 in this version. + +## Server-side usage + +```ts +import { validateAvailability, expandAvailability } from '@coderocketapp/availability-pro/core' +const validation = validateAvailability(requestBody) +if (!validation.success) return validation.issues +const { occurrences, diagnostics } = expandAvailability(validation.data, { + from: '2026-10-01', + to: '2026-10-31', +}) +``` + +Every occurrence contains its local date and clock times, IANA timezone, and UTC start/end instants. The preview window is inclusive and limited to 366 days. Calculation is independent of the server's own timezone. + +Ambiguous or nonexistent local-time boundaries during clock changes produce diagnostics and omit the affected slot. They are never silently shifted. Show diagnostics to the user and let them add an explicit date override. + +Limits: 7 weekday entries, 12 windows per day, 100 date exceptions, interval 1–52 weeks. Duplicate days or exception dates are invalid; exceptions must lie within the schedule period. diff --git a/coderocket/apps/site/index.html b/coderocket/apps/site/index.html new file mode 100644 index 0000000..2f60982 --- /dev/null +++ b/coderocket/apps/site/index.html @@ -0,0 +1,20 @@ + + + + + + + CodeRocket UI — Make time work. + + + +
+ + + diff --git a/coderocket/apps/site/package.json b/coderocket/apps/site/package.json new file mode 100644 index 0000000..0e1bb20 --- /dev/null +++ b/coderocket/apps/site/package.json @@ -0,0 +1,14 @@ +{ + "name": "@coderocketapp/site", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --host 127.0.0.1 --port 4180", + "build": "vite build", + "preview": "vite preview --host 127.0.0.1 --port 4180" + }, + "dependencies": { + "@coderocketapp/vue": "0.1.0", + "vue": "3.5.42" + } +} diff --git a/coderocket/apps/site/public/thanks.html b/coderocket/apps/site/public/thanks.html new file mode 100644 index 0000000..c60dcdd --- /dev/null +++ b/coderocket/apps/site/public/thanks.html @@ -0,0 +1,33 @@ + + + + Thank you — CodeRocket UI +
+

CODEROCKET UI

+

Thanks for sharing your project.

+

Your enquiry has been submitted. We’ll get back to you using the email you provided.

+ ← Back to CodeRocket UI +
+ diff --git a/coderocket/apps/site/src/App.vue b/coderocket/apps/site/src/App.vue new file mode 100644 index 0000000..2adef96 --- /dev/null +++ b/coderocket/apps/site/src/App.vue @@ -0,0 +1,301 @@ + +