diff --git a/addon/components/full-calendar.hbs b/addon/components/full-calendar.hbs
new file mode 100644
index 0000000..d61be8a
--- /dev/null
+++ b/addon/components/full-calendar.hbs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addon/components/full-calendar.js b/addon/components/full-calendar.js
new file mode 100644
index 0000000..cf97394
--- /dev/null
+++ b/addon/components/full-calendar.js
@@ -0,0 +1,110 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action } from '@ember/object';
+import { classify } from '@ember/string';
+import { Calendar } from '@fullcalendar/core';
+import dayGridPlugin from '@fullcalendar/daygrid';
+import interactionPlugin from '@fullcalendar/interaction';
+
+export default class FullCalendarComponent extends Component {
+ /**
+ * @var {HTMLElement} calendarEl
+ */
+ @tracked calendarEl;
+
+ /**
+ * @var {Calendar} calendar
+ * @package @fullcalendar/core
+ */
+ @tracked calendar;
+
+ /**
+ * Default events to trigger for
+ * @var {Array}
+ */
+ @tracked events = ['dateClick', 'drop', 'eventReceive', 'eventClick', 'eventDragStop', 'eventDrop', 'eventAdd', 'eventChange', 'eventRemove'];
+
+ /**
+ * Tracked calendar event listeners
+ * @var {Array}
+ */
+ @tracked _listeners = [];
+
+ /**
+ * Initializes and renders the calendar component
+ *
+ * @param {HTMLElement} calendarEl
+ */
+ @action setupCalendar(calendarEl) {
+ // track calendar htmlelement
+ this.calendarEl = calendarEl;
+
+ // get events
+ let events = this.args.events || [];
+
+ // initialize calendar
+ this.calendar = new Calendar(calendarEl, {
+ events,
+ plugins: [dayGridPlugin, interactionPlugin],
+ initialView: 'dayGridMonth',
+ editable: true,
+ headerToolbar: {
+ left: 'prev,next today',
+ center: 'title',
+ right: '',
+ },
+ });
+
+ // trigger callback on initialize
+ if (typeof this.args.onInit === 'function') {
+ this.args.onInit(this.calendar);
+ }
+
+ // render calendar
+ this.calendar.render();
+
+ // listen for events
+ this.createCalendarEventListeners();
+ }
+
+ triggerCalendarEvent(eventName, ...params) {
+ if (typeof this[eventName] === 'function') {
+ this[eventName](...params);
+ }
+
+ if (typeof this.args[eventName] === 'function') {
+ this.args[eventName](...params);
+ }
+ }
+
+ createCalendarEventListeners() {
+ for (let i = 0; i < this.events.length; i++) {
+ const eventName = this.events.objectAt(i);
+ const callbackName = `on${classify(eventName)}`;
+
+ if (typeof this.args[callbackName] === 'function') {
+ // track for destroy purposes
+ this._listeners.pushObject({
+ eventName,
+ callbackName,
+ });
+
+ // create listener
+ this.calendar.on(eventName, this.triggerCalendarEvent.bind(this, callbackName));
+ }
+ }
+
+ // check for custom events
+ // @todo
+ }
+
+ destroyCalendarEventListeners() {
+ for (let i = 0; i < this._listeners.length; i++) {
+ const listener = this._listeners.objectAt(i);
+ const { eventName, callbackName } = listener;
+
+ // kill listener
+ this.calendar.off(eventName, this.triggerCalendarEvent.bind(this, callbackName));
+ }
+ }
+}
diff --git a/addon/components/full-calendar/draggable.hbs b/addon/components/full-calendar/draggable.hbs
new file mode 100644
index 0000000..2f2af9f
--- /dev/null
+++ b/addon/components/full-calendar/draggable.hbs
@@ -0,0 +1,3 @@
+
+ {{yield}}
+
\ No newline at end of file
diff --git a/addon/components/full-calendar/draggable.js b/addon/components/full-calendar/draggable.js
new file mode 100644
index 0000000..d59eb5a
--- /dev/null
+++ b/addon/components/full-calendar/draggable.js
@@ -0,0 +1,18 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action } from '@ember/object';
+import { Draggable } from '@fullcalendar/interaction';
+
+export default class DraggableFullcalendarEventComponent extends Component {
+ @tracked draggable;
+ @tracked eventData = {};
+
+ constructor() {
+ super(...arguments);
+ this.eventData = this.args.eventData ?? {};
+ }
+
+ @action makeDraggable(element) {
+ this.draggable = new Draggable(element);
+ }
+}
diff --git a/addon/helpers/json-hash.js b/addon/helpers/json-hash.js
index 3f470d0..739ba0e 100644
--- a/addon/helpers/json-hash.js
+++ b/addon/helpers/json-hash.js
@@ -1,5 +1,6 @@
import { helper } from '@ember/component/helper';
-export default helper(function jsonHash(positional /*, named*/) {
- return positional;
+export default helper(function jsonHash(positional, named) {
+ let json = JSON.stringify(named);
+ return json;
});
diff --git a/addon/styles/addon.css b/addon/styles/addon.css
index 36411b6..4faa8dc 100644
--- a/addon/styles/addon.css
+++ b/addon/styles/addon.css
@@ -40,6 +40,7 @@
@import 'components/notification-tray.css';
@import 'components/fleet-listing.css';
@import 'components/drawer.css';
+@import 'components/full-calendar.css';
/** Third party */
@import 'air-datepicker/air-datepicker.css';
diff --git a/addon/styles/components/full-calendar.css b/addon/styles/components/full-calendar.css
new file mode 100644
index 0000000..d7bcc80
--- /dev/null
+++ b/addon/styles/components/full-calendar.css
@@ -0,0 +1,99 @@
+.fleetbase-full-calendar .fc-toolbar-title {
+ @apply text-base text-gray-900 font-semibold;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-toolbar-title {
+ @apply text-gray-200;
+}
+
+.fleetbase-full-calendar.fc td,
+.fleetbase-full-calendar.fc th {
+ @apply border-gray-200;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc td,
+body[data-theme='dark'] .fleetbase-full-calendar.fc th {
+ @apply border-gray-700;
+}
+
+.fleetbase-full-calendar.fc table.fc-scrollgrid {
+ @apply border-gray-200;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc table.fc-scrollgrid {
+ @apply border-gray-700;
+}
+
+.fleetbase-full-calendar.fc .fc-button {
+ @apply inline-flex items-center px-3 py-2 text-sm font-medium leading-4 transition duration-150 ease-in-out border border-transparent rounded-md text-gray-800;
+ cursor: default !important;
+}
+
+.fleetbase-full-calendar.fc .fc-button:disabled,
+.fleetbase-full-calendar.fc .fc-button-primary:disabled,
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary:disabled {
+ @apply opacity-50 cursor-not-allowed;
+}
+
+.fleetbase-full-calendar.fc .fc-button .fc-icon {
+ font-size: 1rem;
+}
+
+.fleetbase-full-calendar.fc .fc-toolbar {
+ justify-content: start;
+}
+
+.fleetbase-full-calendar.fc .fc-toolbar.fc-header-toolbar {
+ margin-bottom: 1rem;
+}
+
+.fleetbase-full-calendar.fc .fc-toolbar > .fc-toolbar-chunk {
+ margin-right: 1.25rem;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary {
+ @apply text-gray-300 bg-gray-700 border-gray-900 shadow;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary:hover:not(:disabled) {
+ @apply text-gray-200 bg-gray-600;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary:focus {
+ @apply outline-0;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary:active:not(:disabled) {
+ @apply text-gray-300 bg-gray-600;
+}
+
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button .fc-icon {
+ @apply text-gray-300;
+}
+
+.fleetbase-full-calendar.fc .fc-button-primary {
+ @apply bg-white border-gray-300 shadow-sm text-gray-800;
+}
+
+.fleetbase-full-calendar.fc .fc-button-primary:hover:not(:disabled) {
+ @apply text-gray-500
+}
+
+.fleetbase-full-calendar.fc .fc-button-primary:focus {
+ @apply border-gray-300 outline-0;
+}
+
+.fleetbase-full-calendar.fc .fc-button-primary:active:not(:disabled) {
+ @apply text-gray-800 bg-gray-50;
+}
+
+.fleetbase-full-calendar.fc .fc-button .fc-icon {
+ @apply text-gray-900;
+}
+
+.fleetbase-full-calendar.fc .fc-button-primary:not(:disabled).fc-button-active:focus,
+.fleetbase-full-calendar.fc .fc-button-primary:not(:disabled):active:focus,
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary:not(:disabled).fc-button-active:focus,
+body[data-theme='dark'] .fleetbase-full-calendar.fc .fc-button-primary:not(:disabled):active:focus {
+ box-shadow: none;
+}
\ No newline at end of file
diff --git a/app/components/full-calendar.js b/app/components/full-calendar.js
new file mode 100644
index 0000000..424bf0e
--- /dev/null
+++ b/app/components/full-calendar.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/ember-ui/components/full-calendar';
diff --git a/app/components/full-calendar/draggable.js b/app/components/full-calendar/draggable.js
new file mode 100644
index 0000000..320ca98
--- /dev/null
+++ b/app/components/full-calendar/draggable.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/ember-ui/components/full-calendar/draggable';
diff --git a/package.json b/package.json
index ce434ed..d7838c5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/ember-ui",
- "version": "0.2.3",
+ "version": "0.2.4",
"description": "Fleetbase UI provides all the interface components, helpers, services and utilities for building a Fleetbase extension into the Console.",
"keywords": [
"fleetbase-ui",
@@ -41,9 +41,14 @@
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.4.0",
+ "@fullcalendar/core": "^6.1.9",
+ "@fullcalendar/daygrid": "^6.1.9",
+ "@fullcalendar/interaction": "^6.1.9",
"@makepanic/ember-power-calendar-date-fns": "^0.4.2",
+ "@tailwindcss/forms": "^0.5.3",
"air-datepicker": "^3.3.5",
"autonumeric": "^4.6.2",
+ "autoprefixer": "^10.4.15",
"broccoli-funnel": "^3.0.8",
"broccoli-merge-trees": "^4.2.0",
"chart.js": "^4.2.1",
@@ -80,15 +85,13 @@
"ember-wormhole": "^0.6.0",
"imask": "^6.4.3",
"intl-tel-input": "^18.1.3",
- "autoprefixer": "^10.4.15",
"postcss-at-rules-variables": "^0.3.0",
"postcss-conditionals-renewed": "^1.0.0",
"postcss-each": "^1.1.0",
"postcss-import": "^15.1.0",
"postcss-mixins": "^9.0.4",
"postcss-preset-env": "^9.1.1",
- "tailwindcss": "^3.1.8",
- "@tailwindcss/forms": "^0.5.3"
+ "tailwindcss": "^3.1.8"
},
"devDependencies": {
"@ember/optional-features": "^2.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8991f8f..668d306 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
dependencies:
'@ember/render-modifiers':
specifier: ^2.0.4
@@ -28,6 +32,15 @@ dependencies:
'@fortawesome/free-solid-svg-icons':
specifier: ^6.4.0
version: 6.4.0
+ '@fullcalendar/core':
+ specifier: ^6.1.9
+ version: 6.1.9
+ '@fullcalendar/daygrid':
+ specifier: ^6.1.9
+ version: 6.1.9(@fullcalendar/core@6.1.9)
+ '@fullcalendar/interaction':
+ specifier: ^6.1.9
+ version: 6.1.9(@fullcalendar/core@6.1.9)
'@makepanic/ember-power-calendar-date-fns':
specifier: ^0.4.2
version: 0.4.2
@@ -2211,6 +2224,28 @@ packages:
'@fortawesome/fontawesome-common-types': 6.4.0
dev: false
+ /@fullcalendar/core@6.1.9:
+ resolution: {integrity: sha512-eeG+z9BWerdsU9Ac6j16rpYpPnE0wxtnEHiHrh/u/ADbGTR3hCOjCD9PxQOfhOTHbWOVs7JQunGcksSPu5WZBQ==}
+ dependencies:
+ preact: 10.12.1
+ dev: false
+
+ /@fullcalendar/daygrid@6.1.9(@fullcalendar/core@6.1.9):
+ resolution: {integrity: sha512-o/6joH/7lmVHXAkbaa/tUbzWYnGp/LgfdiFyYPkqQbjKEeivNZWF1WhHqFbhx0zbFONSHtrvkjY2bjr+Ef2quQ==}
+ peerDependencies:
+ '@fullcalendar/core': ~6.1.9
+ dependencies:
+ '@fullcalendar/core': 6.1.9
+ dev: false
+
+ /@fullcalendar/interaction@6.1.9(@fullcalendar/core@6.1.9):
+ resolution: {integrity: sha512-I3FGnv0kKZpIwujg3HllbKrciNjTqeTYy3oJG226oAn7lV6wnrrDYMmuGmA0jPJAGN46HKrQqKN7ItxQRDec4Q==}
+ peerDependencies:
+ '@fullcalendar/core': ~6.1.9
+ dependencies:
+ '@fullcalendar/core': 6.1.9
+ dev: false
+
/@glimmer/compiler@0.27.0:
resolution: {integrity: sha512-SJUUEpkFCL+GTpEK6c2EhZQJant67ahGLF6M1xRmIsq6E+AtbHgu+y8mWvFbtpb7lx4gqNKpXSEwlHUTTuxVGw==}
dependencies:
@@ -3258,6 +3293,7 @@ packages:
/async-each@1.0.6:
resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==}
+ requiresBuild: true
dev: false
optional: true
@@ -3661,6 +3697,7 @@ packages:
/binary-extensions@1.13.1:
resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
engines: {node: '>=0.10.0'}
+ requiresBuild: true
dev: false
optional: true
@@ -3675,6 +3712,7 @@ packages:
/bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
+ requiresBuild: true
dependencies:
file-uri-to-path: 1.0.0
dev: false
@@ -4672,6 +4710,7 @@ packages:
/chokidar@2.1.8:
resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
+ requiresBuild: true
dependencies:
anymatch: 2.0.0
async-each: 1.0.6
@@ -7834,6 +7873,7 @@ packages:
/file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
+ requiresBuild: true
dev: false
optional: true
@@ -8337,6 +8377,7 @@ packages:
/glob-parent@3.1.0:
resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==}
+ requiresBuild: true
dependencies:
is-glob: 3.1.0
path-dirname: 1.0.2
@@ -8919,6 +8960,7 @@ packages:
/is-binary-path@1.0.1:
resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==}
engines: {node: '>=0.10.0'}
+ requiresBuild: true
dependencies:
binary-extensions: 1.13.1
dev: false
@@ -9026,6 +9068,7 @@ packages:
/is-glob@3.1.0:
resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==}
engines: {node: '>=0.10.0'}
+ requiresBuild: true
dependencies:
is-extglob: 2.1.1
dev: false
@@ -10046,6 +10089,7 @@ packages:
/nan@2.18.0:
resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==}
+ requiresBuild: true
dev: false
optional: true
@@ -10558,6 +10602,7 @@ packages:
/path-dirname@1.0.2:
resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==}
+ requiresBuild: true
dev: false
optional: true
@@ -11217,6 +11262,10 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
+ /preact@10.12.1:
+ resolution: {integrity: sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==}
+ dev: false
+
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@@ -11508,6 +11557,7 @@ packages:
/readdirp@2.2.1:
resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
engines: {node: '>=0.10'}
+ requiresBuild: true
dependencies:
graceful-fs: 4.2.11
micromatch: 3.1.10
@@ -13199,6 +13249,7 @@ packages:
/upath@1.2.0:
resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
engines: {node: '>=4'}
+ requiresBuild: true
dev: false
optional: true
diff --git a/tests/integration/components/full-calendar-test.js b/tests/integration/components/full-calendar-test.js
new file mode 100644
index 0000000..170cd38
--- /dev/null
+++ b/tests/integration/components/full-calendar-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | full-calendar', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs``);
+
+ assert.dom(this.element).hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom(this.element).hasText('template block text');
+ });
+});
diff --git a/tests/integration/components/full-calendar/draggable-test.js b/tests/integration/components/full-calendar/draggable-test.js
new file mode 100644
index 0000000..39317bf
--- /dev/null
+++ b/tests/integration/components/full-calendar/draggable-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | full-calendar/draggable', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.set('myAction', function(val) { ... });
+
+ await render(hbs``);
+
+ assert.dom(this.element).hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom(this.element).hasText('template block text');
+ });
+});