Fold each group of settings into an open card
The long help for the download template and the date format now folds shut.
This commit is contained in:
@@ -227,9 +227,9 @@ export function globalRulesCard() {
|
|||||||
.catch(showError);
|
.catch(showError);
|
||||||
|
|
||||||
return h(
|
return h(
|
||||||
'section',
|
'details',
|
||||||
{ class: 'card' },
|
{ class: 'card', open: true },
|
||||||
h('h2', {}, 'Global replacement rules'),
|
h('summary', {}, h('h2', {}, 'Global replacement rules')),
|
||||||
h(
|
h(
|
||||||
'p',
|
'p',
|
||||||
{ class: 'hint' },
|
{ class: 'hint' },
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ const DEFAULTS_INI = 'https://github.com/JimmXinu/FanFicFare/blob/main/fanficfar
|
|||||||
const TEMPLATE_DOCS = 'https://manual.calibre-ebook.com/template_lang.html';
|
const TEMPLATE_DOCS = 'https://manual.calibre-ebook.com/template_lang.html';
|
||||||
const DATE_CODES = 'https://docs.python.org/3/library/datetime.html#format-codes';
|
const DATE_CODES = 'https://docs.python.org/3/library/datetime.html#format-codes';
|
||||||
const code = (text) => h('code', {}, text);
|
const code = (text) => h('code', {}, text);
|
||||||
|
// A card of settings that folds shut. It starts open.
|
||||||
|
const card = (title, ...children) =>
|
||||||
|
h('details', { class: 'card', open: true }, h('summary', {}, h('h2', {}, title)), ...children);
|
||||||
|
|
||||||
export function settingsPage(main, _params, config) {
|
export function settingsPage(main, _params, config) {
|
||||||
document.title = 'Settings · Bindery';
|
document.title = 'Settings · Bindery';
|
||||||
@@ -104,11 +107,9 @@ export function settingsPage(main, _params, config) {
|
|||||||
|
|
||||||
fill(
|
fill(
|
||||||
main,
|
main,
|
||||||
h(
|
|
||||||
'section',
|
|
||||||
{ class: 'card' },
|
|
||||||
h('h1', {}, 'Settings'),
|
h('h1', {}, 'Settings'),
|
||||||
h('h2', {}, 'Recheck recent chapters'),
|
card(
|
||||||
|
'Recheck recent chapters',
|
||||||
h(
|
h(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'controls' },
|
{ class: 'controls' },
|
||||||
@@ -124,10 +125,8 @@ export function settingsPage(main, _params, config) {
|
|||||||
),
|
),
|
||||||
saveButton(() => ({ recent_chapters: recent.value === '' ? 0 : Number(recent.value) })),
|
saveButton(() => ({ recent_chapters: recent.value === '' ? 0 : Number(recent.value) })),
|
||||||
),
|
),
|
||||||
config.cwa_enabled && h(
|
config.cwa_enabled && card(
|
||||||
'section',
|
'Uploads to CWA',
|
||||||
{ class: 'card' },
|
|
||||||
h('h2', {}, 'Uploads to CWA'),
|
|
||||||
h('label', {}, linkBooks, ' Link books to CWA library'),
|
h('label', {}, linkBooks, ' Link books to CWA library'),
|
||||||
h(
|
h(
|
||||||
'p',
|
'p',
|
||||||
@@ -161,31 +160,30 @@ export function settingsPage(main, _params, config) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
h(
|
card(
|
||||||
'section',
|
'Book Downloads',
|
||||||
{ class: 'card' },
|
|
||||||
h('h2', {}, 'Book Downloads'),
|
|
||||||
h('div', { class: 'controls' }, h('label', { for: 'download-template' }, 'File name template'), template),
|
h('div', { class: 'controls' }, h('label', { for: 'download-template' }, 'File name template'), template),
|
||||||
h(
|
h(
|
||||||
'p',
|
'p',
|
||||||
{ class: 'hint' },
|
{ class: 'hint' },
|
||||||
'This template gives the file name of a book that you download from a story page. It follows the ',
|
'This template gives the file name of a book that you download from a story page. To go back to the ' +
|
||||||
externalLink(TEMPLATE_DOCS, 'template rules of Calibre'),
|
'default, ',
|
||||||
' for file names. Bindery replaces each field in braces with the value of the book, and adds .epub. ' +
|
code('{title} - {authors}'),
|
||||||
'A field with no value becomes empty text. To go back to the default, {title} - {authors}, clear the field ' +
|
', clear the field and save.',
|
||||||
'and save. ' +
|
|
||||||
'For example, ',
|
|
||||||
code('{series:|| - }{series_index:0>2s|| - }{title} - {authors}'),
|
|
||||||
' gives "Saga, The - 02 - Book, The - Ann Writer.epub".',
|
|
||||||
),
|
),
|
||||||
h('div', { class: 'controls' }, h('label', { for: 'download-date-format' }, 'Date format'), dateFormat),
|
h(
|
||||||
|
'details',
|
||||||
|
{ class: 'help' },
|
||||||
|
h('summary', {}, 'File name template help'),
|
||||||
h(
|
h(
|
||||||
'p',
|
'p',
|
||||||
{ class: 'hint' },
|
{ class: 'hint' },
|
||||||
'The form of the dates in {pubdate}, {timestamp} and {last_modified}. %d gives the day, %b the month name, ' +
|
'The template follows the ',
|
||||||
'%m the month number and %Y the year. See the ',
|
externalLink(TEMPLATE_DOCS, 'template rules of Calibre'),
|
||||||
externalLink(DATE_CODES, 'list of all codes'),
|
' for file names. Bindery replaces each field in braces with the value of the book, and adds .epub. ' +
|
||||||
'. To go back to the default, %b, %Y, clear the field and save. The default gives "May, 2020".',
|
'A field with no value becomes empty text. For example, ',
|
||||||
|
code('{series:|| - }{series_index:0>2s|| - }{title} - {authors}'),
|
||||||
|
' gives "Saga, The - 02 - Book, The - Ann Writer.epub".',
|
||||||
),
|
),
|
||||||
h('p', { class: 'hint' }, 'You can use these fields:'),
|
h('p', { class: 'hint' }, 'You can use these fields:'),
|
||||||
h(
|
h(
|
||||||
@@ -229,6 +227,34 @@ export function settingsPage(main, _params, config) {
|
|||||||
),
|
),
|
||||||
h('li', {}, 'If the template fails or gives no name for a book, Bindery names the file after the title.'),
|
h('li', {}, 'If the template fails or gives no name for a book, Bindery names the file after the title.'),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
h('div', { class: 'controls' }, h('label', { for: 'download-date-format' }, 'Date format'), dateFormat),
|
||||||
|
h(
|
||||||
|
'p',
|
||||||
|
{ class: 'hint' },
|
||||||
|
'The form of the dates in {pubdate}, {timestamp} and {last_modified}. To go back to the default, ',
|
||||||
|
code('%b, %Y'),
|
||||||
|
', clear the field and save.',
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
'details',
|
||||||
|
{ class: 'help' },
|
||||||
|
h('summary', {}, 'Date format help'),
|
||||||
|
h(
|
||||||
|
'p',
|
||||||
|
{ class: 'hint' },
|
||||||
|
code('%d'),
|
||||||
|
' gives the day, ',
|
||||||
|
code('%b'),
|
||||||
|
' the month name, ',
|
||||||
|
code('%m'),
|
||||||
|
' the month number and ',
|
||||||
|
code('%Y'),
|
||||||
|
' the year. See the ',
|
||||||
|
externalLink(DATE_CODES, 'list of all codes'),
|
||||||
|
'. The default gives "May, 2020". A / in a date becomes _, as in Calibre.',
|
||||||
|
),
|
||||||
|
),
|
||||||
saveButton(
|
saveButton(
|
||||||
() => ({ download_template: template.value, download_date_format: dateFormat.value }),
|
() => ({ download_template: template.value, download_date_format: dateFormat.value }),
|
||||||
(settings) => {
|
(settings) => {
|
||||||
@@ -238,10 +264,8 @@ export function settingsPage(main, _params, config) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
h(
|
card(
|
||||||
'section',
|
'Jobs list',
|
||||||
{ class: 'card' },
|
|
||||||
h('h2', {}, 'Jobs list'),
|
|
||||||
h(
|
h(
|
||||||
'div',
|
'div',
|
||||||
{ class: 'controls' },
|
{ class: 'controls' },
|
||||||
@@ -274,10 +298,8 @@ export function settingsPage(main, _params, config) {
|
|||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
globalRulesCard(),
|
globalRulesCard(),
|
||||||
h(
|
card(
|
||||||
'section',
|
'FanFicFare settings (personal.ini)',
|
||||||
{ class: 'card' },
|
|
||||||
h('h2', {}, 'FanFicFare settings (personal.ini)'),
|
|
||||||
h(
|
h(
|
||||||
'p',
|
'p',
|
||||||
{ class: 'hint' },
|
{ class: 'hint' },
|
||||||
|
|||||||
@@ -1063,6 +1063,16 @@ textarea {
|
|||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Help that folds shut under a setting, such as the help for the download template. */
|
||||||
|
.help {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
|
||||||
|
> summary {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: var(--text-sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Toasts */
|
/* Toasts */
|
||||||
|
|
||||||
#toasts {
|
#toasts {
|
||||||
|
|||||||
+20
-1
@@ -55,7 +55,7 @@ for (const value of ['7', '']) {
|
|||||||
await settle();
|
await settle();
|
||||||
api.on('PUT', 'settings', {});
|
api.on('PUT', 'settings', {});
|
||||||
field(main, 'recent-chapters').value = value;
|
field(main, 'recent-chapters').value = value;
|
||||||
await click(section(main, 'Settings'), 'Save');
|
await click(section(main, 'Recheck recent chapters'), 'Save');
|
||||||
assert.deepEqual(api.sent('PUT', 'settings')[0].body, { recent_chapters: value === '' ? 0 : 7 });
|
assert.deepEqual(api.sent('PUT', 'settings')[0].body, { recent_chapters: value === '' ? 0 : 7 });
|
||||||
assert.match(ui.toasts.textContent, /Saved/);
|
assert.match(ui.toasts.textContent, /Saved/);
|
||||||
});
|
});
|
||||||
@@ -109,6 +109,25 @@ test('the jobs list settings load and save all four fields', async () => {
|
|||||||
assert.match(ui.toasts.textContent, /Saved/);
|
assert.match(ui.toasts.textContent, /Saved/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('each group of settings is an open card, and the download help starts closed', async () => {
|
||||||
|
settingsPage(main, {}, config);
|
||||||
|
await settle();
|
||||||
|
const cards = main.children.filter((el) => el.tagName !== 'h1');
|
||||||
|
assert.deepEqual(cards.map((el) => [el.tagName, el.className, el.open, el.children[0].textContent]), [
|
||||||
|
['details', 'card', true, 'Recheck recent chapters'],
|
||||||
|
['details', 'card', true, 'Uploads to CWA'],
|
||||||
|
['details', 'card', true, 'Book Downloads'],
|
||||||
|
['details', 'card', true, 'Jobs list'],
|
||||||
|
['details', 'card', true, 'Global replacement rules'],
|
||||||
|
['details', 'card', true, 'FanFicFare settings (personal.ini)'],
|
||||||
|
]);
|
||||||
|
const help = nodes(section(main, 'Book Downloads')).filter((el) => el.className === 'help');
|
||||||
|
assert.deepEqual(help.map((el) => [el.tagName, el.open, el.children[0].textContent]), [
|
||||||
|
['details', undefined, 'File name template help'],
|
||||||
|
['details', undefined, 'Date format help'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test('the download template loads, lists its fields, and saves the stored form', async () => {
|
test('the download template loads, lists its fields, and saves the stored form', async () => {
|
||||||
api.on('GET', 'settings', {
|
api.on('GET', 'settings', {
|
||||||
recent_chapters: 0, personal_ini: '', download_template: '{title}', download_date_format: '%b, %Y',
|
recent_chapters: 0, personal_ini: '', download_template: '{title}', download_date_format: '%b, %Y',
|
||||||
|
|||||||
Reference in New Issue
Block a user