Compare commits

...

6 Commits

12 changed files with 87 additions and 26 deletions

View File

@ -1 +1,2 @@
Dockerfile
web/app/node_modules

View File

@ -3,7 +3,6 @@ package app
import (
"net/http"
"github.com/Damillora/Shioriko/pkg/models"
"github.com/Damillora/Shioriko/pkg/services"
"github.com/gin-gonic/gin"
)
@ -12,18 +11,16 @@ func InitializeTagRoutes(g *gin.Engine) {
unprotected := g.Group("/api/tag")
{
unprotected.GET("/", tagGet)
unprotected.GET("/autocomplete", tagAutocomplete)
}
}
func tagGet(c *gin.Context) {
tags := services.GetTagAll()
var tagResult []models.TagListItem
for _, tag := range tags {
tagResult = append(tagResult, models.TagListItem{
ID: tag.ID,
Name: tag.Name,
TagType: tag.TagType.Name,
})
}
c.JSON(http.StatusOK, tagResult)
c.JSON(http.StatusOK, tags)
}
func tagAutocomplete(c *gin.Context) {
tags := services.GetTagAutocomplete()
c.JSON(http.StatusOK, tags)
}

View File

@ -6,9 +6,14 @@ type TagTypeListItem struct {
}
type TagListItem struct {
ID string `json:"id"`
Name string `json:"name"`
TagType string `json:"tagType"`
TagID string `json:"tagId"`
TagName string `json:"tagName"`
TagType string `json:"tagType"`
PostCount int `json:"postCount"`
}
type TagAutocompleteListItem struct {
Name string `json:"name"`
}
type PostListItem struct {

View File

@ -5,12 +5,31 @@ import (
"strings"
"github.com/Damillora/Shioriko/pkg/database"
"github.com/Damillora/Shioriko/pkg/models"
"github.com/google/uuid"
)
func GetTagAll() []database.Tag {
var tags []database.Tag
database.DB.Joins("TagType").Find(&tags)
func GetTagAll() []models.TagListItem {
var tags []models.TagListItem
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
}

View File

@ -49,4 +49,13 @@
font-size: 13.3333px;
}
}
#tags .svelte-tags-input-matchs {
z-index: 200;
&-parent {
z-index: 200;
}
& li:hover {
background: $primary;
}
}
</style>

View File

@ -35,6 +35,7 @@
<div class="navbar-menu" class:is-active={menu_shown}>
<div class="navbar-start">
<Link class="navbar-item" to="/posts">Posts</Link>
<Link class="navbar-item" to="/tags">Tags</Link>
{#if loggedIn}
<Link class="navbar-item" to="/upload">Upload</Link>
{/if}

View File

@ -41,6 +41,11 @@ export async function getTags() {
const response = await axios.get(endpoint);
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 }) {
const endpoint = url + "/api/post?page=" + page;
const response = await axios.get(endpoint);

View File

@ -10,4 +10,7 @@
.tile.is-multiline {
flex-wrap: wrap;
}
.svelte-tags-input-matchs-parent {
z-index: 200;
}

View File

@ -1,5 +1,5 @@
<script>
import { getPost, postUpdate } from "../api.js";
import { getPost, postUpdate, getTagAutocomplete } from "../api.js";
import { navigate } from "svelte-routing";
import Tags from "svelte-tags-input";
import { onMount } from "svelte";
@ -26,6 +26,11 @@
form.tags = value.detail.tags;
};
const onAutocomplete = async () => {
const list = await getTagAutocomplete();
return list;
};
const onSubmit = async () => {
const response = await postUpdate(id, form);
navigate(`/post/${response.id}`);
@ -71,6 +76,7 @@
tags={form.tags}
addKeys={[9, 32]}
on:tags={onTagChange}
autoComplete={onAutocomplete}
/>
</div>
</div>

View File

@ -1,6 +1,6 @@
<script>
import { onMount } from "svelte";
import { getPostSearchTag } from "../api.js";
import { getPostSearchTag, getTagAutocomplete } from "../api.js";
import { Link, navigate } from "svelte-routing";
import InfiniteScroll from "svelte-infinite-scroll";
import TagLink from "../TagLink.svelte";
@ -51,6 +51,11 @@
searchTerms = value.detail.tags;
};
const onAutocomplete = async () => {
const list = await getTagAutocomplete();
return list;
};
$: {
queryParams = queryString.parse(location.search);
if (queryParams.tags) {
@ -88,6 +93,7 @@
tags={searchTerms}
addKeys={[9, 32]}
on:tags={onTagChange}
autoComplete={onAutocomplete}
/>
</div>
</div>

View File

@ -1,6 +1,6 @@
<script>
import { getTags } from "../api";
import { getTags } from "../api";
import { Link } from "svelte-routing";
let tags = [];
@ -25,15 +25,19 @@ import { getTags } from "../api";
<table class="table is-fullwidth">
<thead>
<tr>
<th>Tag</th>
<th>Tag Type</th>
<th >Tag</th>
<th style="width: 30%;">Tag Type</th>
<th style="width: 10%;">Post Count</th>
</tr>
</thead>
<tbody>
{#each tags as tag}
<tr>
<td>{tag.name}</td>
<td>
<Link to="/posts?tags={tag.tagType}:{tag.tagName}">{tag.tagName}</Link>
</td>
<td>{tag.tagType}</td>
<td>{tag.postCount}</td>
</tr>
{/each}
</tbody>

View File

@ -1,5 +1,5 @@
<script>
import { uploadBlob, postCreate } from "../api.js";
import { uploadBlob, postCreate, getTagAutocomplete } from "../api.js";
import { navigate, Link } from "svelte-routing";
import Tags from "svelte-tags-input";
import AuthRequired from "../AuthRequired.svelte";
@ -38,6 +38,11 @@
form.tags = value.detail.tags;
};
const onAutocomplete = async () => {
const list = await getTagAutocomplete();
return list;
};
const onSubmit = async () => {
const response = await postCreate(form);
navigate(`/post/${response.id}`);
@ -107,7 +112,7 @@
<div class="field">
<label for="tags" class="label">Tags</label>
<div class="control" id="tags">
<Tags addKeys={[9, 32]} on:tags={onTagChange} />
<Tags addKeys={[9, 32]} on:tags={onTagChange} autoComplete={onAutocomplete} />
</div>
</div>
<div class="control">