enhance iconify usage and tune editor styles

This commit is contained in:
Reorx 2023-02-03 00:53:36 +08:00
parent 3c8ac17617
commit 0a28944eea
6 changed files with 236 additions and 22 deletions

View File

@ -1,11 +1,64 @@
@mixin button-base {
appearance: none;
user-select: none;
vertical-align: middle;
outline: 0;
display: inline-block;
cursor: pointer;
position: relative;
}
@mixin normal-button {
@include button-base;
background-color: #eee;
border: 1px solid transparent;
border-radius: 2px;
padding: 0px 8px;
line-height: 22px;
&:hover {
background-color: #e1e1e1;
}
&:active {
border-color: #555;
}
}
@mixin text-button {
@include button-base;
background-color: transparent;
padding: 0;
font-size: 12px;
line-height: 1;
color: #555;
&:hover {
border-bottom: 1px solid #999;
}
&:active {
border-color: transparent;
border-bottom: 1px solid #000;
}
}
.editor-container {
font-size: 14px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
--gap: 8px;
--blue-0: #D0EBFF;
--blue-1: #A5D8FF;
--red-0: #FFE3E3;
--red-1: #FFC9C9;
--yellow-0: #FFF3BF;
--yellow-1: #FFEC99;
--green-0: #D3F9D8;
--green-1: #B2F2BB;
h1 {}
h2 {}
h3 {}
h3 {
margin: 12px 0 12px 0;
}
p {
margin: 0 0 var(--gap) 0;
}
@ -18,12 +71,46 @@
line-height: 1.3;
padding: var(--gap);
}
input[type=text],
input[type=email],
textarea {
border: 1px solid #888;
border-radius: 2px;
}
button {
@include normal-button;
margin-right: var(--gap);
// last-of-type should not be used here
&:last-child {
margin-right: 0;
}
svg {
vertical-align: middle;
font-size: 14px;
position: relative;
bottom: 1px;
}
}
iconify-icon {
font-size: 15px;
}
.je-header {
label {
font-weight: 700;
vertical-align: middle;
}
}
// override theme-default
.je-indented-panel {
padding-left: var(--gap);
margin-left: var(--gap);
border-left: 1px solid #ccc
padding-left: calc(var(--gap) * 2);
padding-bottom: var(--gap);
margin-left: 0;
border-left: 1px solid #ddd;
margin-bottom: var(--gap);
}
.je-indented-panel--top {
@ -31,10 +118,6 @@
margin-left: var(--gap);
}
.je-object__container {
}
.form-control {
margin-bottom: var(--gap);
}
@ -42,7 +125,7 @@
.je-form-input-label {
display: block;
margin-bottom: calc(var(--gap) / 2);
font-weight: bold;
font-weight: 500;
}
.je-form-input-description {
margin: 0;
@ -63,6 +146,36 @@
border-bottom: 1px solid #ccc;
}
/* buttons */
.je-object__controls {
display: inline-block;
position: relative;
margin-left: calc(var(--gap) * 2);
top: 2px;
button {
@include text-button;
}
}
.json-editor-btn-add {
background-color: var(--green-0);
&:hover {
background-color: var(--green-1);
}
}
.json-editor-btn-subtract {
background-color: var(--yellow-0);
&:hover {
background-color: var(--yellow-1);
}
}
.json-editor-btn-delete {
background-color: var(--red-0);
&:hover {
background-color: var(--red-1);
}
}
.je-textarea {
height: 150px;
min-height: 150px;

40
editor/iconlib.js Normal file
View File

@ -0,0 +1,40 @@
import { AbstractIconLib } from '@json-editor/json-editor/src/iconlib.js';
import { getIconSVG } from '../icons';
const iconMapping = {
collapse: 'mdi:chevron-down',
expand: 'mdi:chevron-right',
delete: 'mdi:delete',
edit: 'mdi:pen',
add: 'mdi:plus',
subtract: 'mdi:minus',
cancel: 'mdi:cancel',
save: 'mdi:content-save',
moveup: 'mdi:arrow-up',
moveright: 'mdi:arrow-right',
movedown: 'mdi:arrow-down',
moveleft: 'mdi:arrow-left',
copy: 'mdi:content-copy',
clear: 'mdi:close-circle',
time: 'mdi:clock',
calendar: 'mdi:calendar',
edit_properties: 'mdi:format-list-bulleted',
}
export class MyIconLib extends AbstractIconLib {
getIcon(key) {
const svg = getIconSVG(iconMapping[key], {dom: true})
return svg
// const i = document.createElement('iconify-icon')
// i.setAttribute('icon', )
// return i
}
}
export function registerIconLib(JSONEditor) {
JSONEditor.defaults.iconlibs['myiconlib'] = MyIconLib
}

View File

@ -1,11 +1,17 @@
import 'iconify-icon'; // import only
import objectPath from 'object-path';
import { JSONEditor } from '@json-editor/json-editor/dist/jsoneditor';
import * as exampleData from '../sample.resume.json';
import * as jsoncvSchema from '../schema/jsoncv.schema.json';
import * as jsoncvSchemaModule from '../schema/jsoncv.schema.json';
import { registerIconLib } from './iconlib';
import { registerTheme } from './theme';
import { createElement } from './utils';
import {
createElement,
traverseDownObject,
} from './utils';
const propertiesInOrder = ['basics', 'education', 'work', 'skills', 'projects', 'languages', 'interests', 'references', 'awards', 'publications', 'volunteer']
const basicsPropertiesInOrder = ['name', 'label', 'email', 'phone', 'url', 'summary', 'image', 'location', 'profiles']
@ -19,7 +25,9 @@ const basicsUl = createElement('ul', {
parent: tocUl
})
const attrSchemaPathTo = 'data-schemapath-to'
// copy the object to remove the readonly restriction on module
const jsoncvSchema = {...jsoncvSchemaModule.default}
// add propertyOrder to schema, and add links to toc
propertiesInOrder.forEach((name, index) => {
@ -50,6 +58,15 @@ basicsPropertiesInOrder.forEach((name, index) => {
})
})
// add headerTemplate for each type:array in schema
traverseDownObject(jsoncvSchema, (key, obj) => {
let noun = key
if (noun.endsWith('s')) noun = noun.slice(0, -1)
if (obj.type === 'array' && obj.items) {
obj.items.headerTemplate = `${noun} {{i1}}`
}
})
// add format to schema
const keyFormatMap = {
'basics.properties.summary': 'textarea',
@ -58,12 +75,17 @@ for (const [key, format] of Object.entries(keyFormatMap)) {
objectPath.get(jsoncvSchema.properties, key).format = format
}
// change schema title
jsoncvSchema.title = 'Resume'
// initialize editor
registerTheme(JSONEditor)
registerIconLib(JSONEditor)
const elEditorContainer = document.querySelector('.editor-container')
const editor = new JSONEditor(elEditorContainer, {
schema: jsoncvSchema,
theme: 'mytheme',
iconlib: 'myiconlib',
});
editor.on('ready',() => {
editor.setValue(exampleData)
@ -72,6 +94,5 @@ editor.on('ready',() => {
document.querySelectorAll('[data-schemapath]').forEach(el => {
const schemapath = el.getAttribute('data-schemapath')
el.id = schemapath
console.log('el', schemapath)
})
})

View File

@ -14,3 +14,13 @@ export const createElement = function(tagName, {className, text, attrs, parent})
}
return el
}
export const traverseDownObject = function(obj, callback) {
for (const key in obj) {
const value = obj[key]
if (typeof value === 'object') {
callback(key, value)
traverseDownObject(value, callback)
}
}
}

45
package-lock.json generated
View File

@ -8,10 +8,11 @@
"name": "jsoncv",
"version": "1.0.0",
"dependencies": {
"@iconify/json": "^2.2.15",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"dayjs": "^1.11.7",
"iconify-icon": "^1.0.0",
"iconify-icon": "^1.0.3",
"object-path": "^0.11.8"
},
"devDependencies": {
@ -86,6 +87,15 @@
"@iconify/types": "*"
}
},
"node_modules/@iconify/json": {
"version": "2.2.15",
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.2.15.tgz",
"integrity": "sha512-+BVLIjTJpBiEOGD3xhCY7/ajH+7QTl/jzF59gf9Hf5y/HyU8D+HUmOsXEGLIsCZErEQB66wZ36AziOlYf3wuPA==",
"dependencies": {
"@iconify/types": "*",
"pathe": "^1.0.0"
}
},
"node_modules/@iconify/types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
@ -847,14 +857,14 @@
}
},
"node_modules/iconify-icon": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-1.0.0.tgz",
"integrity": "sha512-UY4PDCKQPpIGgDIx2yxM8wiOdMdLz0mb93dTV0Ox5hThwO8OA2zy8gDmjRReKqkPHK/mY7p/ivDaDGHE8O9xIw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-1.0.3.tgz",
"integrity": "sha512-pyWLbx8IBfD2G3M0hULuvUBwoowrZtXEKyeAXhD2AlbNYTSDPmWGhgPYaRAnVIuBjMAZ4dCyEHmaYgnlDZc0XQ==",
"dependencies": {
"@iconify/types": "^2.0.0"
},
"funding": {
"url": "http://github.com/sponsors/cyberalien"
"url": "https://github.com/sponsors/cyberalien"
}
},
"node_modules/immutable": {
@ -1196,6 +1206,11 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/pathe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz",
"integrity": "sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w=="
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -1975,6 +1990,15 @@
"@iconify/types": "*"
}
},
"@iconify/json": {
"version": "2.2.15",
"resolved": "https://registry.npmjs.org/@iconify/json/-/json-2.2.15.tgz",
"integrity": "sha512-+BVLIjTJpBiEOGD3xhCY7/ajH+7QTl/jzF59gf9Hf5y/HyU8D+HUmOsXEGLIsCZErEQB66wZ36AziOlYf3wuPA==",
"requires": {
"@iconify/types": "*",
"pathe": "^1.0.0"
}
},
"@iconify/types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
@ -2436,9 +2460,9 @@
"dev": true
},
"iconify-icon": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-1.0.0.tgz",
"integrity": "sha512-UY4PDCKQPpIGgDIx2yxM8wiOdMdLz0mb93dTV0Ox5hThwO8OA2zy8gDmjRReKqkPHK/mY7p/ivDaDGHE8O9xIw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-1.0.3.tgz",
"integrity": "sha512-pyWLbx8IBfD2G3M0hULuvUBwoowrZtXEKyeAXhD2AlbNYTSDPmWGhgPYaRAnVIuBjMAZ4dCyEHmaYgnlDZc0XQ==",
"requires": {
"@iconify/types": "^2.0.0"
}
@ -2692,6 +2716,11 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"pathe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz",
"integrity": "sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w=="
},
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",

View File

@ -16,10 +16,11 @@
"vite-plugin-handlebars": "^1.6.0"
},
"dependencies": {
"@iconify/json": "^2.2.15",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"dayjs": "^1.11.7",
"iconify-icon": "^1.0.0",
"iconify-icon": "^1.0.3",
"object-path": "^0.11.8"
}
}