initial mockup
commit
684ed78fb7
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"recommendations": ["johnsoncodehk.volar"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
# Vue 3 + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>reMARCable</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "remarcable",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.25"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^2.3.0",
|
||||
"vite": "^2.9.0"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,359 @@
|
|||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
|
||||
import MarcRecords from './components/MarcRecords.vue'
|
||||
import MarcFileUploader from './components/MarcFileUploader.vue'
|
||||
|
||||
const records = reactive([]);
|
||||
const marcFileLoaded = ref(false);
|
||||
|
||||
function onMarcFileLoaded(event) {
|
||||
marcFileLoaded.value = true;
|
||||
}
|
||||
|
||||
records.push(
|
||||
{
|
||||
leader: "01505nas 2200325 i 4500",
|
||||
directory: '4500001001400000003000800014005001700022006001900039007001500058008004100073022002500114040003500139050001000174082001500184245002600199264004600225300002200271310002100293336002100314337002300335338003200358362001000390500007400400520044900474588009200923650002601015710005301041776003101094856005401125',
|
||||
fields: [
|
||||
{
|
||||
tag: "022",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: '0022-2372'
|
||||
},
|
||||
{
|
||||
code: 'y',
|
||||
content: '1545-1532'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "040",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'StDuBDS'
|
||||
},
|
||||
{
|
||||
code: 'b',
|
||||
content: 'eng'
|
||||
},
|
||||
{
|
||||
code: 'c',
|
||||
content: 'StDuBDS'
|
||||
},
|
||||
{
|
||||
code: 'e',
|
||||
content: 'erda'
|
||||
},
|
||||
{
|
||||
code: 'e',
|
||||
content: 'epn'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "050",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'QL700'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "082",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: '599.05'
|
||||
},
|
||||
{
|
||||
code: '2',
|
||||
content: '23'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "245",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'Journal of mammology.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "264",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'Oxford :'
|
||||
},
|
||||
{
|
||||
code: 'b',
|
||||
content: 'Oxford University Press,'
|
||||
},
|
||||
{
|
||||
code: 'c',
|
||||
content: '1919 -'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "300",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: '1 online resource'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "310",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'Six times a year'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "336",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'text'
|
||||
},
|
||||
{
|
||||
code: '2',
|
||||
content: 'rdacontent'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "337",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'computer'
|
||||
},
|
||||
{
|
||||
code: '2',
|
||||
content: 'rdamedia'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "338",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'online resource'
|
||||
},
|
||||
{
|
||||
code: '2',
|
||||
content: 'rdacarrier'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "362",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: '1919-'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "500",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: '"Published on behalf of American Society of Mammalogists"--Home page.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "520",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'The Journal of Mammalogy has been the flagship publication of the American Society of Mammalogists since 1919 and was voted one of the top 100 most influential serials in biology and medicine of the 20th century. This highly respected international scientific journal is produced 6 times per year and promotes interest in mammals throughout the world by the publication of original and timely research on all aspects of the biology of mammals.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "588",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'Description based on online resource; title from home page (viewed on October 3, 2016).'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "650",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'Mammals'
|
||||
},
|
||||
{
|
||||
code: 'v',
|
||||
content: 'Periodicals'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "710",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'American Society of Mammalogists,'
|
||||
},
|
||||
{
|
||||
code: 'e',
|
||||
content: 'issuing body.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "776",
|
||||
subfields: [
|
||||
{
|
||||
code: 'i',
|
||||
content: 'Print version :'
|
||||
},
|
||||
{
|
||||
code: 'x',
|
||||
content: '1545-1542'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "856",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'Oxford journals'
|
||||
},
|
||||
{
|
||||
code: 'u',
|
||||
content: 'https://academic.oup.com/jmammal'
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
});
|
||||
records.push(
|
||||
{
|
||||
leader: "xxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
directory: "directory",
|
||||
fields: [
|
||||
{
|
||||
tag: "123",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'some content'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "999",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'some content'
|
||||
},
|
||||
{
|
||||
code: 'b',
|
||||
content: 'some content'
|
||||
},
|
||||
{
|
||||
code: 'c',
|
||||
content: 'some content more content'
|
||||
},
|
||||
{
|
||||
code: 'd',
|
||||
content: 'some content content content content content'
|
||||
},
|
||||
{
|
||||
code: 'e',
|
||||
content: 'some content content content content content content content content content content content content content'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "321",
|
||||
subfields: [
|
||||
{
|
||||
code: 'a',
|
||||
content: 'some content'
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="components" :class="{ active: marcFileLoaded }">
|
||||
<MarcFileUploader :class="{ mini: marcFileLoaded }" @marc-file-loaded="onMarcFileLoaded"/>
|
||||
<MarcRecords v-model="records" v-if="marcFileLoaded"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
font-size: 62.5%;
|
||||
}
|
||||
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #2c3e50;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1.3em;
|
||||
letter-spacing: .01em;
|
||||
line-height: 1.6;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
*, *:after, *:before {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
#components {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#components.active {
|
||||
align-items: normal;
|
||||
justify-content: normal;
|
||||
}
|
||||
</style>
|
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,35 @@
|
|||
<script setup>
|
||||
import { defineProps, defineEmits, computed, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
directory: String
|
||||
});
|
||||
|
||||
const isFull = ref(false);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="directory" :class="{full: isFull}" @click.prevent="isFull = !isFull">
|
||||
<span> {{ props.directory }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.directory {
|
||||
flex: 1;
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size: 1.3em;
|
||||
padding: 0 .5rem 0 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.directory.full {
|
||||
cursor: zoom-out;
|
||||
flex: auto;
|
||||
word-break: break-word;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,59 @@
|
|||
<script setup>
|
||||
import { ref, toRef, computed } from 'vue'
|
||||
|
||||
import Subfields from './Subfields.vue'
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Array,
|
||||
})
|
||||
|
||||
const isControlField = computed(() => {
|
||||
return true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="fields">
|
||||
<ul>
|
||||
<li v-for="field in modelValue">
|
||||
<div class="field">
|
||||
<div class="tag">
|
||||
{{ field.tag }}
|
||||
</div>
|
||||
<Subfields v-model="field.subfields"/>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.fields {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.field:last {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: stretch;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
|
||||
.field .tag {
|
||||
padding: .25rem .5rem;
|
||||
background-color: #4c3973;
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.field .subfields {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,110 @@
|
|||
<script setup>
|
||||
import { defineProps, computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
leader: String
|
||||
})
|
||||
const parsedLeader = computed(() => {
|
||||
return [
|
||||
{
|
||||
description: 'Record length',
|
||||
value: props.leader.slice(0, 4)
|
||||
},
|
||||
{
|
||||
description: 'Record status',
|
||||
value: props.leader.slice(4, 5)
|
||||
},
|
||||
{
|
||||
description: 'Type of record',
|
||||
value: props.leader.slice(5, 6)
|
||||
},
|
||||
{
|
||||
description: 'Bibliographic level',
|
||||
value: props.leader.slice(6, 7)
|
||||
},
|
||||
{
|
||||
description: 'Type of control',
|
||||
value: props.leader.slice(7, 8)
|
||||
},
|
||||
{
|
||||
description: 'Character coding scheme',
|
||||
value: props.leader.slice(8, 9)
|
||||
},
|
||||
{
|
||||
description: 'Indicator count',
|
||||
value: props.leader.slice(9, 10)
|
||||
},
|
||||
{
|
||||
description: 'Subfield code count',
|
||||
value: props.leader.slice(10, 11)
|
||||
},
|
||||
{
|
||||
description: 'Base address of data',
|
||||
value: props.leader.slice(11, 16)
|
||||
},
|
||||
{
|
||||
description: 'Encoding Level',
|
||||
value: props.leader.slice(16, 17)
|
||||
},
|
||||
{
|
||||
description: 'Descriptive cataloging form',
|
||||
value: props.leader.slice(17, 18)
|
||||
},
|
||||
{
|
||||
description: 'Multipart resource record level',
|
||||
value: props.leader.slice(18, 19)
|
||||
},
|
||||
{
|
||||
description: 'Length of the length-of-field portion',
|
||||
value: props.leader.slice(19, 20)
|
||||
},
|
||||
{
|
||||
description: 'Length of the starting-cahracter-position portion',
|
||||
value: props.leader.slice(20, 21)
|
||||
},
|
||||
{
|
||||
description: 'Length of the implementation-defined portion',
|
||||
value: props.leader.slice(21, 22)
|
||||
},
|
||||
{
|
||||
description: 'undefined',
|
||||
value: props.leader.slice(22, 23)
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="leader">
|
||||
<ul>
|
||||
<li v-for="section in parsedLeader">
|
||||
<span>{{ section.value }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.leader {
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size: 1.3em;
|
||||
padding: 0 .5rem 0 0;
|
||||
}
|
||||
|
||||
.leader ul li {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
background-color: rgba(217, 107, 11, .25);
|
||||
}
|
||||
|
||||
.leader ul li:after {
|
||||
content: '\22c5';
|
||||
display: inline-block;
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
.leader ul li:last-child:after {
|
||||
content: none;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,118 @@
|
|||
<script setup>
|
||||
import { defineEmits } from 'vue'
|
||||
|
||||
const emit = defineEmits(['marc-file-loaded']);
|
||||
|
||||
function onDrop(event) {
|
||||
console.log("dropped");
|
||||
}
|
||||
|
||||
function onProcessClicked(event) {
|
||||
emit('marc-file-loaded');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section id="marc-file-uploader" class="">
|
||||
<div id="drop-zone" @drop.prevent="onDrop">
|
||||
<label for="marc-file-input">
|
||||
<p>Drop a MARC file here</p>
|
||||
<p><strong>or</strong></p>
|
||||
<p>click to select file</p>
|
||||
<input type="file" id="marc-file-input" />
|
||||
</label>
|
||||
</div>
|
||||
<button id="marc-process-button" @click.prevent="onProcessClicked">Upload</button>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
#marc-file-uploader {
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
font-size: 1.6rem;
|
||||
width: 50vh;
|
||||
height: 50vh;
|
||||
background-color: #473367;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#marc-file-uploader #marc-process-button {
|
||||
width: 25%;
|
||||
margin: 0 2rem 2rem 2rem;
|
||||
background-color: #d96b0b;
|
||||
border: none;
|
||||
height: 2.6rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#marc-file-uploader #drop-zone {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 6rem;
|
||||
}
|
||||
|
||||
|
||||
#marc-file-uploader #drop-zone label {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #8162b2;
|
||||
background-color: rgba(129, 94, 178, .25);
|
||||
}
|
||||
|
||||
#marc-file-uploader input[type=file]:not(:focus-visible) {
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(0, 0, 0, 0) !important;
|
||||
white-space: nowrap !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
#marc-file-uploader.mini {
|
||||
flex: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: auto;
|
||||
flex-direction: row;
|
||||
margin: 0;
|
||||
padding: .8rem 1rem;
|
||||
align-items: normal;
|
||||
}
|
||||
|
||||
#marc-file-uploader.mini #marc-process-button {
|
||||
padding: 0;
|
||||
margin: 0 0 0 .8rem;
|
||||
}
|
||||
|
||||
#marc-file-uploader.mini #drop-zone {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#marc-file-uploader.mini #drop-zone label {
|
||||
cusor: default;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#marc-file-uploader.mini #drop-zone label p {
|
||||
display: inline-block;
|
||||
margin: 0 .8rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,58 @@
|
|||
<script setup>
|
||||
import { defineProps, defineEmits, computed } from 'vue'
|
||||
|
||||
import Fields from './Fields.vue'
|
||||
import Leader from './Leader.vue'
|
||||
import Directory from './Directory.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Array
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section id="marc-records">
|
||||
<ul>
|
||||
<li v-for="record in modelValue" class="marc-record-group">
|
||||
<div class="marc-record">
|
||||
<div class="record-metadata">
|
||||
<Leader :leader="record.leader"/>
|
||||
<Directory :directory="record.directory"/>
|
||||
</div>
|
||||
<Fields v-model="record.fields"/>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#marc-records {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
#marc-records .marc-record-group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#marc-records .marc-record-group .marc-record-controls {
|
||||
}
|
||||
|
||||
#marc-records .marc-record {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#marc-records .marc-record .record-metadata {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background-color: #d96B0b;
|
||||
padding: 0 .5rem;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,66 @@
|
|||
<script setup>
|
||||
import { defineProps, defineEmits, computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Array,
|
||||
})
|
||||
|
||||
function onContentEdit(event, index) {
|
||||
props.modelValue[index].content = event.target.innerText;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="subfields">
|
||||
<ul>
|
||||
<li v-for="(subfield, index) in modelValue" :key="index">
|
||||
<div class="subfield">
|
||||
<div class="code">
|
||||
<span
|
||||
contenteditable
|
||||
v-html="subfield.code"
|
||||
@blur="onCodeEdit($event, index)"
|
||||
@keydown.enter.prevent
|
||||
@keyup.enter="$event.target.blur()" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<span contenteditable
|
||||
v-html="subfield.content"
|
||||
@blur="onContentEdit($event, index)"
|
||||
@keydown.enter.prevent
|
||||
@keyup.enter="$event.target.blur()"></span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.subfield {
|
||||
display: flex;
|
||||
wdith: 100%;
|
||||
}
|
||||
|
||||
.subfield .code {
|
||||
padding: .25rem .5rem;
|
||||
background-color: #037f8c;
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.subfield .content {
|
||||
padding: .25rem .25rem;
|
||||
background-color: #fafafa;
|
||||
width: 100%;
|
||||
font-family: monospace;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.subfields ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()]
|
||||
})
|
Loading…
Reference in New Issue