How do I format [future, non-current] dates in Eleventy + Nunjucks? - node.js

I'm building a site with a CMS (Netlify) for a local band, and they have future gig dates they will put on the site. So far the dates show up as very long non-formatted strings that include the time and time zone. I'm trying to figure out how to format the dates to be simpler (day, date, time for example).
I've tried plugins like nunjucks-date but I'm a little confused about how to use a plugin (and filters) in this case.
My repo: https://github.com/mollycarroll/serapis-eleventy-2
Example gig entry:
---
layout: gig
venue: Cedar Lake Cellars
date: 2022-05-28
time: 6pm
city: Wright City, MO
---
Gig template:
<h2>{{ venue }}</h2>
<h4>{{ city }} {{ date }} {{ time }}</h4>
config.yml for the CMS:
- name: 'gigs'
label: 'Shows'
folder: 'src/gigs'
create: true
slug: '{{month}}-{{day}}-{{venue}}'
fields:
- { label: 'Layout', name: 'layout', widget: 'hidden', default: '_includes/gig.njk' }
- { label: 'Date', name: 'date', widget: 'date', default: '' }
- { label: 'Time', name: 'time', widget: 'string', default: '' }
- { label: 'Venue', name: 'venue', widget: 'string', default: '' }
- { label: 'City', name: 'city', widget: 'string', default: '' }
Thanks for any help.

First, you should create a filter, let's say src/filters/date.js with the following content:
const { DateTime } = require("luxon");
// Add a friendly date filter to nunjucks.
// Defaults to format of LLLL d, y unless an
// alternate is passed as a parameter.
// {{ date | friendlyDate('OPTIONAL FORMAT STRING') }}
// List of supported tokens: https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens
module.exports = (dateObj, format = 'LLLL d, y') => {
return DateTime.fromISO(dateObj, { zone: "Europe/Amsterdam", locale: "en" }).toFormat(format);
};
Make sure you check Luxon documentation for details. Then add the filter in .eleventy.js:
module.exports = function(eleventyConfig) {
...
eleventyConfig.addFilter("date", require("./src/filters/date.js"));
...
};
Now you can use it in Nunjacks with a default value {{ date }}, in this example 'LLLL d, y', or any value you need at a certain position on your website {{ date | date('dd. LLLL yyyy.') }}. This can be very useful if you need at some point just month and year or just day and month.
You can even create multiple language filters, like dateEn.js and dateDe.js, and format each to its own language if you have a multilingual site.
Hope this helps.
EDIT: In order for this filter to work the dateObj should be in ISO 8601 format.

Related

Best strategy for Angular Front-End Form Building by Users [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 3 years ago.
Improve this question
Good day, whoever reads this, thanks for taking the time to possibly assist!
Back in the day, I used to work a lot with Wordpress (PHP) and there was this plugin we used to gather metadata: Advanced Custom Fields (advancedcustomfields . com). What made it cool was that you could visually set up groups of questions (a form if you will), by selecting the types of questions and configure their setup and style (input with label in inside or outside, or, table with rows and columns specifying each key alongside which the answer would be saved against in the database).
I'm looking to build the exact same thing in Angular 8+, allowing my client to choose whatever type of field (input) they want and group them together. How do you suggest I go about this:
1) build custom components like: text input/area, radio, table, map, image, file upload, checkboxes, date/time pickers, select boxes, groups etc (each carrying conditional rules to show or not depending on some other component)... and then let the user choose the relevant parameters for each component and send them to the component ngOnInit() with #Input or a service?
2) does a similar package already exist for me to leverage such functionality quicker?
Appreciate the advice and input :)
Rgds,
Wzz
Have a look at ngx-formly. Another option is ng-dynamic-forms. These libraries have dynamically configurable input elements section.
ngx-formly code sample from their demo below:
app.component.ts
import { Component } from '#angular/core';
import {FormGroup} from '#angular/forms';
import {FormlyFieldConfig} from '#ngx-formly/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
form = new FormGroup({});
model = {};
fields: FormlyFieldConfig[] = [
{
key: 'input',
type: 'input',
templateOptions: {
label: 'Input',
placeholder: 'Input placeholder',
required: true,
}
},
{
key: 'textarea',
type: 'textarea',
templateOptions: {
label: 'Textarea',
placeholder: 'Textarea placeholder',
required: true,
}
},
{
key: 'checkbox',
type: 'checkbox',
templateOptions: {
label: 'Checkbox',
}
},
{
key: 'select',
type: 'select',
templateOptions: {
label: 'Select',
placeholder: 'Select placeholder',
required: true,
options: [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
{ label: 'Option 3', value: '3' },
]
}
},
{
key: 'radio',
type: 'radio',
templateOptions: {
label: 'Radio',
required: true,
options: [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
]
}
}
];
onSubmit() {
if (this.form.valid) {
alert(JSON.stringify(this.model, null, 2));
}
}
}
app.component.html
<div class="header">
<img src="https://raw.githubusercontent.com/ngx-formly/ngx-formly/v5/logo.svg?sanitize=true" alt="" width="72" height="72">
<h4 class="mat-h2">Angular Formly Material</h4>
</div>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<formly-form
[form]="form"
[model]="model"
[fields]="fields">
</formly-form>
<button type="submit" color="primary" mat-raised-button>
Submit
</button>
<button type="reset" color="warn" mat-raised-button>
Reset
</button>
</form>

