Code Monkey home page Code Monkey logo

vaadin-minicalendar's Introduction

Buy Me A Coffee

MiniCalendar

MiniCalendar is a server-only Vaadin component for displaying and selecting LocalDate values.

The sunny side ๐ŸŒž The dark side (of the moon ๐ŸŒ’)
Default Standard Default Standard

Motivation

I am building a small Diary application and needed a way to easily let users select days in a month with a single click (just to make it as comfortable as possible). I first tried to use the built-in DatePicker component, but unfortunately there's no way to have this component "always open".

Hence, I decided to build one on my own.

The next thought was "oh, this could be useful for somebody else as well" and I quickly checked how "hard" it is to contribute components to the Vaadin Directory. Luckily this is not problematic at all and I love that it's this easy โค๏ธ

I hope you enjoy the component, if there's anything you want to chit-chat about feel free to say [email protected].

Fundamentals

The internals are built on the Java Time API , the displayed values are localized with the locale that is set for the current UI.

The component implements the LocaleChangeObserver. It listens for locale changes and will redraw itself when the locale has changed.

It is highly customizable, offers a lot of configuration- and interaction possibilities. You can either use the built-in MiniCalendarVariant or provide custom CSS classes using the setDayStyleProvider().

Features

Single Value Selection

The Component is designed to have a single value selected. It implements the HasValue interface and can therefore be used with a Binder like any other default Vaadin field.

You can listen to value changes as well as YearMonth changes which will be triggered when the user navigates through the months or the component gets a new value set which differs from the previous YearMonth value.

var miniCalendar = new MiniCalendar();

miniCalendar.addValueChangeListener(event -> {
    Notification.show("Value changed to " + event.getValue());
});

miniCalendar.addYearMonthChangeListener(event -> {
    Notification.show("Value changed to " + event.getValue());
});

When adding a listener you'll get an instance of Registration back which can be used to remove said listener again.

var registration = miniCalendar.addYearMonthChangeListener(...);

registration.remove();

Dynamically En- or Disable certain days

You can dynamically en- or disable certain days in the calendar view by setting up a DayEnabledProvider with setDayEnabledProvider(). The method takes a SerializablePredicate<LocallDate> as argument which will be used to evaluate the enabled state of a day when rendering the component.

Warning DayEnabledProvider could cause performance issues!

The DayEnabledProvider may be called quite a few times during the lifetime of a MiniCalendar, you should ensure that the backing function is not an expensive backend operation, else you could experience some performance issues.

var disabledDays = getDisabledDays();

var miniCalendar = new MiniCalendar();
miniCalendar.addThemeVariants(MiniCalendarVariant.HOVER_DAYS, MiniCalendarVariant.HIGHLIGHT_WEEKEND);
miniCalendar.setDayEnabledProvider(value -> !disabledDays.contains(value));

Warning Disabled days can still be selected by the server!

Even though a day is disabled in the calendar view, it can still be marked as the selected value from server side. Disabled days are not considered as invalid value from the server, the feature's purpose is to indicate valid selections to the user.

Details
var disabledDays = getDisabledDays();

var miniCalendar = new MiniCalendar();
miniCalendar.setValue(disabledDays.get(0));
miniCalendar.addThemeVariants(MiniCalendarVariant.HOVER_DAYS, MiniCalendarVariant.HIGHLIGHT_WEEKEND);
miniCalendar.setDayEnabledProvider(value -> !disabledDays.contains(value));

Appearance

Theming

The component is based on the Lumo Theme, and it's appearance can easily be changed by using the built-in Theme Variants.

To apply a Theme Variant you simply call the addThemeVariants() method.

miniCalendar.addThemeVariants(MiniCalendarVariant.ROUNDED);
miniCalendar.addThemeVariants(MiniCalendarVariant.HIGHLIGHT_WEEKEND);

To remove an already applied Theme Variant simply call the removeThemeVariants() method.

miniCalendar.removeThemeVariants(MiniCalendarVariant.HOVER_DAYS);

You can combine multiple Theme Variants to change the component's appearance.

Show examples

Highlight weekends

Light Mode Dark Mode

Shifted beginning of the week

Light Mode Dark Mode

Hover days

Light Mode Dark Mode

Rounded

Light Mode Dark Mode

Rounded, Highlight weekends

Light Mode Dark Mode

Component State

The component's state implicitly affects the appearance of the component. For instance a disabled component will look gray-ish to indicate that the user cannot interact with it. A component in read only state won't change the cursor when hovering over interaction parts and hide the navigation buttons.

Check out these examples of the component in different states.

Read Only

No Theme Variant

Light Mode Dark Mode

Highlight weekends

Light Mode Dark Mode

Shifted beginning of the week

Light Mode Dark Mode

Hover days

Light Mode Dark Mode

Rounded

Light Mode Dark Mode

Rounded, Highlight weekends

Light Mode Dark Mode
Disabled

No Theme Variant

Light Mode Dark Mode

Highlight weekends

Light Mode Dark Mode

Shifted beginning of the week

Light Mode Dark Mode

Hover days

Light Mode Dark Mode

Rounded

Light Mode Dark Mode

Rounded, Highlight weekends

Light Mode Dark Mode
Disabled, Read Only

No Theme Variant

Light Mode Dark Mode

Highlight weekends

Light Mode Dark Mode

Shifted beginning of the week

Light Mode Dark Mode

Hover days

Light Mode Dark Mode

Rounded

Light Mode Dark Mode

Rounded, Highlight weekends

Light Mode Dark Mode

Adding custom CSS classes

You can easily provide custom css classes for the day components by using the setDayStyleProvider() method. The method takes a SerializableFunction<LocalDate, List<String>> as argument which will be used to evaluate the additional classes for a day when rendering the component.

Warning DayStyleProvider could cause performance issues!

The DayStyleProvider may be called quite a few times during the lifetime of a MiniCalendar, you should ensure that the backing function is not an expensive backend operation, else you could experience some performance issues.

funky.css

@-webkit-keyframes bounce {
    0%, 20%, 50%, 80%, 100% {-webkit-transform: translateY(0);}
    40% {-webkit-transform: translateY(-30px);}
    60% {-webkit-transform: translateY(-15px);}
}

@keyframes bounce {
    0%, 20%, 50%, 80%, 100% {transform: translateY(0);}
    40% {transform: translateY(-30px);}
    60% {transform: translateY(-15px);}
}

.minicalendar .day.funky {
    color: var(--lumo-primary-contrast-color);
    -webkit-animation-duration: 1s;
    animation-duration: 1s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;
    background: linear-gradient(
            90deg,
            rgba(255, 0, 0, 1) 0%,
            rgba(255, 154, 0, 1) 10%,
            rgba(208, 222, 33, 1) 20%,
            rgba(79, 220, 74, 1) 30%,
            rgba(63, 218, 216, 1) 40%,
            rgba(47, 201, 226, 1) 50%,
            rgba(28, 127, 238, 1) 60%,
            rgba(95, 21, 242, 1) 70%,
            rgba(186, 12, 248, 1) 80%,
            rgba(251, 7, 217, 1) 90%,
            rgba(255, 0, 0, 1) 100%
    );
}

.bounce:hover {
    -webkit-animation-name: bounce;
    animation-name: bounce;
}

StyleProviderShowcaseView.java

@Route("/styleprovider")
@PageTitle("MiniCalendar Showcase")
@CssImport("css/funky.css")
public class StyleProviderShowcaseView extends VerticalLayout {

    public StyleProviderShowcaseView() {

        var funkyDays = getFunkyDays();

        var miniCalendar = new MiniCalendar();
        miniCalendar.setValue(funkyDays.get(0));
        miniCalendar.addThemeVariants(MiniCalendarVariant.HOVER_DAYS, MiniCalendarVariant.HIGHLIGHT_WEEKEND);
        miniCalendar.setDayStyleProvider(day -> {
            if (funkyDays.contains(day)) {
                return List.of("funky", "bounce");
            }
            return null;
        });

        add(miniCalendar);
    }
}

Showcase

The project contains a showcase module that displays some usages of the Add-on. To start the showcase check out the repository and run ./mvnw jetty:run -pl :showcase in the root directory.

vaadin-minicalendar's People

Contributors

downdrown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

vaadin-minicalendar's Issues

Add separate Dockerfile for Railway.app deployment

Since a few weeks the Railway build always fails and the Docker image cannot be started.
Also it would make much mor sense to only deploy de pre-built docker image from Github.

As discussed in this Discord Thread it would be possible to simply add a separate Dockerfile for Railway that launches the pre-built image from Github.

Sample Dockerfile from Vaultvarden can be found here

Direct Month / Year selection should be more user-friendly

When you click on the Header of the calendar to fast-forward to a specific year a modal with a combobox for selecting a year pops up in the center of the screen.

Ideally this should be possible directly in the header of the component instead.
Also it should be possible to fast-forward to a specific month/year combination - at the moment you can only fast-forward to a year that is within the past or upcoming 100 years.

image
image

Calendar styling not applied

Using Vaadin 23.3.32 and 1.3.0 of the minicalendar, the css styling is not applied to the calendar. The minicalendar is added to a layout that is included in a module in the maven build.

image

    MiniCalendar appointmentDatePicker = new MiniCalendar();
    calendarLayout.add(appointmentDatePicker);
    appointmentDatePicker.setValue(activityItem.getAvailableStartDate());
    appointmentDatePicker.addValueChangeListener(event -> {
        updateTimeslotLayout(event.getValue());
    });

Add manual trigger to deploy branch to railway

Currently the showcase will only deployed to railway whenever I trigger a new release.
This is not ideal since I'd need to trigger a release if for example railway just stops my app, just to initiate a new deployment.

There should be a workflow that can be triggered manually for a specific branch to publish the said branch to railway.

In the best case the release workflow will also trigger this new workflow instead of having the railway publish code duplicated.

Fix Railway Pipeline

The railway pipeline does not work as expected and needs to be adapted to work with the new custom Docker image.

Fix GitHub workflow configuration

With the latest chanes of the project the Release workflow config broke.
This must be fixed to have an automated deployment again.
Should be fixed with another Hotfix version.

Fix resource includes

As seen in the screenshot below the resource includes need to be updated to have a ./ prefix since the resources are packaged inside a .jar file.

image

Fix Dockerfile setup

Since the Vaadin 24 Upgrade the old Jetty Version will not be able to boot up the Showcase app.
Therefore, the Dockerfile must be updated to be deployable again.

Add Checkstyle to project

The project should have a Checkstyle configuration that is included in the build process to ensure a certain code style and minimum quality.

Add deployable & locally startable Showcase to the project

Currently the project contains some "showcase views" that can be viewed by starting the Maven Jetty plugin.

It would be nice to have a deployable (.war) and locally startable (.jar) showcase as a new Maven module in the project.
In the best case there's still some free hosting of .war archives possible, then I could add the showcase as URL in the Addon overview page in the Vaadin Directory

False MANIFEST.MF entry preventing vaadin release

Since the project layout has changed somehow the MANIFEST.MF for the addon also changed.
This needs to be adapted to match the old entry because the Vaadin Directory restricts the upload of the final component archive.

image

Constructor feature request

It would be nice to have the following options on the constructor:

  1. Available date range (like the Vaadin DatePicker)
  2. List of available days
  3. List of List of days with List of styles :-)

In my case these are known at construction time and would save the 60 odd server roundtrips.

Thanks for the great component.

Maven Multi-Module Setup breaks the Release

It seems that my switch to the multi-module project setup broke the actual project release because the resulting addon pom.xml is referencing a parent that is not published anywhere. In order to work around this we need to flatten the final build before we publish it to the Vaadin Directory.

See this Plugin

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.