157 lines
4.8 KiB
Vue
157 lines
4.8 KiB
Vue
<template>
|
|
<div class="form-row" v-if="state !== MetadataLoadState.Inactive">
|
|
<div class="form-group col-sm-12">
|
|
<div class="card link-card-mini mb-2 px-0">
|
|
<div v-if="state === MetadataLoadState.Loading" class="row no-gutters">
|
|
<div class="col-12">
|
|
<div class="card-body">
|
|
<h6 class="card-title text-center font-weight-bold text-info" style="font-size: small;">
|
|
<span class="oi oi-loop-circular"></span> オカズの情報を読み込んでいます…
|
|
</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="state === MetadataLoadState.Success" class="row no-gutters">
|
|
<div v-if="hasImage" class="col-4 justify-content-center align-items-center">
|
|
<img :src="metadata.image" alt="Thumbnail" class="w-100 bg-secondary" />
|
|
</div>
|
|
<div :class="descClasses">
|
|
<div class="card-body">
|
|
<h6 class="card-title font-weight-bold" style="font-size: small;">{{ metadata.title }}</h6>
|
|
<template v-if="suggestions.length > 0">
|
|
<p class="card-text mb-2" style="font-size: small;">
|
|
タグ候補<br /><span class="text-secondary"
|
|
>(クリックするとタグ入力欄にコピーできます)</span
|
|
>
|
|
</p>
|
|
<ul class="list-inline d-inline">
|
|
<li
|
|
v-for="tag in suggestions"
|
|
:class="tagClasses(tag)"
|
|
@click="addTag(tag.name)"
|
|
:key="tag.name"
|
|
>
|
|
<span class="oi oi-tag"></span> {{ tag.name }}
|
|
</li>
|
|
</ul>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="row no-gutters">
|
|
<div class="col-12">
|
|
<div class="card-body">
|
|
<h6 class="card-title text-center font-weight-bold text-danger" style="font-size: small;">
|
|
<span class="oi oi-circle-x"></span> オカズの情報を読み込めませんでした
|
|
</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Vue, Component, Prop } from 'vue-property-decorator';
|
|
import { bus, MetadataLoadState } from '../checkin';
|
|
|
|
type Metadata = {
|
|
url: string;
|
|
title: string;
|
|
description: string;
|
|
image: string;
|
|
expires_at: string | null;
|
|
tags: {
|
|
name: string;
|
|
}[];
|
|
};
|
|
|
|
type Suggestion = {
|
|
name: string;
|
|
used: boolean;
|
|
};
|
|
|
|
@Component
|
|
export default class MetadataPreview extends Vue {
|
|
@Prop() readonly state!: MetadataLoadState;
|
|
@Prop() readonly metadata!: Metadata | null;
|
|
|
|
// for use in v-if
|
|
private readonly MetadataLoadState = MetadataLoadState;
|
|
|
|
tags: string[] = [];
|
|
|
|
created() {
|
|
bus.$on('change-tag', (tags: string[]) => (this.tags = tags));
|
|
bus.$emit('resend-tag');
|
|
}
|
|
|
|
addTag(tag: string) {
|
|
bus.$emit('add-tag', tag);
|
|
}
|
|
|
|
tagClasses(s: Suggestion) {
|
|
return {
|
|
'list-inline-item': true,
|
|
badge: true,
|
|
'badge-primary': !s.used,
|
|
'badge-secondary': s.used,
|
|
'metadata-tag-item': true,
|
|
};
|
|
}
|
|
|
|
get suggestions(): Suggestion[] {
|
|
if (this.metadata === null) {
|
|
return [];
|
|
}
|
|
|
|
return this.metadata.tags.map((t) => {
|
|
return {
|
|
name: t.name,
|
|
used: this.tags.indexOf(t.name) !== -1,
|
|
};
|
|
});
|
|
}
|
|
|
|
get hasImage() {
|
|
return this.metadata !== null && this.metadata.image !== '';
|
|
}
|
|
|
|
get descClasses() {
|
|
return {
|
|
'col-8': this.hasImage,
|
|
'col-12': !this.hasImage,
|
|
};
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.link-card-mini {
|
|
$height: 150px;
|
|
overflow: hidden;
|
|
|
|
.row > div:first-child {
|
|
display: flex;
|
|
|
|
&:not([display='none']) {
|
|
min-height: $height;
|
|
|
|
img {
|
|
position: absolute;
|
|
}
|
|
}
|
|
}
|
|
|
|
.card-text {
|
|
white-space: pre-line;
|
|
}
|
|
}
|
|
|
|
.metadata-tag-item {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
</style>
|