From d45d210381ffe1528a81165e3a0af713633bac7d Mon Sep 17 00:00:00 2001 From: Marek Skacelik Date: Mon, 21 Jul 2025 12:10:45 +0200 Subject: [PATCH] Add Timestamp component --- .../patternfly/component/ComponentType.java | 2 + .../component/timestamp/CustomFormat.java | 166 ++++++++++ .../timestamp/DateTimeFormatOptions.java | 266 ++++++++++++++++ .../component/timestamp/FormatOptions.java | 28 ++ .../component/timestamp/LocaleOptions.java | 76 +++++ .../component/timestamp/Timestamp.java | 298 ++++++++++++++++++ .../component/timestamp/TimestampFormat.java | 47 +++ .../java/org/patternfly/style/Classes.java | 1 + showcase/common/src/bundle/components.json | 3 +- .../component/TimestampComponent.java | 116 +++++++ 10 files changed, 1002 insertions(+), 1 deletion(-) create mode 100644 components/src/main/java/org/patternfly/component/timestamp/CustomFormat.java create mode 100644 components/src/main/java/org/patternfly/component/timestamp/DateTimeFormatOptions.java create mode 100644 components/src/main/java/org/patternfly/component/timestamp/FormatOptions.java create mode 100644 components/src/main/java/org/patternfly/component/timestamp/LocaleOptions.java create mode 100644 components/src/main/java/org/patternfly/component/timestamp/Timestamp.java create mode 100644 components/src/main/java/org/patternfly/component/timestamp/TimestampFormat.java create mode 100644 showcase/common/src/main/java/org/patternfly/showcase/component/TimestampComponent.java diff --git a/components/src/main/java/org/patternfly/component/ComponentType.java b/components/src/main/java/org/patternfly/component/ComponentType.java index 3e739d004..e7a921044 100644 --- a/components/src/main/java/org/patternfly/component/ComponentType.java +++ b/components/src/main/java/org/patternfly/component/ComponentType.java @@ -145,6 +145,8 @@ public enum ComponentType { TextInputGroup("tig", "PF6/TextInputGroup"), + Timestamp("ts", "PF6/Timestamp"), + Title("tlt", "PF6/Title"), ToggleGroup("tg", null), diff --git a/components/src/main/java/org/patternfly/component/timestamp/CustomFormat.java b/components/src/main/java/org/patternfly/component/timestamp/CustomFormat.java new file mode 100644 index 000000000..bea0943a6 --- /dev/null +++ b/components/src/main/java/org/patternfly/component/timestamp/CustomFormat.java @@ -0,0 +1,166 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.component.timestamp; + +import java.util.Objects; + +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class CustomFormat implements FormatOptions { + + @JsOverlay + public static final CustomFormat create() { + return new CustomFormat(); + } + + @JsProperty + private String year; + @JsProperty + private String month; + @JsProperty + private String day; + @JsProperty + private String weekday; + @JsProperty + private String hour; + @JsProperty + private String minute; + @JsProperty + private String second; + @JsProperty + private String timeZone; + @JsProperty + private String timeZoneName; + @JsProperty + private Boolean hour12; + @JsProperty + private String era; + @JsProperty + private String dayPeriod; + @JsProperty + private String fractionalSecondDigits; + + private CustomFormat() { + } + + @JsOverlay + public final CustomFormat year(DateTimeFormatOptions.Year year) { + if (!Objects.equals(this.year, year.value)) { + this.year = year.value; + } + return this; + } + + @JsOverlay + public final CustomFormat month(DateTimeFormatOptions.Month month) { + if (!Objects.equals(this.month, month.value)) { + this.month = month.value; + } + return this; + } + + @JsOverlay + public final CustomFormat day(DateTimeFormatOptions.Day day) { + if (!Objects.equals(this.day, day.value)) { + this.day = day.value; + } + return this; + } + + @JsOverlay + public final CustomFormat weekday(DateTimeFormatOptions.Weekday weekday) { + if (!Objects.equals(this.weekday, weekday.value)) { + this.weekday = weekday.value; + } + return this; + } + + @JsOverlay + public final CustomFormat hour(DateTimeFormatOptions.Hour hour) { + if (!Objects.equals(this.hour, hour.value)) { + this.hour = hour.value; + } + return this; + } + + @JsOverlay + public final CustomFormat minute(DateTimeFormatOptions.Minute minute) { + if (!Objects.equals(this.minute, minute.value)) { + this.minute = minute.value; + } + return this; + } + + @JsOverlay + public final CustomFormat second(DateTimeFormatOptions.Second second) { + if (!Objects.equals(this.second, second.value)) { + this.second = second.value; + } + return this; + } + + @JsOverlay + public final CustomFormat timeZone(String timeZone) { + if (!Objects.equals(this.timeZone, timeZone)) { + this.timeZone = timeZone; // IANA time zone name + } + return this; + } + + @JsOverlay + public final CustomFormat timeZoneName(DateTimeFormatOptions.TimeZoneName timeZoneName) { + if (!Objects.equals(this.timeZoneName, timeZoneName.value)) { + this.timeZoneName = timeZoneName.value; + } + return this; + } + + @JsOverlay + public final CustomFormat hour12(boolean hour12) { + if (this.hour12 != hour12) { + this.hour12 = hour12; + } + return this; + } + + @JsOverlay + public final CustomFormat era(DateTimeFormatOptions.Era era) { + if (!Objects.equals(this.era, era.value)) { + this.era = era.value; + } + return this; + } + + @JsOverlay + public final CustomFormat dayPeriod(DateTimeFormatOptions.DayPeriod dayPeriod) { + if (!Objects.equals(this.dayPeriod, dayPeriod.value)) { + this.dayPeriod = dayPeriod.value; + } + return this; + } + + @JsOverlay + public final CustomFormat fractionalSecondDigits(DateTimeFormatOptions.FractionalSecondDigits digits) { + if (!Objects.equals(this.fractionalSecondDigits, digits.value)) { + this.fractionalSecondDigits = digits.value; + } + return this; + } +} diff --git a/components/src/main/java/org/patternfly/component/timestamp/DateTimeFormatOptions.java b/components/src/main/java/org/patternfly/component/timestamp/DateTimeFormatOptions.java new file mode 100644 index 000000000..5e03eb42b --- /dev/null +++ b/components/src/main/java/org/patternfly/component/timestamp/DateTimeFormatOptions.java @@ -0,0 +1,266 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.component.timestamp; + +/** + * Container for all date/time formatting options based on MDN + * Intl.DateTimeFormat + * Consolidates all format enums into static inner classes for better + * organization. + * + */ +public class DateTimeFormatOptions { + + /** + * Options for weekday formatting. + * + */ + public enum Weekday { + narrow("narrow"), + _short("short"), + _long("long"); + + public final String value; + + Weekday(String value) { + this.value = value; + } + } + + /** + * Options for era formatting. + * + */ + public enum Era { + narrow("narrow"), + _short("short"), + _long("long"); + + public final String value; + + Era(String value) { + this.value = value; + } + } + + /** + * Options for year formatting. + * + */ + public enum Year { + numeric("numeric"), + _2digit("2-digit"); + + public final String value; + + Year(String value) { + this.value = value; + } + } + + /** + * Options for month formatting. + * + */ + public enum Month { + numeric("numeric"), + _2digit("2-digit"), + narrow("narrow"), + _short("short"), + _long("long"); + + public final String value; + + Month(String value) { + this.value = value; + } + } + + /** + * Options for day formatting. + * + */ + public enum Day { + numeric("numeric"), + _2digit("2-digit"); + + public final String value; + + Day(String value) { + this.value = value; + } + } + + /** + * Options for hour formatting. + * + */ + public enum Hour { + numeric("numeric"), + _2digit("2-digit"); + + public final String value; + + Hour(String value) { + this.value = value; + } + } + + /** + * Options for minute formatting. + * + */ + public enum Minute { + numeric("numeric"), + _2digit("2-digit"); + + public final String value; + + Minute(String value) { + this.value = value; + } + } + + /** + * Options for second formatting. + * + */ + public enum Second { + numeric("numeric"), + _2digit("2-digit"); + + public final String value; + + Second(String value) { + this.value = value; + } + } + + /** + * Options for fractional second digits. + * The number of digits used to represent fractions of a second (any additional + * digits are truncated). + * + */ + public enum FractionalSecondDigits { + _1("1"), + _2("2"), + _3("3"); + + public final String value; + + FractionalSecondDigits(String value) { + this.value = value; + } + } + + /** + * Options for day period formatting. + * The formatting style used for day periods like "in the morning", "am", + * "noon", etc. + *

+ * Note: This option only has an effect if a 12-hour clock + * ({@code hourCycle: "h12"} or {@code hourCycle: "h11"}) is used. + * Many locales use the same string irrespective of the width specified. + *

+ * + */ + public enum DayPeriod { + narrow("narrow"), + _short("short"), + _long("long"); + + public final String value; + + DayPeriod(String value) { + this.value = value; + } + } + + /** + * Options for time zone name formatting. + * The localized representation of the time zone name. + *

+ * Note: Timezone display may fall back to another format if a + * required string is unavailable. + * For example, the non-location formats should display the timezone without a + * specific country/city location + * like "Pacific Time", but may fall back to a timezone like "Los Angeles Time". + *

+ * + */ + public enum TimeZoneName { + _short("short"), + _long("long"), + shortOffset("shortOffset"), + longOffset("longOffset"), + shortGeneric("shortGeneric"), + longGeneric("longGeneric"); + + public final String value; + + TimeZoneName(String value) { + this.value = value; + } + } +} diff --git a/components/src/main/java/org/patternfly/component/timestamp/FormatOptions.java b/components/src/main/java/org/patternfly/component/timestamp/FormatOptions.java new file mode 100644 index 000000000..73ffe6fac --- /dev/null +++ b/components/src/main/java/org/patternfly/component/timestamp/FormatOptions.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.component.timestamp; + +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +/** + * A marker interface for different formatting options used in the Timestamp component. + * This allows for a unified handling of various format settings. + */ +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public interface FormatOptions { + // This is a marker interface and does not define any methods. +} diff --git a/components/src/main/java/org/patternfly/component/timestamp/LocaleOptions.java b/components/src/main/java/org/patternfly/component/timestamp/LocaleOptions.java new file mode 100644 index 000000000..d4c6e47dd --- /dev/null +++ b/components/src/main/java/org/patternfly/component/timestamp/LocaleOptions.java @@ -0,0 +1,76 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.component.timestamp; + +import java.util.Objects; + +import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class LocaleOptions implements FormatOptions { + + @JsOverlay + public static final LocaleOptions create() { + return new LocaleOptions(); + } + + @JsProperty + private String dateStyle; + @JsProperty + private String timeStyle; + @JsProperty + private boolean hour12; + @JsProperty + private String timeZone; + + private LocaleOptions() { + } + + @JsOverlay + public final LocaleOptions dateStyle(TimestampFormat dateStyle) { + if (!Objects.equals(this.dateStyle, dateStyle.value)) { + this.dateStyle = dateStyle.value; + } + return this; + } + + @JsOverlay + public final LocaleOptions timeStyle(TimestampFormat timeStyle) { + if (!Objects.equals(this.timeStyle, timeStyle.value)) { + this.timeStyle = timeStyle.value; + } + return this; + } + + @JsOverlay + public final LocaleOptions hour12(boolean hour12) { + if (this.hour12 != hour12) { + this.hour12 = hour12; + } + return this; + } + + @JsOverlay + public final LocaleOptions timeZone(String timeZone) { + if (!Objects.equals(this.timeZone, timeZone)) { + this.timeZone = timeZone; + } + return this; + } +} diff --git a/components/src/main/java/org/patternfly/component/timestamp/Timestamp.java b/components/src/main/java/org/patternfly/component/timestamp/Timestamp.java new file mode 100644 index 000000000..9b9658738 --- /dev/null +++ b/components/src/main/java/org/patternfly/component/timestamp/Timestamp.java @@ -0,0 +1,298 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.component.timestamp; + +import java.util.Date; + +import org.jboss.elemento.ElementTextDelegate; +import org.jboss.elemento.HTMLContainerBuilder; +import org.jboss.elemento.logger.Logger; +import org.patternfly.component.BaseComponent; +import org.patternfly.component.ComponentType; + +import elemental2.core.JsDate; +import elemental2.dom.Element; +import elemental2.dom.HTMLElement; + +import static org.jboss.elemento.Elements.span; +import static org.jboss.elemento.Elements.time; +import static org.patternfly.component.timestamp.TimestampFormat.full; +import static org.patternfly.style.Classes.component; +import static org.patternfly.style.Classes.text; +import static org.patternfly.style.Classes.timestamp; + +/** + * A timestamp component for displaying date and time values. + * This component supports various formatting options including + * custom formats, standard date/time styles, and UTC display. + * It can also handle custom HTML content or plain text. + * + * @see https://www.patternfly.org/components/timestamp + * + * @author mskacelik + */ +public class Timestamp extends BaseComponent + implements ElementTextDelegate { + + private static final Logger logger = Logger.getLogger(Timestamp.class.getName()); + private static final String DATETIME_ATTR = "datetime"; + private static final String COORDINATED_UNIVERSAL_TIME = "Coordinated Universal Time"; + private static final String UTC = "UTC"; + + // ------------------------------------------------------ factory + + public static Timestamp timestamp() { + return new Timestamp(); + } + + public static Timestamp timestamp(String text) { + return new Timestamp().text(text); + } + + public static Timestamp timestamp(Date dateTime) { + return new Timestamp().dateTime(dateTime); + } + + public static Timestamp timestamp(String text, Date dateTime) { + return new Timestamp().text(text).dateTime(dateTime); + } + + // ------------------------------------------------------ instance + + private HTMLContainerBuilder timeElement; + private Date dateTime; + private TimestampFormat dateFormat; + private TimestampFormat timeFormat; + private CustomFormat customFormat; + private String displaySuffix = ""; + private boolean is12Hour = true; + private String locale; + private boolean shouldDisplayUTC = false; + private boolean showDateTimeAsTextFlag = true; + + Timestamp() { + super(ComponentType.Timestamp, span().css(component(timestamp)).element()); + this.timeElement = time().css(component(timestamp, text)); + updateDisplayAndDatetime(); + } + + // ------------------------------------------------------ builder + + @Override + public Timestamp that() { + return this; + } + + @Override + public Element textDelegate() { + return timeElement.element(); + } + + @Override + public Timestamp text(String text) { + this.showDateTimeAsTextFlag = text == null || text.trim().length() == 0; // isBlank() + textDelegate().textContent = text; + return this; + } + + public Timestamp dateTime(Date dateTime) { + this.dateTime = dateTime; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp dateFormat(TimestampFormat dateFormat) { + if (this.customFormat != null) { + logger.warn("Setting dateFormat while customFormat is already set. " + + "CustomFormat will be cleared to avoid conflicting format options. " + + "Use either dateFormat/timeFormat OR customFormat, not both."); + } + this.dateFormat = dateFormat; + this.customFormat = null; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp timeFormat(TimestampFormat timeFormat) { + if (this.customFormat != null) { + logger.warn("Setting timeFormat while customFormat is already set. " + + "CustomFormat will be cleared to avoid conflicting format options. " + + "Use either dateFormat/timeFormat OR customFormat, not both."); + } + this.timeFormat = timeFormat; + this.customFormat = null; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp customFormat(CustomFormat customFormat) { + if (this.dateFormat != null || this.timeFormat != null) { + logger.warn("Setting customFormat while dateFormat and/or timeFormat are already set. " + + "Standard formats will be cleared to avoid conflicting format options. " + + "Use either dateFormat/timeFormat OR customFormat, not both."); + } + this.customFormat = customFormat; + this.dateFormat = null; + this.timeFormat = null; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp displaySuffix(String displaySuffix) { + this.displaySuffix = displaySuffix; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp is12Hour(boolean is12Hour) { + this.is12Hour = is12Hour; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp locale(String locale) { + this.locale = locale; + updateDisplayAndDatetime(); + return this; + } + + public Timestamp utc(boolean shouldDisplayUTC) { + this.shouldDisplayUTC = shouldDisplayUTC; + updateDisplayAndDatetime(); + return this; + } + + // ------------------------------------------------------ accessors + + public Date dateTime() { + return dateTime; + } + // ------------------------------------------------------ internal + + + /** + * Updates both the display text and datetime attribute of the timestamp + * component. + * This method is called whenever any formatting property changes. + */ + private void updateDisplayAndDatetime() { + timeElement.attr(DATETIME_ATTR, formatDateTimeAttribute()); + if (showDateTimeAsTextFlag) { + timeElement.text(formatDisplayText()); // important not to set via this#text() + } + element().replaceChildren(timeElement.element()); + } + + /** + * Formats the display text using current date and formatting options. + * Separated from updateDisplayAndDatetime for clarity and reusability. + */ + private String formatDisplayText() { + Date dateToFormat = (dateTime != null) ? dateTime : new Date(); + JsDate jsDate = new JsDate((double) dateToFormat.getTime()); + + String formattedText; + if (customFormat != null) { + formattedText = formatWithCustomFormat(jsDate); + } else { + formattedText = formatWithStandardOptions(jsDate); + } + if (!shouldDisplayUTC) { + return appendSuffix(formattedText); + } + return formattedText; + } + + /** + * Formats the date using custom format options. + * CustomFormat settings take precedence over builder-level settings. + */ + private String formatWithCustomFormat(JsDate jsDate) { + if (shouldDisplayUTC) { + return formatAsUTC(jsDate, customFormat); + } + return jsDate.toLocaleString(locale, customFormat); + } + + /** + * Formats the date using standard TimestampFormat options with builder-level + * preferences. + */ + private String formatWithStandardOptions(JsDate jsDate) { + LocaleOptions formatOptions = LocaleOptions.create(); + + if (dateFormat != null) { + formatOptions.dateStyle(dateFormat); + } + formatOptions.hour12(is12Hour); + if (timeFormat != null) { + formatOptions.timeStyle(timeFormat); + } + if (shouldDisplayUTC) { + return formatAsUTC(jsDate, formatOptions); + } + return jsDate.toLocaleString(locale, formatOptions); + } + + private String formatAsUTC(JsDate jsDate, FormatOptions formatOptions) { + JsDate utcDate = convertToUtcDate(jsDate); + String utcDateString = utcDate.toLocaleString(locale, formatOptions); + return appendSuffix(utcDateString); + } + + private JsDate convertToUtcDate(JsDate jsDate) { + String utcString = jsDate.toUTCString(); + String convertToUTCString = utcString.substring(0, utcString.length() - 3); + return new JsDate(convertToUTCString); + } + + /** + * Determines the UTC suffix to use for display. + * Returns the displaySuffix if set, otherwise uses the default based on + * timeFormat. + */ + private String determineUtcSuffix() { + if (displaySuffix != null && !displaySuffix.isEmpty()) { + return displaySuffix; + } + return full.equals(timeFormat) ? COORDINATED_UNIVERSAL_TIME : UTC; + } + + private String appendSuffix(String dateAsString) { + String suffixToUse = ""; + if (shouldDisplayUTC) { + suffixToUse = determineUtcSuffix(); + } else if (displaySuffix != null && !displaySuffix.isEmpty()) { + suffixToUse = displaySuffix; + } + + if (!suffixToUse.isEmpty()) { + return dateAsString + " " + suffixToUse; + } + return dateAsString; + } + + /** + * Formats the datetime attribute for semantic HTML compliance. + * Always uses ISO format regardless of display formatting. + */ + private String formatDateTimeAttribute() { + Date dateToFormat = (dateTime != null) ? dateTime : new Date(); + JsDate jsDate = new JsDate((double) dateToFormat.getTime()); + return jsDate.toISOString(); + } +} diff --git a/components/src/main/java/org/patternfly/component/timestamp/TimestampFormat.java b/components/src/main/java/org/patternfly/component/timestamp/TimestampFormat.java new file mode 100644 index 000000000..ebf0ba1d2 --- /dev/null +++ b/components/src/main/java/org/patternfly/component/timestamp/TimestampFormat.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.component.timestamp; + +/** + * Enum representing various timestamp formats–for {@code dateStyle} and + * {@code timeStyle}–based on the Intl.DateTimeFormat + * API. + * + *

+ * The formats correspond to the standard JavaScript Intl.DateTimeFormat + * options: + *

+ *
    + *
  • {@code full} - Tuesday, August 9, 2022 | 11:25:00 AM Eastern + * Daylight Time
  • + *
  • {@code long} - August 9, 2022 | 11:25:00 AM EDT
  • + *
  • {@code medium} - Aug 9, 2022 | 11:25:00 AM
  • + *
  • {@code short} - 8/9/22 | 11:25 AM
  • + *
+ */ +public enum TimestampFormat { + full("full"), + _long("long"), + medium("medium"), + _short("short"); + + public final String value; + + TimestampFormat(String value) { + this.value = value; + } +} diff --git a/core/src/main/java/org/patternfly/style/Classes.java b/core/src/main/java/org/patternfly/style/Classes.java index 7204d0d99..35f9891e3 100644 --- a/core/src/main/java/org/patternfly/style/Classes.java +++ b/core/src/main/java/org/patternfly/style/Classes.java @@ -273,6 +273,7 @@ public interface Classes { String thead = "thead"; String thumb = "thumb"; String tick = "tick"; + String timestamp = "timestamp"; String title = "title"; String titleCell = "title-cell"; String toast = "toast"; diff --git a/showcase/common/src/bundle/components.json b/showcase/common/src/bundle/components.json index 0e0bef5c6..30fc22137 100644 --- a/showcase/common/src/bundle/components.json +++ b/showcase/common/src/bundle/components.json @@ -617,7 +617,8 @@ "timestamp": { "name": "timestamp", "title": "Timestamp", - "route": "/components/date-and-time/timestamp", + "route": "/components/timestamp", + "clazz": "org.patternfly.component.timestamp.Timestamp", "illustration": "timestamp.png", "summary": "A timestamp is a consistently formatted visual that displays date and time values." }, diff --git a/showcase/common/src/main/java/org/patternfly/showcase/component/TimestampComponent.java b/showcase/common/src/main/java/org/patternfly/showcase/component/TimestampComponent.java new file mode 100644 index 000000000..6f86a3eb1 --- /dev/null +++ b/showcase/common/src/main/java/org/patternfly/showcase/component/TimestampComponent.java @@ -0,0 +1,116 @@ +/* + * Copyright 2023 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.patternfly.showcase.component; + +import java.util.Date; + +import org.jboss.elemento.router.Route; +import org.patternfly.component.timestamp.CustomFormat; +import org.patternfly.component.timestamp.TimestampFormat; +import org.patternfly.component.timestamp.DateTimeFormatOptions.Day; +import org.patternfly.component.timestamp.DateTimeFormatOptions.Hour; +import org.patternfly.component.timestamp.DateTimeFormatOptions.Month; +import org.patternfly.component.timestamp.DateTimeFormatOptions.Weekday; +import org.patternfly.component.timestamp.DateTimeFormatOptions.Year; +import org.patternfly.component.timestamp.Timestamp; +import org.patternfly.showcase.Snippet; +import org.patternfly.showcase.SnippetPage; + +import static org.jboss.elemento.Elements.br; +import static org.jboss.elemento.Elements.div; +import static org.patternfly.component.timestamp.Timestamp.timestamp; +import static org.patternfly.showcase.ApiDoc.Type.component; +import static org.patternfly.showcase.Code.code; +import static org.patternfly.showcase.Data.components; +import static org.patternfly.style.Classes.timestamp; + +@Route(value = "/components/timestamp", title = "Timestamp") +public class TimestampComponent extends SnippetPage { + + public TimestampComponent() { + super(components.get(timestamp)); + + startExamples(); + addSnippet(new Snippet("timestamp-default", "Default", + code("timestamp-default"), () -> { + // @code-start:timestamp-default + return div() + .add(timestamp()) + .add(br()) + .add(timestamp().utc(true)) + .add(br()) + .add(timestamp().timeFormat(TimestampFormat._short)) + .element(); + // @code-end:timestamp-default + })); + + addSnippet(new Snippet("timestamp-basic-formats", "Basic formats", + code("timestamp-basic-formats"), () -> { + // @code-start:timestamp-basic-formats + Date currentDateTime = new Date(); + return div() + .add(timestamp().dateTime(currentDateTime) + .dateFormat(TimestampFormat.full) + .timeFormat(TimestampFormat.full)) + .add(br()).add(br()) + .add(timestamp().dateTime(currentDateTime) + .dateFormat(TimestampFormat.full)) + .add(br()).add(br()) + .add(timestamp().dateTime(currentDateTime) + .timeFormat(TimestampFormat.full)) + .add(br()).add(br()) + .add(timestamp().dateTime(currentDateTime) + .dateFormat(TimestampFormat.medium) + .timeFormat(TimestampFormat._short) + .displaySuffix("US Eastern")) + .element(); + // @code-end:timestamp-basic-formats + })); + + addSnippet(new Snippet("timestamp-custom-format", "Custom format", + code("timestamp-custom-format"), () -> { + // @code-start:timestamp-custom-format + Date currentDate = new Date(); + + return div() + .add(timestamp().dateTime(currentDate) + .customFormat(CustomFormat.create() + .weekday(Weekday._short) + .day(Day.numeric) + .month(Month._short) + .year(Year._2digit) + .hour(Hour._2digit))) + .element(); + // @code-end:timestamp-custom-format + })); + + addSnippet(new Snippet("timestamp-custom-content", "Custom content", + code("timestamp-custom-content"), () -> { + // @code-start:timestamp-custom-content + Date pastDateTime = new Date(122, 7, 9, 14, 57); + return div() + .add(timestamp("1 hour ago").dateTime(pastDateTime)) + .add(br()).add(br()) + .add(timestamp("Last updated August 9th, 2022 at 2:57 PM EDT") + .dateTime(pastDateTime)) + .element(); + // @code-end:timestamp-custom-content + })); + + startApiDocs(Timestamp.class); + addApiDoc(Timestamp.class, component); + } +}