WIP
This commit is contained in:
parent
094f8a3fb3
commit
01eca061ce
25
app/http/endpoints/api/emojis.go
Normal file
25
app/http/endpoints/api/emojis.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/botcontext"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EmojisHandler(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
botContext, err := botcontext.ContextForGuild(guildId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
emojis, err := botContext.GetGuildEmojis(guildId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, emojis)
|
||||||
|
}
|
@ -75,6 +75,7 @@ func StartServer() {
|
|||||||
guildAuthApiSupport.GET("/premium", api.PremiumHandler)
|
guildAuthApiSupport.GET("/premium", api.PremiumHandler)
|
||||||
guildAuthApiSupport.GET("/user/:user", api.UserHandler)
|
guildAuthApiSupport.GET("/user/:user", api.UserHandler)
|
||||||
guildAuthApiSupport.GET("/roles", api.RolesHandler)
|
guildAuthApiSupport.GET("/roles", api.RolesHandler)
|
||||||
|
guildAuthApiSupport.GET("/emojis", rl(middleware.RateLimitTypeGuild, 5, time.Second*30), api.EmojisHandler)
|
||||||
guildAuthApiSupport.GET("/members/search",
|
guildAuthApiSupport.GET("/members/search",
|
||||||
rl(middleware.RateLimitTypeGuild, 5, time.Second),
|
rl(middleware.RateLimitTypeGuild, 5, time.Second),
|
||||||
rl(middleware.RateLimitTypeGuild, 10, time.Second*30),
|
rl(middleware.RateLimitTypeGuild, 10, time.Second*30),
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/TicketsBot/database"
|
"github.com/TicketsBot/database"
|
||||||
"github.com/rxdn/gdl/objects/channel"
|
"github.com/rxdn/gdl/objects/channel"
|
||||||
"github.com/rxdn/gdl/objects/guild"
|
"github.com/rxdn/gdl/objects/guild"
|
||||||
|
"github.com/rxdn/gdl/objects/guild/emoji"
|
||||||
"github.com/rxdn/gdl/objects/member"
|
"github.com/rxdn/gdl/objects/member"
|
||||||
"github.com/rxdn/gdl/objects/user"
|
"github.com/rxdn/gdl/objects/user"
|
||||||
"github.com/rxdn/gdl/rest"
|
"github.com/rxdn/gdl/rest"
|
||||||
@ -100,6 +101,19 @@ func (ctx BotContext) GetGuildRoles(guildId uint64) (roles []guild.Role, err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx BotContext) GetGuildEmojis(guildId uint64) (emojis []emoji.Emoji, err error) {
|
||||||
|
if emojis := cache.Instance.GetGuildEmojis(guildId); len(emojis) > 0 {
|
||||||
|
return emojis, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
emojis, err = rest.ListGuildEmojis(ctx.Token, ctx.RateLimiter, guildId)
|
||||||
|
if err == nil {
|
||||||
|
go cache.Instance.StoreEmojis(emojis, guildId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx BotContext) SearchMembers(guildId uint64, query string) (members []member.Member, err error) {
|
func (ctx BotContext) SearchMembers(guildId uint64, query string) (members []member.Member, err error) {
|
||||||
data := rest.SearchGuildMembersData{
|
data := rest.SearchGuildMembersData{
|
||||||
Query: query,
|
Query: query,
|
||||||
|
97
frontend/src/components/EmojiItem.svelte
Normal file
97
frontend/src/components/EmojiItem.svelte
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<script>
|
||||||
|
export let isActive = false;
|
||||||
|
export let isFirst = false;
|
||||||
|
export let isHover = false;
|
||||||
|
export let isSelectable = false;
|
||||||
|
export let getOptionLabel = undefined;
|
||||||
|
export let item = undefined;
|
||||||
|
export let filterText = '';
|
||||||
|
|
||||||
|
let itemClasses = '';
|
||||||
|
|
||||||
|
$: {
|
||||||
|
const classes = [];
|
||||||
|
if (isActive) {
|
||||||
|
classes.push('active');
|
||||||
|
}
|
||||||
|
if (isFirst) {
|
||||||
|
classes.push('first');
|
||||||
|
}
|
||||||
|
if (isHover) {
|
||||||
|
classes.push('hover');
|
||||||
|
}
|
||||||
|
if (item.isGroupHeader) {
|
||||||
|
classes.push('groupHeader');
|
||||||
|
}
|
||||||
|
if (item.isGroupItem) {
|
||||||
|
classes.push('groupItem');
|
||||||
|
}
|
||||||
|
if (!isSelectable) {
|
||||||
|
classes.push('notSelectable');
|
||||||
|
}
|
||||||
|
itemClasses = classes.join(' ');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.item {
|
||||||
|
cursor: default;
|
||||||
|
height: var(--height, 42px);
|
||||||
|
line-height: var(--height, 42px);
|
||||||
|
padding: var(--itemPadding, 0 20px);
|
||||||
|
color: var(--itemColor, inherit);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groupHeader {
|
||||||
|
text-transform: var(--groupTitleTextTransform, uppercase);
|
||||||
|
}
|
||||||
|
|
||||||
|
.groupItem {
|
||||||
|
padding-left: var(--groupItemPaddingLeft, 40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
.item:active {
|
||||||
|
background: var(--itemActiveBackground, #b9daff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.active {
|
||||||
|
background: var(--itemIsActiveBG, #007aff);
|
||||||
|
color: var(--itemIsActiveColor, #fff);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
.item.notSelectable {
|
||||||
|
color: var(--itemIsNotSelectableColor, #999);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.first {
|
||||||
|
border-radius: var(--itemFirstBorderRadius, 4px 4px 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.hover:not(.active) {
|
||||||
|
background: var(--itemHoverBG, #e7f2ff);
|
||||||
|
color: var(--itemHoverColor, inherit);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="item {itemClasses}">
|
||||||
|
<img class="icon" src={`https://cdn.discordapp.com/emojis/${item.id}.png`} alt={item.name} />
|
||||||
|
<span class="name">:{item.name}:</span>
|
||||||
|
</div>
|
@ -1,5 +1,7 @@
|
|||||||
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
||||||
<label for="input" class="form-label">{label}</label>
|
{#if label !== undefined}
|
||||||
|
<label class="form-label">{label}</label>
|
||||||
|
{/if}
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<input id="input" class="form-input" placeholder="{placeholder}" disabled="{disabled}" bind:value={value}>
|
<input id="input" class="form-input" placeholder="{placeholder}" disabled="{disabled}" bind:value={value}>
|
||||||
{#if !disabled}
|
{#if !disabled}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{#if label !== undefined}
|
`{#if label !== undefined}
|
||||||
<label class="form-label">{label}</label>
|
<label class="form-label">{label}</label>
|
||||||
{/if}
|
{/if}`
|
||||||
|
|
||||||
<div class="multiselect-super">
|
<div class="multiselect-super">
|
||||||
<Select placeholder="Search..." optionIdentifier="id" items={roles}
|
<Select placeholder="Search..." optionIdentifier="id" items={roles}
|
||||||
|
@ -12,26 +12,46 @@
|
|||||||
<Colour col4=true label="Panel Colour" on:change={updateColour} bind:value={tempColour}/>
|
<Colour col4=true label="Panel Colour" on:change={updateColour} bind:value={tempColour}/>
|
||||||
<ChannelDropdown label="Panel Channel" col4=true {channels} bind:value={data.channel_id}/>
|
<ChannelDropdown label="Panel Channel" col4=true {channels} bind:value={data.channel_id}/>
|
||||||
<CategoryDropdown label="Ticket Category" col4=true {channels} bind:value={data.category_id}/>
|
<CategoryDropdown label="Ticket Category" col4=true {channels} bind:value={data.category_id}/>
|
||||||
<div class="col-4" style="z-index: 1">
|
<Dropdown col4=true label="Form" bind:value={data.form_id}>
|
||||||
<EmojiInput label="Button Emoji" col1=true bind:value={data.emote}/>
|
<option value=null>None</option>
|
||||||
</div>
|
{#each forms as form}
|
||||||
|
<option value={form.form_id}>{form.title}</option>
|
||||||
|
{/each}
|
||||||
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<Dropdown col3=true label="Button Style" bind:value={data.button_style}>
|
<Dropdown col4=true label="Button Style" bind:value={data.button_style}>
|
||||||
<option value="1">Blue</option>
|
<option value="1">Blue</option>
|
||||||
<option value="2">Grey</option>
|
<option value="2">Grey</option>
|
||||||
<option value="3">Green</option>
|
<option value="3">Green</option>
|
||||||
<option value="4">Red</option>
|
<option value="4">Red</option>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
<Input col3={true} label="Button Text" placeholder="Open a ticket!" bind:value={data.button_label} />
|
<Input col4={true} label="Button Text" placeholder="Open a ticket!" bind:value={data.button_label} />
|
||||||
|
|
||||||
<Dropdown col3=true label="Form" bind:value={data.form_id}>
|
<div class="col-2" style="z-index: 1">
|
||||||
<option value=null>None</option>
|
<label for="emoji-pick-wrapper" class="form-label">Button Emoji</label>
|
||||||
{#each forms as form}
|
<div id="emoji-pick-wrapper" class="row">
|
||||||
<option value={form.form_id}>{form.title}</option>
|
<div class="col-2">
|
||||||
{/each}
|
<label for="use-custom-emoji" class="form-label">Custom Emoji</label>
|
||||||
</Dropdown>
|
<input id="use-custom-emoji" class="form-checkbox" type=checkbox bind:checked={data.use_custom_emoji} on:change={() => console.log('a')}>
|
||||||
|
</div>
|
||||||
|
{#if data.use_custom_emoji}
|
||||||
|
<!--bind:selectedValue={selectedMentions}
|
||||||
|
on:select={updateMentions}-->
|
||||||
|
<div class="multiselect-super">
|
||||||
|
<Select items={emojis}
|
||||||
|
Item={EmojiItem}
|
||||||
|
optionIdentifier="id"
|
||||||
|
getSelectionLabel={emojiNameMapper}
|
||||||
|
getOptionLabel={emojiNameMapper}
|
||||||
|
placeholderAlwaysShow={true} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<EmojiInput col1=true bind:value={data.emote}/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="justify-content: center">
|
<div class="row" style="justify-content: center">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
@ -70,7 +90,7 @@
|
|||||||
on:select={updateTeams}
|
on:select={updateTeams}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
optionIdentifier="id"
|
optionIdentifier="id"
|
||||||
getSelectionLabel={nameMapper}
|
getSelectionLabel={emojiNameMapper}
|
||||||
getOptionLabel={nameMapper}
|
getOptionLabel={nameMapper}
|
||||||
isMulti={true} />
|
isMulti={true} />
|
||||||
</div>
|
</div>
|
||||||
@ -95,8 +115,10 @@
|
|||||||
import {colourToInt, intToColour} from "../../js/util";
|
import {colourToInt, intToColour} from "../../js/util";
|
||||||
import CategoryDropdown from "../CategoryDropdown.svelte";
|
import CategoryDropdown from "../CategoryDropdown.svelte";
|
||||||
import EmojiInput from "../form/EmojiInput.svelte";
|
import EmojiInput from "../form/EmojiInput.svelte";
|
||||||
|
import EmojiItem from "../EmojiItem.svelte";
|
||||||
import Select from 'svelte-select';
|
import Select from 'svelte-select';
|
||||||
import Dropdown from "../form/Dropdown.svelte";
|
import Dropdown from "../form/Dropdown.svelte";
|
||||||
|
import Checkbox from "../form/Checkbox.svelte";
|
||||||
|
|
||||||
export let guildId;
|
export let guildId;
|
||||||
export let seedDefault = true;
|
export let seedDefault = true;
|
||||||
@ -109,6 +131,7 @@
|
|||||||
|
|
||||||
export let channels = [];
|
export let channels = [];
|
||||||
export let roles = [];
|
export let roles = [];
|
||||||
|
export let emojis = [];
|
||||||
export let teams = [];
|
export let teams = [];
|
||||||
export let forms = [];
|
export let forms = [];
|
||||||
|
|
||||||
@ -144,6 +167,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nameMapper = (team) => team.name;
|
const nameMapper = (team) => team.name;
|
||||||
|
const emojiNameMapper = (emoji) => `:${emoji.name}:`;
|
||||||
|
|
||||||
function mentionNameMapper(role) {
|
function mentionNameMapper(role) {
|
||||||
if (role.id === "user") {
|
if (role.id === "user") {
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
<div slot="body" class="card-body">
|
<div slot="body" class="card-body">
|
||||||
<p>Your panel quota: <b>{panels.length} / {isPremium ? '∞' : '3'}</b></p>
|
<p>Your panel quota: <b>{panels.length} / {isPremium ? '∞' : '3'}</b></p>
|
||||||
|
|
||||||
|
<img src="https://cdn.discordapp.com/emojis/986995010136318022.png" />
|
||||||
|
|
||||||
<table style="margin-top: 10px">
|
<table style="margin-top: 10px">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -55,7 +57,7 @@
|
|||||||
|
|
||||||
<div slot="body" class="body-wrapper">
|
<div slot="body" class="body-wrapper">
|
||||||
{#if !$loadingScreen}
|
{#if !$loadingScreen}
|
||||||
<PanelCreationForm {guildId} {channels} {roles} {teams} {forms} bind:data={panelCreateData}/>
|
<PanelCreationForm {guildId} {channels} {roles} {emojis} {teams} {forms} bind:data={panelCreateData}/>
|
||||||
<div style="display: flex; justify-content: center">
|
<div style="display: flex; justify-content: center">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<Button icon="fas fa-paper-plane" fullWidth={true} on:click={createPanel}>Submit</Button>
|
<Button icon="fas fa-paper-plane" fullWidth={true} on:click={createPanel}>Submit</Button>
|
||||||
@ -142,6 +144,7 @@
|
|||||||
|
|
||||||
let channels = [];
|
let channels = [];
|
||||||
let roles = [];
|
let roles = [];
|
||||||
|
let emojis = [];
|
||||||
let teams = [];
|
let teams = [];
|
||||||
let forms = [];
|
let forms = [];
|
||||||
let panels = [];
|
let panels = [];
|
||||||
@ -332,6 +335,16 @@
|
|||||||
roles = res.data.roles;
|
roles = res.data.roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadEmojis() {
|
||||||
|
const res = await axios.get(`${API_URL}/api/${guildId}/emojis`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emojis = res.data;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadForms() {
|
async function loadForms() {
|
||||||
const res = await axios.get(`${API_URL}/api/${guildId}/forms`);
|
const res = await axios.get(`${API_URL}/api/${guildId}/forms`);
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
@ -349,6 +362,7 @@
|
|||||||
loadTeams(),
|
loadTeams(),
|
||||||
loadForms(),
|
loadForms(),
|
||||||
loadRoles(),
|
loadRoles(),
|
||||||
|
loadEmojis(),
|
||||||
loadPanels(),
|
loadPanels(),
|
||||||
loadMultiPanels()
|
loadMultiPanels()
|
||||||
]);
|
]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user