add tag link
This commit is contained in:
		
							parent
							
								
									64f5c82c8c
								
							
						
					
					
						commit
						e63e82fde9
					
				
					 6 changed files with 53 additions and 30 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
                    </>)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue