add tag link

This commit is contained in:
monoid 2021-01-17 01:33:45 +09:00
parent 64f5c82c8c
commit e63e82fde9
6 changed files with 53 additions and 30 deletions

View File

@ -11,8 +11,8 @@ export const toQueryString = (obj:ToQueryStringA)=> {
e[1] !== undefined)
.map(e =>
e[1] instanceof Array
? e[1].map(f=>`${e[0]}[]=${encodeURIComponent(f)}`).join('&')
: `${e[0]}=${encodeURIComponent(e[1])}`)
? e[1].map(f=>`${e[0]}=${(f)}`).join('&')
: `${e[0]}=${(e[1])}`)
.join('&');
}
export const QueryStringToMap = (query:string) =>{
@ -20,16 +20,16 @@ export const QueryStringToMap = (query:string) =>{
const param:{[k:string]:string|string[]} = {};
keyValue.forEach((p)=>{
const [k,v] = p.split("=");
if(k.endsWith("[]")){
let arr = param[k];
if(arr instanceof Array){
arr.push(v);
}
else{
param[k] = [v];
}
const pv = param[k];
if(pv === undefined){
param[k] = v;
}
else if(typeof pv === "string"){
param[k] = [pv,v];
}
else{
pv.push(v);
}
else param[k] = v;
});
return param;
}

View File

@ -117,7 +117,7 @@ export const ContentInfo = (props: {
</Link>
<Box className={propclasses.subinfoContainer || subinfoContainer}>
{props.short ? (<Box className={propclasses.tag_list || classes.tag_list}>{document.tags.map(x =>
(<TagChip key={x} label={x} clickable={true} tagname={x} size="small"></TagChip>)
(<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>)
)}</Box>) : (
<>
<Typography variant='subtitle1'>Artist</Typography>
@ -125,7 +125,7 @@ export const ContentInfo = (props: {
<Typography variant='subtitle1'>Tags</Typography>
<Box className={propclasses.tag_list || classes.tag_list}>
{allTag.map(x => {
return (<TagChip key={x} label={x} clickable={true} tagname={x} size="small"></TagChip>);
return (<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>);
})}
</Box>
</>)

View File

@ -1,7 +1,8 @@
import React from 'react';
import {ChipProps} from '@material-ui/core/Chip';
import {ChipTypeMap} from '@material-ui/core/Chip';
import { Chip, colors } from '@material-ui/core';
import {useTheme, makeStyles, Theme, emphasize, fade} from '@material-ui/core/styles';
import {Link as RouterLink} from 'react-router-dom';
type TagChipStyleProp = {
color: string
@ -43,14 +44,20 @@ const useTagStyles = makeStyles((theme:Theme)=>({
const {blue, pink} = colors;
const getTagColorName = (tagname :string):string=>{
if(tagname.startsWith("female")){
return pink['700'];
return pink[600];
}
else if(tagname.startsWith("male")){
return blue[600];
}
else return "default";
}
export const ColorChip = (props:Omit<ChipProps,"color"> & {color: string})=>{
type ColorChipProp = Omit<ChipTypeMap['props'],"color"> & TagChipStyleProp & {
component?: React.ElementType,
to?: string
}
export const ColorChip = (props:ColorChipProp)=>{
const {color,...rest} = props;
const classes = useTagStyles({color : color !== "default" ? color : "#000"});
return <Chip color="default" classes={{
@ -58,8 +65,12 @@ export const ColorChip = (props:Omit<ChipProps,"color"> & {color: string})=>{
}} {...rest}></Chip>;
}
export const TagChip = (props:Omit<ChipProps,"color"> & {tagname: string})=>{
const {tagname,label,...rest} = props;
type TagChipProp = Omit<ChipTypeMap['props'],"color"> & {
tagname:string
}
export const TagChip = (props:TagChipProp)=>{
const {tagname,label,clickable,...rest} = props;
let newlabel:string|undefined = undefined;
if(typeof label === "string"){
if(label.startsWith("female:")){
@ -69,5 +80,9 @@ export const TagChip = (props:Omit<ChipProps,"color"> & {tagname: string})=>{
newlabel = "♂ "+label.slice(5);
}
}
return <ColorChip color={getTagColorName(tagname)} label={newlabel||label} {...rest}></ColorChip>;
const inner = clickable ?
(<ColorChip color={getTagColorName(tagname)} clickable={clickable} label={newlabel||label} {...rest}
component={RouterLink} to={`/search?allow_tag=${tagname}`}></ColorChip>):
(<ColorChip color={getTagColorName(tagname)} clickable={clickable} label={newlabel||label} {...rest}></ColorChip>);
return inner;
}

View File

@ -80,12 +80,16 @@ class KnexDocumentAccessor implements DocumentAccessor{
const cursor = option.cursor;
const buildquery = ()=>{
let query = this.knex.select("*");
let query = this.knex.select("document.*");
if(allow_tag.length > 0){
query = query.from("doc_tag_relation").innerJoin("document","doc_tag_relation.doc_id","document.id");
for(const tag of allow_tag){
query = query.where({tag_name:tag});
query = query.from("doc_tag_relation as tags_0");
query = query.where("tags_0.tag_name","=",allow_tag[0]);
for (let index = 1; index < allow_tag.length; index++) {
const element = allow_tag[index];
query = query.innerJoin(`doc_tag_relation as tags_${index}`,`tags_${index}.doc_id`,"tags_0.doc_id");
query = query.where(`tags_${index}.tag_name`,'=',element);
}
query = query.innerJoin("document","tags_0.doc_id","document.id");
}
else{
query = query.from("document");

View File

@ -2,7 +2,7 @@ import { Context, Next } from 'koa';
import Router from 'koa-router';
import {Document, DocumentAccessor, isDocBody} from '../model/doc';
import {QueryListOption} from '../model/doc';
import {ParseQueryNumber, ParseQueryArray, ParseQueryBoolean} from './util'
import {ParseQueryNumber, ParseQueryArray, ParseQueryBoolean, ParseQueryArgString} from './util'
import {sendError} from './error_handler';
import { join } from 'path';
import {AllContentRouter} from './all';
@ -31,14 +31,14 @@ const ContentTagIDHandler = (controller: DocumentAccessor) => async (ctx: Contex
const ContentQueryHandler = (controller : DocumentAccessor) => async (ctx: Context,next: Next)=>{
const limit = ParseQueryNumber(ctx.query['limit']);
const cursor = ParseQueryNumber(ctx.query['cursor']);
const word: string|undefined = ctx.query['word'];
const content_type:string|undefined = ctx.query['content_type'];
const word = ParseQueryArgString(ctx.query['word']);
const content_type = ParseQueryArgString(ctx.query['content_type']);
const offset = ParseQueryNumber(ctx.query['offset']);
if(limit === NaN || cursor === NaN || offset === NaN){
return sendError(400,"parameter limit, cursor or offset is not a number");
}
const allow_tag = ParseQueryArray(ctx.query['allow_tag[]']);
let [ok,use_offset] = ParseQueryBoolean(ctx.query['use_offset']);
const allow_tag = ParseQueryArray(ctx.query['allow_tag']);
const [ok,use_offset] = ParseQueryBoolean(ctx.query['use_offset']);
if(!ok){
return sendError(400,"use_offset must be true or false.");
}
@ -50,7 +50,7 @@ const ContentQueryHandler = (controller : DocumentAccessor) => async (ctx: Conte
eager_loading: true,
offset: offset,
use_offset: use_offset,
content_type:content_type,
content_type: content_type,
};
let document = await controller.findList(option);
ctx.body = document;

View File

@ -8,7 +8,11 @@ export function ParseQueryNumber(s: string|undefined): number| undefined{
}
export function ParseQueryArray(s: string[]|string|undefined){
s = s || [];
return s instanceof Array ? s : [s];
const r = s instanceof Array ? s : [s];
return r.map(x=>decodeURIComponent(x));
}
export function ParseQueryArgString(s: string|undefined){
return s === undefined ? s : decodeURIComponent(s);
}
export function ParseQueryBoolean(s: string|undefined): [boolean,boolean|undefined]{
let value:boolean|undefined;