base_ui/components/other/_NotionComponent.vue
2025-02-01 13:04:55 +03:30

552 lines
14 KiB
Vue

<template>
<div class="form-row form-group" :key="$attrs.key">
<vue-tribute class="tribute-container" :options="tributeOptions">
<div class="ta-header">
<div class="ta-type-selection">
<multiselect
v-model="types[0]"
id="group-filter"
placeholder=""
track-by="id"
label="title"
:options="types"
:searchable="true"
:options-limit="300"
:limit="10"
:max-height="350"
selectLabel=""
selectedLabel=""
deselectLabel=""
:close-on-select="true"
:clear-on-select="false"
:preserve-search="true"
>
<!-- <template slot="selection" slot-scope="{ values, search, isOpen }"
><span
class="multiselect__single"
v-if="values.length"
v-show="!isOpen"
>{{ values.length }} فیلتر</span
></template
> -->
<!-- <template slot="noResult" slot-scope="{ values, search, isOpen }">
چیزی یافت نشد.
</template>
<template slot="noOptions" slot-scope="{ values, search, isOpen }">
فهرست خالی است.
</template> -->
</multiselect>
</div>
<div class="ta-options">
<div class="ta-options-item">
<svg role="graphics-symbol" viewBox="0 0 14 16" class="copy">
<path
d="M2.404 15.322h5.701c1.26 0 1.887-.662 1.887-1.927V12.38h1.154c1.254 0 1.91-.662 1.91-1.928V5.555c0-.774-.158-1.266-.626-1.74L9.512.837C9.066.387 8.545.21 7.865.21H5.463c-1.254 0-1.91.662-1.91 1.928v1.084H2.404c-1.254 0-1.91.668-1.91 1.933v8.239c0 1.265.656 1.927 1.91 1.927zm7.588-6.62c0-.792-.1-1.161-.592-1.665L6.225 3.814c-.452-.462-.844-.58-1.5-.591V2.215c0-.533.28-.832.843-.832h2.38v2.883c0 .726.386 1.113 1.107 1.113h2.83v4.998c0 .539-.276.832-.844.832H9.992V8.701zm-.79-4.29c-.206 0-.288-.088-.288-.287V1.594l2.771 2.818H9.201zM2.503 14.15c-.563 0-.844-.293-.844-.832V5.232c0-.539.281-.837.85-.837h1.91v3.187c0 .85.416 1.26 1.26 1.26h3.14v4.476c0 .54-.28.832-.843.832H2.504zM5.79 7.816c-.24 0-.346-.105-.346-.345V4.547l3.223 3.27H5.791z"
></path>
</svg>
کپی
</div>
<div class="ta-options-item">کپشن</div>
<div class="ta-options-item">
<div class="dropdown">
<button
class="btn btn-secondary dropdown-toggle"
type="button"
>
<svg
role="graphics-symbol"
viewBox="0 0 13 3"
class="dots"
style="
width: 14px;
height: 14px;
display: block;
fill: inherit;
flex-shrink: 0;
"
>
<g>
<path
d="M3,1.5A1.5,1.5,0,1,1,1.5,0,1.5,1.5,0,0,1,3,1.5Z"
></path>
<path
d="M8,1.5A1.5,1.5,0,1,1,6.5,0,1.5,1.5,0,0,1,8,1.5Z"
></path>
<path
d="M13,1.5A1.5,1.5,0,1,1,11.5,0,1.5,1.5,0,0,1,13,1.5Z"
></path>
</g>
</svg>
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu2">
<button class="dropdown-item" type="button">Action</button>
<button class="dropdown-item" type="button">
Another action
</button>
<button class="dropdown-item" type="button">
Something else here
</button>
</div>
</div>
</div>
</div>
</div>
<textarea
@tribute-no-match="noMatchFound"
@tribute-replaced="textReplaced"
:ref="localFormElement.key"
class="form-control"
@focus="clearErrors"
@blur="validate"
@change="validate"
:placeholder="localFormElement.placeholder"
:id="localFormElement.key"
:name="localFormElement.key"
v-model="textValue"
cols="1"
rows="1"
>
</textarea>
<div class="ta-footer">
<input
class="form-control ta-footer-input"
type="text"
value="فریم وظیفه"
/>
</div>
</vue-tribute>
<context-menu
style="position: static; display: inline-flex"
v-if="contextMenu.length"
:id="'context-menu-' + localFormElement.key"
:contextMenu="contextMenu"
@other="methodName($event)"
>
</context-menu>
</div>
</template>
<script>
import formBuilderMixin from "~/extensions/formBuilderExtension";
import VueTribute from "vue-tribute";
import apis from "~/apis/borhanApi.js";
export default {
props: {
enableSuggestion: {
default: false,
},
contextMenu: {
default() {
return [];
},
},
},
extends: formBuilderMixin,
data() {
return {
types: [
{
id: "1",
title: "javascript",
},
{
id: "2",
title: "PHP",
},
{
id: "3",
title: "SpareQL",
},
{
id: "4",
title: "Paython",
},
{
id: "5",
title: "BASIC",
},
],
tributeOptions: {
// symbol or string that starts the lookup
trigger: "",
// element to target for @mentions
iframe: null,
// class added in the flyout menu for active item
selectClass: "highlight",
// class added to the menu container
containerClass: "tribute-container large",
// class added to each list item
itemClass: "my-tribute-class",
// function called on select that returns the content to insert
selectTemplate: function (item) {
return item.original.value;
// return "@" + item.original.value;
},
// template for displaying item in menu
menuItemTemplate: function (item) {
return item.string;
},
// template for when no match is found (optional),
// If no template is provided, menu is hidden.
noMatchTemplate:
'<span class="no-result">مورد مشابهی ثبت نشده است.</span>',
// specify an alternative parent container for the menu
// container must be a positioned element for the menu to appear correctly ie. `position: relative;`
// default container is the body
menuContainer: document.body,
// column to search against in the object (accepts function or string)
lookup: "key",
// column that contains the content to insert by default
fillAttr: "value",
// REQUIRED: array of objects to match or a function that returns data (see 'Loading remote data' for an example)
values: [
{
key: "سلام",
value: "سلام",
},
{
key: "باسلام",
value: "باسلام",
},
{
key: "علیک سلام",
value: "علیک سلام",
},
{
key: "بی سلام",
value: "بی سلام",
},
{
key: "صدتا سلام",
value: "صدتا سلام",
},
],
// values: ["سلام", "باسلام", "علیک سلام", "بی سلام", "صدتا سلام"],
// values: (text, cb) => {
// this.remoteSearch(text, (items) => cb(items));
// },
// When your values function is async, an optional loading template to show
loadingItemTemplate: null,
// specify whether a space is required before the trigger string
requireLeadingSpace: true,
// specify whether a space is allowed in the middle of mentions
allowSpaces: true,
// optionally specify a custom suffix for the replace text
// (defaults to empty space if undefined)
// replaceTextSuffix: "",
// specify whether the menu should be positioned. Set to false and use in conjuction with menuContainer to create an inline menu
// (defaults to true)
positionMenu: true,
// when the spacebar is hit, select the current match
spaceSelectsMatch: false,
// turn tribute into an autocomplete
autocompleteMode: true,
// Customize the elements used to wrap matched strings within the results list
// defaults to <span></span> if undefined
searchOpts: {
pre: "<span>",
post: "</span>",
skip: false, // true will skip local search, useful if doing server-side search
},
// Limits the number of items in the menu
menuItemLimit: 25,
// specify the minimum number of characters that must be typed before menu appears
menuShowMinLength: 0,
},
httpService: undefined,
};
},
mounted() {
this.httpService = new HttpService(import.meta.env.VITE_BASE_URL);
},
methods: {
limitText(count) {
return `و ${count} کاربر دیگر`;
},
noMatchFound(args) {
},
textReplaced(args) {
},
methodName(action, index = 0) {
try {
this[action](index);
} catch (err) {
this.$emit(action, index);
}
},
remoteSearch(input, callback) {
return this.httpService
.getRequest(apis.concept.annotations.read + "?ontology_id=" + input)
.then((res) => {
callback(res.data);
})
.catch((e) => {
callback([]);
})
.finally(() => {
this.fetchingData = false;
});
},
},
};
</script>
<!-- #region tribute -->
<style scoped lang="scss">
.multiselect {
font-size: 11px;
-webkit-box-sizing: content-box;
box-sizing: content-box;
display: block;
position: relative;
width: 100%;
min-height: 30px;
text-align: left;
color: #35495e;
&.multiselect--active {
background-color: #fff;
z-index: 999999;
}
}
.multiselect__content-wrapper {
z-index: 9999;
}
.multiselect__select {
position: absolute;
width: 40px;
height: 33px;
right: 1px;
top: 1px;
padding: 4px 8px;
text-align: center;
-webkit-transition: -webkit-transform 0.2s ease;
transition: -webkit-transform 0.2s ease;
transition: transform 0.2s ease;
transition: transform 0.2s ease, -webkit-transform 0.2s ease;
&::before {
position: relative;
right: 0;
top: unset;
color: #999;
margin-top: 0;
border: none;
background-size: contain;
width: 2em;
height: 2em;
display: inline-block;
background-repeat: no-repeat;
background-image: url("../../assets/common/img/Component-25--1.svg");
}
}
.multiselect__tags {
min-height: 30px;
display: block;
padding: 8px 40px 0 8px;
border-radius: 5px;
border: 1px solid #e8e8e8;
background: #fff;
font-size: 14px;
border-color: transparent;
background: transparent;
}
[dir="rtl"] .multiselect__tags {
padding: 5px 5px 0 30px;
}
.multiselect__input,
.multiselect__single {
position: relative;
display: inline-block;
min-height: 20px;
line-height: 20px;
border: none;
border-radius: 5px;
background: transparent;
padding: 0 0 0 5px;
width: 100%;
-webkit-transition: border 0.1s ease;
transition: border 0.1s ease;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 8px;
vertical-align: top;
}
.form-group {
&:hover {
.ta-header,
.ta-options {
opacity: 1;
visibility: visible;
transition: opacity 300ms ease-in 0s;
}
}
&.active,
&:active {
.ta-header,
.ta-options {
opacity: 1;
visibility: visible;
transition: opacity 300ms ease-in 0s;
}
}
}
</style>
<!-- #endregion tribute -->
<style lang="scss" scoped>
.ta-header {
position: absolute;
top: 3px;
right: 8px;
left: 1px;
display: flex;
justify-content: space-between;
opacity: 0;
visibility: hidden;
transition: opacity 300ms ease-in 0s;
.ta-type-selection {
// position: absolute;
// top: 8px;
// right: 8px;
z-index: 1;
color: rgba(55, 53, 47, 0.65);
display: flex;
align-items: center;
justify-content: flex-end;
opacity: 1;
transition: opacity 300ms ease-in 0s;
}
}
.ta-options {
opacity: 0;
visibility: hidden;
// position: absolute;
// top: 3px;
// left: 1px;
z-index: 1;
color: rgba(55, 53, 47, 0.65);
display: flex;
align-items: center;
justify-content: flex-end;
height: 25px;
font-size: 11.5px;
transition: opacity 300ms ease-in 0s;
.ta-options-item {
user-select: none;
transition: background 20ms ease-in 0s;
cursor: pointer;
display: inline-flex;
align-items: center;
white-space: nowrap;
height: 25px;
border-radius: 4px 0px 0px 4px;
font-size: 11.5px;
line-height: 1.2;
padding: 4px 6px;
color: rgb(55, 53, 47);
background: rgb(234, 233, 229);
font-weight: 400;
svg {
width: 16px;
height: 16px;
display: block;
fill: inherit;
flex-shrink: 0;
padding-right: 4px;
}
}
}
.ta-footer {
background: white;
padding-left: 105px;
.ta-footer-input {
border-radius: unset;
height: unset;
max-width: 100%;
width: 100%;
white-space: pre-wrap;
word-break: break-word;
caret-color: rgb(55, 53, 47);
font-size: 14px;
line-height: 1.4;
color: rgba(55, 53, 47, 0.65);
padding-top: 6px;
padding-bottom: 6px;
padding-left: 2px;
border-color: transparent !important;
background-color: #fff;
}
}
.form-control {
flex-grow: 1;
flex-shrink: 1;
tab-size: 2;
padding: 34px 16px 32px 32px;
min-height: 1em;
color: rgb(55, 53, 47);
white-space: pre;
border-radius: 4px;
position: relative;
background: rgb(247, 246, 243);
min-width: 0px;
width: 100%;
resize: none;
border-color: transparent;
}
.main-page__content .form-builder div input {
border-color: transparent !important;
}
</style>