Default value for images in apostrophe cms?

I have a custom widget:
module.exports = {
extend: 'apostrophe-widgets',
label: 'Banner',
addFields: [
{
name: 'bannerImg',
type: 'attachment',
label: 'Picture',
def: 'http://via.placeholder.com/350x150'
}
]
};
And widget view:
<img class="logo" src="{{ apos.attachments.url(data.widget.bannerImg) }}" />
If I load image It's Ok I see it. But I don't have the default value. Also can I choose file from gallery without upload?
I spent a half of the day and found the solution:
as answered in: How to define widgets with default values in Apostrophe CMS
{% if apos.areas.isEmpty(data.widget, 'bannerImg') %}
<h1>Default Value</h1>
{% endif %}
{{ apos.singleton(data.widget, 'bannerImg', 'apostrophe-images', { limit: 1 }) }}
And also if we want to get href of this images:
{{ apos.attachments.url(apos.images.first(data.widget.bannerImg)) }}
Also in index.js I changed on:
{
name: 'bannerImg',
type: 'singleton',
label: 'Banner',
widgetType: 'apostrophe-images',
options: {
limit: 1
}
},

Can you add separators to dropdown menus in activeadmin

Is there a way to add separators to a dropdown menu in activeadmin?
For example, if I wanted a separator between the first and second items, how can I do that?
menu.add label: 'Tasks', priority: 10 do |tasks|
tasks.add label: 'Add News Item',
url: proc { new_feed_path },
if: proc { authorized? :create, Feed },
priority: 14
tasks.add label: 'Add Calendar Event',
url: proc { new_event_path },
if: proc { authorized? :create, Event },
priority: 15
end
I checked the documentation but don't seem to see anything for that.
As of writing this comment, ActiveAdmin is at version 1.2.1 and based on its code, it isn't possible to add separators/dividers in a dropdown menu. :(
I just checked on the Github repo and they have no opened issue nor pull request matching the "separator" or "divider" keywords.
Maybe the first step would be to open an issue describing what and how to implement it.
Nothing is preventing us from adding a divider manually:
menu.add label: 'Tasks', priority: 10 do |tasks|
tasks.add label: 'Add News Item',
url: proc { new_feed_path },
if: proc { authorized? :create, Feed },
priority: 14
tasks.add label: "<hr>".html_safe,
url: "javascript:void(0)",
priority: 15
tasks.add label: 'Add Calendar Event',
url: proc { new_event_path },
if: proc { authorized? :create, Event },
priority: 16
end
a url attribute is required so using javascript:void(0) is an option here as # will not render the label. This question discusses javascript:void(0)

Building dynamic HighCharts and image Highcharts with (mostly) one codebase?

