とりあえず一旦これで自動修正

This commit is contained in:
hina 2020-06-06 18:01:56 +09:00
parent 334c810b8d
commit edd7a6f4c8
No known key found for this signature in database
GPG Key ID: B666B2A137443F76
12 changed files with 295 additions and 268 deletions

View File

@ -1,4 +1,4 @@
// @types/bootstrap に足りないもの // @types/bootstrap に足りないもの
interface JQuery<TElement = HTMLElement> { interface JQuery<TElement = HTMLElement> {
modal(action: "toggle" | "show" | "hide" | "handleUpdate" | "dispose", relatedTarget?: TElement): this; modal(action: 'toggle' | 'show' | 'hide' | 'handleUpdate' | 'dispose', relatedTarget?: TElement): this;
} }

View File

@ -1,4 +1,4 @@
declare module "*.vue" { declare module '*.vue' {
import Vue from "vue"; import Vue from 'vue';
export default Vue; export default Vue;
} }

View File

@ -52,7 +52,7 @@ $(() => {
$.ajax({ $.ajax({
url: '/api/likes/' + encodeURIComponent(targetId), url: '/api/likes/' + encodeURIComponent(targetId),
method: 'delete', method: 'delete',
type: 'json' type: 'json',
}) })
.then(callback) .then(callback)
.catch(function (xhr: jqXHR) { .catch(function (xhr: jqXHR) {
@ -78,8 +78,8 @@ $(() => {
method: 'post', method: 'post',
type: 'json', type: 'json',
data: { data: {
id: targetId id: targetId,
} },
}) })
.then(callback) .then(callback)
.catch(function (xhr: jqXHR) { .catch(function (xhr: jqXHR) {
@ -99,7 +99,7 @@ $(() => {
$(document).on('click', '.card-spoiler-overlay', function (event) { $(document).on('click', '.card-spoiler-overlay', function (event) {
const $this = $(this); const $this = $(this);
$this.siblings(".card-link").removeClass("card-spoiler"); $this.siblings('.card-link').removeClass('card-spoiler');
$this.remove(); $this.remove();
}); });
}); });

View File

@ -8,8 +8,8 @@ if (!token) {
} else { } else {
$.ajaxSetup({ $.ajaxSetup({
headers: { headers: {
'X-CSRF-TOKEN': token.content 'X-CSRF-TOKEN': token.content,
} },
}); });
} }

View File

@ -1,8 +1,8 @@
import Vue from 'vue'; import Vue from 'vue';
import TagInput from "./components/TagInput.vue"; import TagInput from './components/TagInput.vue';
import MetadataPreview from './components/MetadataPreview.vue'; import MetadataPreview from './components/MetadataPreview.vue';
export const bus = new Vue({name: "EventBus"}); export const bus = new Vue({ name: 'EventBus' });
export enum MetadataLoadState { export enum MetadataLoadState {
Inactive, Inactive,
@ -19,11 +19,11 @@ new Vue({
}, },
components: { components: {
TagInput, TagInput,
MetadataPreview MetadataPreview,
}, },
mounted() { mounted() {
// オカズリンクにURLがセットされている場合は、すぐにメタデータを取得する // オカズリンクにURLがセットされている場合は、すぐにメタデータを取得する
const linkInput = this.$el.querySelector<HTMLInputElement>("#link"); const linkInput = this.$el.querySelector<HTMLInputElement>('#link');
if (linkInput && /^https?:\/\//.test(linkInput.value)) { if (linkInput && /^https?:\/\//.test(linkInput.value)) {
this.fetchMetadata(linkInput.value); this.fetchMetadata(linkInput.value);
} }
@ -52,15 +52,17 @@ new Vue({
method: 'get', method: 'get',
type: 'json', type: 'json',
data: { data: {
url url,
} },
}).then(data => { })
.then((data) => {
this.metadata = data; this.metadata = data;
this.metadataLoadState = MetadataLoadState.Success; this.metadataLoadState = MetadataLoadState.Success;
}).catch(e => { })
.catch((e) => {
this.metadata = null; this.metadata = null;
this.metadataLoadState = MetadataLoadState.Failed; this.metadataLoadState = MetadataLoadState.Failed;
}); });
} },
} },
}); });

View File

