Compare commits
6 Commits
e79b033c59
...
2cc9705845
Author | SHA1 | Date |
---|---|---|
Damillora | 2cc9705845 | |
Damillora | 16c9f998d5 | |
Damillora | 63b19dcf0f | |
Damillora | 1a0a0a7c83 | |
Damillora | 45d4278a52 | |
Damillora | a420b50877 |
|
@ -1 +1,2 @@
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
web/app/node_modules
|
||||||
|
|
|
@ -3,7 +3,6 @@ package app
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Damillora/Shioriko/pkg/models"
|
|
||||||
"github.com/Damillora/Shioriko/pkg/services"
|
"github.com/Damillora/Shioriko/pkg/services"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@ -12,18 +11,16 @@ func InitializeTagRoutes(g *gin.Engine) {
|
||||||
unprotected := g.Group("/api/tag")
|
unprotected := g.Group("/api/tag")
|
||||||
{
|
{
|
||||||
unprotected.GET("/", tagGet)
|
unprotected.GET("/", tagGet)
|
||||||
|
unprotected.GET("/autocomplete", tagAutocomplete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagGet(c *gin.Context) {
|
func tagGet(c *gin.Context) {
|
||||||
tags := services.GetTagAll()
|
tags := services.GetTagAll()
|
||||||
var tagResult []models.TagListItem
|
c.JSON(http.StatusOK, tags)
|
||||||
for _, tag := range tags {
|
}
|
||||||
tagResult = append(tagResult, models.TagListItem{
|
|
||||||
ID: tag.ID,
|
func tagAutocomplete(c *gin.Context) {
|
||||||
Name: tag.Name,
|
tags := services.GetTagAutocomplete()
|
||||||
TagType: tag.TagType.Name,
|
c.JSON(http.StatusOK, tags)
|
||||||
})
|
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, tagResult)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,14 @@ type TagTypeListItem struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagListItem struct {
|
type TagListItem struct {
|
||||||
ID string `json:"id"`
|
TagID string `json:"tagId"`
|
||||||
Name string `json:"name"`
|
TagName string `json:"tagName"`
|
||||||
TagType string `json:"tagType"`
|
TagType string `json:"tagType"`
|
||||||
|
PostCount int `json:"postCount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagAutocompleteListItem struct {
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostListItem struct {
|
type PostListItem struct {
|
||||||
|
|
|
@ -5,12 +5,31 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Damillora/Shioriko/pkg/database"
|
"github.com/Damillora/Shioriko/pkg/database"
|
||||||
|
"github.com/Damillora/Shioriko/pkg/models"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetTagAll() []database.Tag {
|
func GetTagAll() []models.TagListItem {
|
||||||
var tags []database.Tag
|
var tags []models.TagListItem
|
||||||
database.DB.Joins("TagType").Find(&tags)
|
database.DB.Model(&database.Tag{}).
|
||||||
|
Joins("join tag_types on tag_types.id = tags.tag_type_id").
|
||||||
|
Joins("left join post_tags on post_tags.tag_id = tags.id").
|
||||||
|
Select("tags.id as tag_id, tags.name as tag_name, tag_types.name as tag_type, count(post_tags.post_id) as post_count").
|
||||||
|
Group("tags.id, tags.name, tag_types.name").
|
||||||
|
Order("post_count DESC").
|
||||||
|
Find(&tags)
|
||||||
|
return tags
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTagAutocomplete() []string {
|
||||||
|
var tags []string
|
||||||
|
result := database.DB.Model(&database.Tag{}).
|
||||||
|
Joins("join tag_types on tag_types.id = tags.tag_type_id").
|
||||||
|
Select("concat(tag_types.name,':',tags.name) as name").
|
||||||
|
Find(&tags)
|
||||||
|
if result.Error != nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,4 +49,13 @@
|
||||||
font-size: 13.3333px;
|
font-size: 13.3333px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#tags .svelte-tags-input-matchs {
|
||||||
|
z-index: 200;
|
||||||
|
&-parent {
|
||||||
|
z-index: 200;
|
||||||
|
}
|
||||||
|
& li:hover {
|
||||||
|
background: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<div class="navbar-menu" class:is-active={menu_shown}>
|
<div class="navbar-menu" class:is-active={menu_shown}>
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<Link class="navbar-item" to="/posts">Posts</Link>
|
<Link class="navbar-item" to="/posts">Posts</Link>
|
||||||
|
<Link class="navbar-item" to="/tags">Tags</Link>
|
||||||
{#if loggedIn}
|
{#if loggedIn}
|
||||||
<Link class="navbar-item" to="/upload">Upload</Link>
|
<Link class="navbar-item" to="/upload">Upload</Link>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -41,6 +41,11 @@ export async function getTags() {
|
||||||
const response = await axios.get(endpoint);
|
const response = await axios.get(endpoint);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
export async function getTagAutocomplete() {
|
||||||
|
const endpoint = url + "/api/tag/autocomplete";
|
||||||
|
const response = await axios.get(endpoint);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
export async function getPosts({ page }) {
|
export async function getPosts({ page }) {
|
||||||
const endpoint = url + "/api/post?page=" + page;
|
const endpoint = url + "/api/post?page=" + page;
|
||||||
const response = await axios.get(endpoint);
|
const response = await axios.get(endpoint);
|
||||||
|
|
|
@ -10,4 +10,7 @@
|
||||||
.tile.is-multiline {
|
.tile.is-multiline {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.svelte-tags-input-matchs-parent {
|
||||||
|
z-index: 200;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { getPost, postUpdate } from "../api.js";
|
import { getPost, postUpdate, getTagAutocomplete } from "../api.js";
|
||||||
import { navigate } from "svelte-routing";
|
import { navigate } from "svelte-routing";
|
||||||
import Tags from "svelte-tags-input";
|
import Tags from "svelte-tags-input";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
@ -26,6 +26,11 @@
|
||||||
form.tags = value.detail.tags;
|
form.tags = value.detail.tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onAutocomplete = async () => {
|
||||||
|
const list = await getTagAutocomplete();
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const response = await postUpdate(id, form);
|
const response = await postUpdate(id, form);
|
||||||
navigate(`/post/${response.id}`);
|
navigate(`/post/${response.id}`);
|
||||||
|
@ -71,6 +76,7 @@
|
||||||
tags={form.tags}
|
tags={form.tags}
|
||||||
addKeys={[9, 32]}
|
addKeys={[9, 32]}
|
||||||
on:tags={onTagChange}
|
on:tags={onTagChange}
|
||||||
|
autoComplete={onAutocomplete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { getPostSearchTag } from "../api.js";
|
import { getPostSearchTag, getTagAutocomplete } from "../api.js";
|
||||||
import { Link, navigate } from "svelte-routing";
|
import { Link, navigate } from "svelte-routing";
|
||||||
import InfiniteScroll from "svelte-infinite-scroll";
|
import InfiniteScroll from "svelte-infinite-scroll";
|
||||||
import TagLink from "../TagLink.svelte";
|
import TagLink from "../TagLink.svelte";
|
||||||
|
@ -51,6 +51,11 @@
|
||||||
searchTerms = value.detail.tags;
|
searchTerms = value.detail.tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onAutocomplete = async () => {
|
||||||
|
const list = await getTagAutocomplete();
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
queryParams = queryString.parse(location.search);
|
queryParams = queryString.parse(location.search);
|
||||||
if (queryParams.tags) {
|
if (queryParams.tags) {
|
||||||
|
@ -88,6 +93,7 @@
|
||||||
tags={searchTerms}
|
tags={searchTerms}
|
||||||
addKeys={[9, 32]}
|
addKeys={[9, 32]}
|
||||||
on:tags={onTagChange}
|
on:tags={onTagChange}
|
||||||
|
autoComplete={onAutocomplete}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getTags } from "../api";
|
import { getTags } from "../api";
|
||||||
|
import { Link } from "svelte-routing";
|
||||||
|
|
||||||
let tags = [];
|
let tags = [];
|
||||||
|
|
||||||
|
@ -25,15 +25,19 @@ import { getTags } from "../api";
|
||||||
<table class="table is-fullwidth">
|
<table class="table is-fullwidth">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Tag</th>
|
<th >Tag</th>
|
||||||
<th>Tag Type</th>
|
<th style="width: 30%;">Tag Type</th>
|
||||||
|
<th style="width: 10%;">Post Count</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each tags as tag}
|
{#each tags as tag}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{tag.name}</td>
|
<td>
|
||||||
|
<Link to="/posts?tags={tag.tagType}:{tag.tagName}">{tag.tagName}</Link>
|
||||||
|
</td>
|
||||||
<td>{tag.tagType}</td>
|
<td>{tag.tagType}</td>
|
||||||
|
<td>{tag.postCount}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { uploadBlob, postCreate } from "../api.js";
|
import { uploadBlob, postCreate, getTagAutocomplete } from "../api.js";
|
||||||
import { navigate, Link } from "svelte-routing";
|
import { navigate, Link } from "svelte-routing";
|
||||||
import Tags from "svelte-tags-input";
|
import Tags from "svelte-tags-input";
|
||||||
import AuthRequired from "../AuthRequired.svelte";
|
import AuthRequired from "../AuthRequired.svelte";
|
||||||
|
@ -38,6 +38,11 @@
|
||||||
form.tags = value.detail.tags;
|
form.tags = value.detail.tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onAutocomplete = async () => {
|
||||||
|
const list = await getTagAutocomplete();
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const response = await postCreate(form);
|
const response = await postCreate(form);
|
||||||
navigate(`/post/${response.id}`);
|
navigate(`/post/${response.id}`);
|
||||||
|
@ -107,7 +112,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="tags" class="label">Tags</label>
|
<label for="tags" class="label">Tags</label>
|
||||||
<div class="control" id="tags">
|
<div class="control" id="tags">
|
||||||
<Tags addKeys={[9, 32]} on:tags={onTagChange} />
|
<Tags addKeys={[9, 32]} on:tags={onTagChange} autoComplete={onAutocomplete} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
|
Loading…
Reference in New Issue