We're already creating dynamic HighCharts for our webpages--these have a few javascript dependencies and a chart-generation script. We'd like to start creating PDFs of these charts using the new HighCharts/Node/PhantomJS suite HighCharts has rigged up (see press release). Our image-gen node server would run on a separate box/vm. How can we do this without having to maintain two separate codebases for the same chart? I'm not too familiar with Node yet, so I'm not sure how requesting the scripts with a web request would work. I'm guessing a lot of HighCharts users that want to start generating some of their charts as images server-side will run into a similar issue with managing two related codesets...
In essence, we already have have this:
Webserver -> JSON (data) + foo.js + bar.js + foo.html -> webpage with dynamic charts.
We'd like to build:
Web-server -> JSON (data) + separate Node Server + foo.js + bar.js -> images available via web request
Obviously some redundancy. How can we manage the dependencies?
While node is awesome, I felt that approach was needlessly complex, with having to many moving parts that could break. So I did the super simple solution of creating files dynamically. The only problem i faced was deleting the temporary file after adding it to the pdf. It would break the PDF from rendering. And setting the directory to /tmp, crashed phantomjs. The best idea i came up with currently is putting the tempory generated files, in a temp directory, then deleting everything in that directory every night, with a cronjob.
I post this out of code simplicity. It should be in a function, to maintain code re-usability.
<?php
$TmpInFileName = 'tmp/graph_'.md5($CurrentDate.rand(666,9482845713)).'.js';
$TmpGraphFileName = 'tmp/pnggraph_'.md5($CurrentDate.rand(2666,54713)).'.png';
$Data = "
{
chart: {
zoomType: 'xy',
width: 700,
height: 520
},
credits: {
enabled: false
},
colors: [
'#2f7ed8',
'#910000',
'#8bbc21',
'#1aadce',
'#492970',
'#f28f43',
'#77a1e5',
'#c42525',
'#a6c96a'
],
title: {
text: 'Sample Graph - created at ".date('m/d/Y g:i:s a')."',
style: {
fontSize: '16px',
}
},
xAxis: [{
categories: ['00:00', '00:15', '00:30', '00:45', '01:00', '01:15', '01:30']
}],
yAxis: [{
labels: {
format: '{value}',
style: {
fontSize: '14px',
color: Highcharts.getOptions().colors[1]
}
},
title: {
text: 'Y axis',
style: {
fontSize: '16px',
color: Highcharts.getOptions().colors[1]
}
}
}, { // Secondary yAxis
title: {
text: 'Sec Yaxis',
style: {
fontSize: '16px',
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '{value}',
style: {
fontSize: '14px',
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}],
tooltip: {
shared: true
},
legend: {
layout: 'horizontal',
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
},
series: [{
name: 'first',
type: 'spline',
yAxis: 1,
data: [0, -119.9502311075212, -119.96203992145706, -119.98172620218355, -119.71898290168028, -119.97023935590325, -119.95230287195413]
},
{
name: 'second',
type: 'spline',
yAxis: 1,
data: [0, -119.24222667756482, -119.60905809195222, -119.63522965403729, -119.11011466187935, -119.63643171374981, -119.54969080301575]
},{
name: 'third',
type: 'column',
data: [10, 11, 9, 7, 5, 2, 7]
},{
name: 'fourth',
type: 'column',
data: [0, -0.7080044299563895, -0.35298182950484147, -0.34649654814626274, -0.6088682398009269, -0.33380764215343106, -0.40261206893838164]
}]
}";
try {
$myfile = fopen($TmpInFileName, "w") or die("Unable to open file!");
fwrite($myfile, $Data);
fclose($myfile);
} catch (Exception $e) {
echo 'Error: '.$e.' <br />';
}
$URL_Command = "phantomjs /highcharts/exporting-server/phantomjs/highcharts-convert.js -infile $TmpInFileName -outfile $TmpGraphFileName -width 600";
exec($URL_Command);
echo '<img src="'.$TmpGraphFileName.'" alt="Could not load img: '.$TmpGraphFileName.'">';
?>
I hope this helps. I couldn't find a good solution that didn't involve Node.JS or Java to do this. I wanted a pure PHP solution.
We decided to pass the entire highcharts config object (e.g. Highcharts.chart(configObj)) to the node server as a URL-encoded string. We had to put a few rendering functions over on the node server, but it wasn't too bad. We also stuck some of the rendering functions in the string config object. Not the most beautiful result, but it worked.

Why does my gridPanel in a tabPanel show the wrong height?

In the attached image, the grid does not show properly. The grid is inside a tabpanel. The layout of the tab is = 'fit'.
What setting error is causing the behavior?
EDIT:
Here is the class definition for the tabpanel: Our tab is the one called 'External ID'
/*
* File: SomeTabPanel.ui.js
* Date: Mon May 02 2011 18:08:34 GMT-0400 (Eastern Daylight Time)
*
* This file was generated by Ext Designer version xds-1.0.3.2.
* http://www.extjs.com/products/designer/
*
* This file will be auto-generated each and everytime you export.
*
* Do NOT hand edit this file.
*/
SomeTabPanelUi = Ext.extend(Ext.TabPanel, {
activeTab: 0,
forceLayout: true,
border: false,
enableTabScroll: true,
initComponent: function() {
this.items = [{
xtype: 'panel',
title: 'General',
layout: 'table',
tpl: '',
ref: 'GeneralTab',
layoutConfig: {
columns: 2
},
items: [{
xtype: 'form',
title: 'Corporate',
height: 500,
width: 500,
animCollapse: false,
items: [{
xtype: 'box',
ref: '../../coporateBox'
}]
}]
},{
xtype: 'panel',
title: 'External ID',
layout: 'fit',
ref: 'ExtIdTab',
id: ''
}];
SomeTabPanelUi.superclass.initComponent.call(this);
}
});
Looks like you need to set a height for the grid somehow. Either a manual height declaration, autoHeight: true, or inherited height from a parent container.
Does the parent tabPanel have a height declared/inherited?
Setting layout: 'fit' is a good start for the containing tab, but without some code or a test case, I can't be more helpful.
It should work as described, so you must have something wrong in your code. Post your layout code if you want more help.

Resources