@ -5,23 +5,29 @@
<div v-if="state === MetadataLoadState.Loading" class="row no-gutters"> <div v-if="state === MetadataLoadState.Loading" class="row no-gutters">
<div class="col-12"> <div class="col-12">
<div class="card-body"> <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> <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>
</div> </div>
<div v-else-if="state === MetadataLoadState.Success" class="row no-gutters"> <div v-else-if="state === MetadataLoadState.Success" class="row no-gutters">
<div v-if="hasImage" class="col-4 justify-content-center align-items-center"> <div v-if="hasImage" class="col-4 justify-content-center align-items-center">
<img :src="metadata.image" alt="Thumbnail" class="w-100 bg-secondary"> <img :src="metadata.image" alt="Thumbnail" class="w-100 bg-secondary" />
</div> </div>
<div :class="descClasses"> <div :class="descClasses">
<div class="card-body"> <div class="card-body">
<h6 class="card-title font-weight-bold" style="font-size: small;">{{ metadata.title }}</h6> <h6 class="card-title font-weight-bold" style="font-size: small;">{{ metadata.title }}</h6>
<template v-if="suggestions.length > 0"> <template v-if="suggestions.length > 0">
<p class="card-text mb-2" style="font-size: small;">タグ候補<br><span class="text-secondary">(クリックするとタグ入力欄にコピーできます)</span></p> <p class="card-text mb-2" style="font-size: small;">
タグ候補<br /><span class="text-secondary"
>(クリックするとタグ入力欄にコピーできます)</span
>
</p>
<ul class="list-inline d-inline"> <ul class="list-inline d-inline">
<li v-for="tag in suggestions" <li v-for="tag in suggestions" :class="tagClasses(tag)" @click="addTag(tag.name)">
:class="tagClasses(tag)" <span class="oi oi-tag"></span> {{ tag.name }}
@click="addTag(tag.name)"><span class="oi oi-tag"></span> {{ tag.name }}</li> </li>
</ul> </ul>
</template> </template>
</div> </div>
@ -30,7 +36,9 @@
<div v-else class="row no-gutters"> <div v-else class="row no-gutters">
<div class="col-12"> <div class="col-12">
<div class="card-body"> <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> <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>
@ -40,24 +48,24 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import {Vue, Component, Prop} from "vue-property-decorator"; import { Vue, Component, Prop } from 'vue-property-decorator';
import {bus, MetadataLoadState} from "../checkin"; import { bus, MetadataLoadState } from '../checkin';
type Metadata = { type Metadata = {
url: string, url: string;
title: string, title: string;
description: string, description: string;
image: string, image: string;
expires_at: string | null, expires_at: string | null;
tags: { tags: {
name: string name: string;
}[], }[];
}; };
type Suggestion = { type Suggestion = {
name: string, name: string;
used: boolean, used: boolean;
} };
@Component @Component
export default class MetadataPreview extends Vue { export default class MetadataPreview extends Vue {
@ -70,21 +78,21 @@
tags: string[] = []; tags: string[] = [];
created() { created() {
bus.$on("change-tag", (tags: string[]) => this.tags = tags); bus.$on('change-tag', (tags: string[]) => (this.tags = tags));
bus.$emit("resend-tag"); bus.$emit('resend-tag');
} }
addTag(tag: string) { addTag(tag: string) {
bus.$emit("add-tag", tag); bus.$emit('add-tag', tag);
} }
tagClasses(s: Suggestion) { tagClasses(s: Suggestion) {
return { return {
"list-inline-item": true, 'list-inline-item': true,
"badge": true, badge: true,
"badge-primary": !s.used, 'badge-primary': !s.used,
"badge-secondary": s.used, 'badge-secondary': s.used,
"metadata-tag-item": true, 'metadata-tag-item': true,
}; };
} }
@ -93,22 +101,22 @@
return []; return [];
} }
return this.metadata.tags.map(t => { return this.metadata.tags.map((t) => {
return { return {
name: t.name, name: t.name,
used: this.tags.indexOf(t.name) !== -1 used: this.tags.indexOf(t.name) !== -1,
}; };
}); });
} }
get hasImage() { get hasImage() {
return this.metadata !== null && this.metadata.image !== '' return this.metadata !== null && this.metadata.image !== '';
} }
get descClasses() { get descClasses() {
return { return {
"col-8": this.hasImage, 'col-8': this.hasImage,
"col-12": !this.hasImage, 'col-12': !this.hasImage,
}; };
} }
} }
@ -122,7 +130,7 @@
.row > div:first-child { .row > div:first-child {
display: flex; display: flex;
&:not([display=none]) { &:not([display='none']) {
min-height: $height; min-height: $height;
img { img {

View File

@ -1,23 +1,18 @@
<template> <template>
<div :class="containerClass" @click="$refs.input.focus()"> <div :class="containerClass" @click="$refs.input.focus()">
<input :name="name" type="hidden" :value="tagValue"> <input :name="name" type="hidden" :value="tagValue" />
<ul class="list-inline d-inline"> <ul class="list-inline d-inline">
<li v-for="(tag, i) in tags" <li v-for="(tag, i) in tags" class="list-inline-item badge badge-primary tag-item" @click="removeTag(i)">
class="list-inline-item badge badge-primary tag-item" <span class="oi oi-tag"></span> {{ tag }} | x
@click="removeTag(i)"><span class="oi oi-tag"></span> {{ tag }} | x</li> </li>
</ul> </ul>
<input :id="id" <input :id="id" ref="input" type="text" class="tag-input" v-model="buffer" @keydown="onKeyDown" />
ref="input"
type="text"
class="tag-input"
v-model="buffer"
@keydown="onKeyDown">
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import {Vue, Component, Prop, Watch} from "vue-property-decorator"; import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import {bus} from "../checkin"; import { bus } from '../checkin';
@Component @Component
export default class TagInput extends Vue { export default class TagInput extends Vue {
@ -26,23 +21,23 @@
@Prop(String) readonly value!: string; @Prop(String) readonly value!: string;
@Prop(Boolean) readonly isInvalid!: boolean; @Prop(Boolean) readonly isInvalid!: boolean;
tags: string[] = this.value.trim() !== "" ? this.value.trim().split(" ") : []; tags: string[] = this.value.trim() !== '' ? this.value.trim().split(' ') : [];
buffer: string = ""; buffer = '';
created() { created() {
bus.$on("add-tag", (tag: string) => this.tags.indexOf(tag) === -1 && this.tags.push(tag)); bus.$on('add-tag', (tag: string) => this.tags.indexOf(tag) === -1 && this.tags.push(tag));
bus.$on("resend-tag", () => bus.$emit("change-tag", this.tags)); bus.$on('resend-tag', () => bus.$emit('change-tag', this.tags));
} }
onKeyDown(event: KeyboardEvent) { onKeyDown(event: KeyboardEvent) {
if (this.buffer.trim() !== "") { if (this.buffer.trim() !== '') {
switch (event.key) { switch (event.key) {
case 'Tab': case 'Tab':
case 'Enter': case 'Enter':
case ' ': case ' ':
if ((event as any).isComposing !== true) { if ((event as any).isComposing !== true) {
this.tags.push(this.buffer.trim()); this.tags.push(this.buffer.trim());
this.buffer = ""; this.buffer = '';
} }
event.preventDefault(); event.preventDefault();
break; break;
@ -50,12 +45,12 @@
// () // ()
if (event.srcElement && (event.srcElement as HTMLInputElement).value.slice(-1) == ' ') { if (event.srcElement && (event.srcElement as HTMLInputElement).value.slice(-1) == ' ') {
this.tags.push(this.buffer.trim()); this.tags.push(this.buffer.trim());
this.buffer = ""; this.buffer = '';
event.preventDefault(); event.preventDefault();
} }
break; break;
} }
} else if (event.key === "Enter") { } else if (event.key === 'Enter') {
// //
event.preventDefault(); event.preventDefault();
} }
@ -65,21 +60,21 @@
this.tags.splice(index, 1); this.tags.splice(index, 1);
} }
@Watch("tags") @Watch('tags')
onTagsChanged() { onTagsChanged() {
bus.$emit("change-tag", this.tags); bus.$emit('change-tag', this.tags);
} }
get containerClass(): object { get containerClass(): object {
return { return {
"form-control": true, 'form-control': true,
"h-auto": true, 'h-auto': true,
"is-invalid": this.isInvalid 'is-invalid': this.isInvalid,
}; };
} }
get tagValue(): string { get tagValue(): string {
return this.tags.join(" "); return this.tags.join(' ');
} }
} }
</script> </script>

View File

@ -8,31 +8,37 @@ new Chart(graph.getContext('2d')!, {
type: 'bar', type: 'bar',
data: { data: {
labels, labels,
datasets: [{ datasets: [
{
data, data,
backgroundColor: 'rgba(0, 0, 0, .1)', backgroundColor: 'rgba(0, 0, 0, .1)',
borderColor: 'rgba(0, 0, 0, .25)', borderColor: 'rgba(0, 0, 0, .25)',
borderWidth: 1 borderWidth: 1,
}] },
],
}, },
options: { options: {
maintainAspectRatio: false, maintainAspectRatio: false,
legend: { legend: {
display: false display: false,
}, },
elements: { elements: {
line: {} line: {},
}, },
scales: { scales: {
xAxes: [{ xAxes: [
display: false {
}], display: false,
yAxes: [{ },
],
yAxes: [
{
display: false, display: false,
ticks: { ticks: {
beginAtZero: true beginAtZero: true,
} },
}] },
} ],
} },
},
}); });

View File

@ -1,5 +1,7 @@
$('#protected').on('change', function () { $('#protected').on('change', function () {
if (!$(this).prop('checked')) { if (!$(this).prop('checked')) {
alert('チェックイン履歴を公開に切り替えると、個別に非公開設定されているものを除いた全てのチェックインが誰でも閲覧できるようになります。\nご注意ください。'); alert(
'チェックイン履歴を公開に切り替えると、個別に非公開設定されているものを除いた全てのチェックインが誰でも閲覧できるようになります。\nご注意ください。'
);
} }
}); });

View File

@ -1,9 +1,11 @@
(function ($) { (function ($) {
$.fn.linkCard = function (options) { $.fn.linkCard = function (options) {
const settings = $.extend({ const settings = $.extend(
endpoint: '/api/checkin/card' {
}, options); endpoint: '/api/checkin/card',
},
options
);
return this.each(function () { return this.each(function () {
const $this = $(this); const $this = $(this);
@ -12,8 +14,8 @@
method: 'get', method: 'get',
type: 'json', type: 'json',
data: { data: {
url: $this.find('a').attr('href') url: $this.find('a').attr('href'),
} },
}).then(function (data) { }).then(function (data) {
const $metaColumn = $this.find('.col-12:last-of-type'); const $metaColumn = $this.find('.col-12:last-of-type');
const $imageColumn = $this.find('.col-12:first-of-type'); const $imageColumn = $this.find('.col-12:first-of-type');
@ -55,18 +57,20 @@
$.fn.deleteCheckinModal = function () { $.fn.deleteCheckinModal = function () {
return this.each(function () { return this.each(function () {
$(this).on('show.bs.modal', function (event) { $(this)
.on('show.bs.modal', function (event) {
const target = $(event.relatedTarget!); const target = $(event.relatedTarget!);
const modal = $(this); const modal = $(this);
modal.find('.modal-body .date-label').text(target.data('date')); modal.find('.modal-body .date-label').text(target.data('date'));
modal.data('id', target.data('id')); modal.data('id', target.data('id'));
}).find('.btn-danger').on('click', function (event) { })
.find('.btn-danger')
.on('click', function (event) {
const modal = $('#deleteCheckinModal'); const modal = $('#deleteCheckinModal');
const form = modal.find('form'); const form = modal.find('form');
form.attr('action', form.attr('action')?.replace('@', modal.data('id')) || null); form.attr('action', form.attr('action')?.replace('@', modal.data('id')) || null);
form.submit(); form.submit();
}) });
}); });
}; };
})(jQuery); })(jQuery);

View File

@ -11,6 +11,6 @@ if (document.getElementById('cal-heatmap')) {
start: subMonths(new Date(), 9), start: subMonths(new Date(), 9),
range: 10, range: 10,
data: JSON.parse(document.getElementById('count-by-day')!.textContent as string), data: JSON.parse(document.getElementById('count-by-day')!.textContent as string),
legend: [1, 2, 3, 4] legend: [1, 2, 3, 4],
}); });
} }

View File

@ -10,34 +10,38 @@ function createLineGraph(id: string, labels: string[], data: any) {
type: 'line', type: 'line',
data: { data: {
labels: labels, labels: labels,
datasets: [{ datasets: [
{
data: data, data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)', backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)', borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1 borderWidth: 1,
}] },
],
}, },
options: { options: {
legend: { legend: {
display: false display: false,
}, },
elements: { elements: {
line: { line: {
tension: 0 tension: 0,
} },
}, },
scales: { scales: {
yAxes: [{ yAxes: [
{
ticks: { ticks: {
beginAtZero: true beginAtZero: true,
} },
}] },
],
}, },
tooltips: { tooltips: {
mode: 'index', mode: 'index',
intersect: false, intersect: false,
} },
} },
}); });
} }
@ -47,29 +51,33 @@ function createBarGraph(id: string, labels: string[], data: any) {
type: 'bar', type: 'bar',
data: { data: {
labels: labels, labels: labels,
datasets: [{ datasets: [
{
data: data, data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)', backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)', borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1 borderWidth: 1,
}] },
],
}, },
options: { options: {
legend: { legend: {
display: false display: false,
}, },
scales: { scales: {
yAxes: [{ yAxes: [
{
ticks: { ticks: {
beginAtZero: true beginAtZero: true,
} },
}] },
],
}, },
tooltips: { tooltips: {
mode: 'index', mode: 'index',
intersect: false, intersect: false,
} },
} },
}); });
} }
@ -106,12 +114,14 @@ if (document.getElementById('cal-heatmap')) {
start: new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0), start: new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0),
range: 12, range: 12,
data: graphData.dailySum, data: graphData.dailySum,
legend: [1, 2, 3, 4] legend: [1, 2, 3, 4],
}); });
} }
if (document.getElementById('monthly-graph')) { if (document.getElementById('monthly-graph')) {
const {keys: monthlyKey, values: monthlySum} = createMonthlyGraphData(new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0)); const { keys: monthlyKey, values: monthlySum } = createMonthlyGraphData(
new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0)
);
createLineGraph('monthly-graph', monthlyKey, monthlySum); createLineGraph('monthly-graph', monthlyKey, monthlySum);
} }
if (document.getElementById('yearly-graph')) { if (document.getElementById('yearly-graph')) {