I need to get back into using git. The hell is wrong with me!?
This commit is contained in:
@@ -1,71 +1,62 @@
|
||||
<template>
|
||||
<!-- change class to .master-note-edit to have it popup on the screen -->
|
||||
<div
|
||||
id="InputNotes" class="master-note-edit"
|
||||
id="InputNotes"
|
||||
class="master-note-edit"
|
||||
@keyup.esc="close"
|
||||
:class="[{'size-down':(sizeDown == true)}, 'position-'+position ]"
|
||||
:style="{'background-color':color, 'color':fontColor}"
|
||||
:style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}"
|
||||
>
|
||||
|
||||
<!-- Loading indicator -->
|
||||
<div v-if="loading" class="loading-note">
|
||||
<div class="ui active dimmer">
|
||||
<div class="ui text loader">{{loadingMessage}}...</div>
|
||||
<div class="ui text loader">{{loadingMessage}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Menu -->
|
||||
<div class="note-top-menu">
|
||||
<div @click="close" class="ui button"><i class="green close icon"></i>Close (ESC)</div>
|
||||
|
||||
<div @click="onToggleFancyInput" class="ui button">
|
||||
Fancy ({{fancyInput?'On':'Off'}})
|
||||
<div @click="close" class="ui basic icon button" data-tooltip="Close" data-position="right center" data-inverted="">
|
||||
<i class="close icon"></i>
|
||||
</div>
|
||||
|
||||
<div @click="onTogglePinned" class="ui button">
|
||||
<i class="pin icon" :class="{green:(pinned == 1)}"></i> {{(pinned == 1)?'pinned':'not pinned'}}
|
||||
<div @click="onTogglePinned" class="ui basic icon button" data-tooltip="Pin to Top" data-position="right center" data-inverted="">
|
||||
<i class="pin icon" :class="{green:(pinned == 1)}"></i> {{(pinned == 1)?'Pinned':''}}
|
||||
</div>
|
||||
<div @click="onToggleArchived" class="ui button">
|
||||
<i class="archive icon" :class="{green:(archived == 1)}"></i> {{(archived == 1)?'archived':'not archived'}}
|
||||
<div @click="onToggleArchived" class="ui basic icon button" data-tooltip="Hide on main" data-position="right center" data-inverted="">
|
||||
<i class="archive icon" :class="{green:(archived == 1)}"></i> {{(archived == 1)?'Archived':''}}
|
||||
</div>
|
||||
|
||||
<span class="relative" v-on:mouseover="showColorPicker = true" v-on:mouseleave="showColorPicker = false">
|
||||
<span class="ui icon button">
|
||||
<!-- <file-upload-button :noteId="noteid" /> -->
|
||||
|
||||
<span class="relative" v-on:click="showColorPicker">
|
||||
<span class="ui basic icon button">
|
||||
<i class="paint brush icon"></i>
|
||||
</span>
|
||||
|
||||
<span v-if="showColorPicker" class="color-picker">
|
||||
<button @click="onChangeColor" class="ui icon white button"></button>
|
||||
<button @click="onChangeColor" class="ui icon red button"></button>
|
||||
<button @click="onChangeColor" class="ui icon orange button"></button>
|
||||
<button @click="onChangeColor" class="ui icon yellow button"></button>
|
||||
<button @click="onChangeColor" class="ui icon olive button"></button>
|
||||
<button @click="onChangeColor" class="ui icon green button"></button>
|
||||
<button @click="onChangeColor" class="ui icon teal button"></button>
|
||||
<button @click="onChangeColor" class="ui icon blue button"></button>
|
||||
<button @click="onChangeColor" class="ui icon violet button"></button>
|
||||
<button @click="onChangeColor" class="ui icon purple button"></button>
|
||||
<button @click="onChangeColor" class="ui icon pink button"></button>
|
||||
<button @click="onChangeColor" class="ui icon brown button"></button>
|
||||
<button @click="onChangeColor" class="ui icon grey button"></button>
|
||||
<button @click="onChangeColor" class="ui icon black button"></button>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div v-if="attachmentCount > 0" class="ui basic icon button" v-on:click="openEditAttachment" data-tooltip="View Links/Images" data-position="right center" data-inverted="">
|
||||
<i class="folder icon"></i>
|
||||
</div>
|
||||
|
||||
<span class="note-status-indicator">{{statusText}}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="fancyInput == 1" class="textarea-height no-flow">
|
||||
<ckeditor ref="main-edit"
|
||||
:editor="editor" @ready="onReady" v-model="noteText" :config="editorConfig" v-on:blur="save" />
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
class="textarea-height raw-edit"
|
||||
v-if="fancyInput == 0"
|
||||
v-model="noteText"
|
||||
v-on:blur="save"
|
||||
v-on:keyup="onKeyup"
|
||||
|
||||
|
||||
<textarea :id="noteid+'-tinymce-editor'">{{noteText}}</textarea>
|
||||
|
||||
<note-tag-edit v-if="!$store.getters.getIsUserOnMobile" :noteId="noteid" :key="'tags-for-note-'+noteid"/>
|
||||
|
||||
<color-picker
|
||||
v-if="colorPickerVisible"
|
||||
:location="colorPickerLocation"
|
||||
@changeColor="onChangeColor"
|
||||
:style-object="styleObject"
|
||||
/>
|
||||
|
||||
<note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -73,21 +64,14 @@
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
import DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';
|
||||
|
||||
//Start working on some plugin, tag plugin, link to other note, interactive checkbox
|
||||
class InsertImage extends Plugin {
|
||||
init() {
|
||||
console.log( 'InsertImage was initialized' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
name: 'InputNotes',
|
||||
props: [ 'noteid', 'position' ],
|
||||
components:{
|
||||
'note-tag-edit': require('@/components/NoteTagEdit.vue').default
|
||||
'note-tag-edit': require('@/components/NoteTagEdit.vue').default,
|
||||
'color-picker': require('@/components/ColorPicker.vue').default,
|
||||
'file-upload-button': require('@/components/FileUploadButton.vue').default,
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
@@ -98,23 +82,19 @@
|
||||
statusText: 'Saved',
|
||||
lastNoteHash: null,
|
||||
saveDebounce: null, //Prevent save from being called numerous times quickly
|
||||
lastSaved: 0,
|
||||
updated: 'Never',
|
||||
editDebounce: null,
|
||||
keyPressesCounter: 0,
|
||||
fancyInput: 0, //Default to basic text edit. Upgrade if set to 1
|
||||
keyPressesCounter: 0, //Determen keys pressed between saves
|
||||
pinned: 0,
|
||||
archived: 0,
|
||||
color: '#fff',
|
||||
fontColor: '#000',
|
||||
sizeDown: false,
|
||||
showColorPicker: false,
|
||||
attachmentCount: 0,
|
||||
styleObject: { 'noteText':null,'noteBackground':null, 'noteIcon':null, 'iconColor':null }, //Style object. Determines colors and badges
|
||||
|
||||
editor: DecoupledEditor,
|
||||
editorConfig: {
|
||||
startupFocus: 'end',
|
||||
toolbar: ["alignment", "fontSize", "removeHighlight", "highlight", "bold", "italic", "strikethrough", "underline", "blockQuote", "heading", "link", "numberedList", "bulletedList", "insertTable", "|", "undo", "redo"]
|
||||
}
|
||||
sizeDown: false, //Used to animate close state
|
||||
colorPickerVisible: false,
|
||||
colorPickerLocation: null,
|
||||
|
||||
tinymce: null, //Initialized editor instance
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -134,24 +114,102 @@
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
|
||||
|
||||
},
|
||||
beforeDestroy(){
|
||||
|
||||
this.$bus.$off('toggle_night_mode', this.listener)
|
||||
//Trash editor instance on close
|
||||
this.tinymce.remove()
|
||||
|
||||
},
|
||||
mounted: function() {
|
||||
|
||||
this.loadNote(this.noteid)
|
||||
//Change TinyMce styles on nightmored change
|
||||
this.$bus.$on('toggle_night_mode', this.setEditorTextColor )
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.loadNote(this.noteid)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onToggleFancyInput(){
|
||||
if(this.fancyInput == 0){
|
||||
this.fancyInput = 1
|
||||
} else {
|
||||
this.fancyInput = 0;
|
||||
initTinyMce(){
|
||||
|
||||
// image_list: [
|
||||
// {title: 'My image 1', value: 'https://www.tinymce.com/my1.gif'},
|
||||
// {title: 'My image 2', value: 'http://www.moxiecode.com/my2.gif'}
|
||||
// ]
|
||||
|
||||
//Tweak doc height for mobile
|
||||
let docHeight = 'calc(100vh - 90px)'
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
docHeight = 'calc(100vh - 37px)'
|
||||
}
|
||||
//Update last note hash, this will tell note to save next update
|
||||
this.lastNoteHash = 0
|
||||
|
||||
//setup skin as dark if night mode is enabled
|
||||
let skin = 'oxide'
|
||||
if(this.$store.getters.getIsNightMode){
|
||||
skin = 'oxide-dark'
|
||||
}
|
||||
|
||||
const editorId = '#'+this.noteid+'-tinymce-editor'
|
||||
|
||||
//Globally defined included in index HTML
|
||||
tinymce.init({
|
||||
selector: editorId,
|
||||
toolbar: 'forecolor backcolor styleselect | bold italic underline | link image | code | undo redo | bullist numlist | outdent indent table, hr, searchreplace | removeformat',
|
||||
plugins: 'paste, link, code, lists, table, hr, searchreplace, image',
|
||||
browser_spellcheck: true,
|
||||
menubar: false,
|
||||
branding: false,
|
||||
statusbar: false,
|
||||
height: docHeight,
|
||||
skin: skin,
|
||||
contextmenu: false,
|
||||
init_instance_callback: this.editorInitCallback,
|
||||
imagetools_toolbar: "imageoptions",
|
||||
})
|
||||
},
|
||||
editorInitCallback(editor){
|
||||
|
||||
this.loading = false //Turn off loading screed when editor is loaded
|
||||
this.tinymce = editor
|
||||
|
||||
this.setEditorTextColor()
|
||||
|
||||
editor
|
||||
.on('Change', this.onKeyup )
|
||||
.on('keyup', this.onKeyup )
|
||||
.on('blur', this.save )
|
||||
|
||||
},
|
||||
setEditorTextColor(){
|
||||
//Only Set editor text color, background is transparent and set on parent element
|
||||
|
||||
//There may be scenarios where editor has not been set up
|
||||
if(this.tinymce){
|
||||
//Set editor color to color from app, change with night mode
|
||||
this.tinymce.getBody().style.color = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue('--text_color');
|
||||
|
||||
//Overwrite set color if theme is set for note.
|
||||
if(this.styleObject && this.styleObject.noteText){
|
||||
this.tinymce.getBody().style.color = this.styleObject.noteText
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
getText(){
|
||||
//Return text from tinyMce Editor
|
||||
return this.tinymce.getContent()
|
||||
},
|
||||
showColorPicker(event){
|
||||
this.colorPickerVisible = !this.colorPickerVisible
|
||||
this.colorPickerLocation = {'x':event.clientX, 'y':event.clientY}
|
||||
},
|
||||
openEditAttachment(){
|
||||
// this.$bus.$emit('open_edit_attachment', this.currentNoteId)
|
||||
this.$router.push('/attachments/note/'+this.currentNoteId)
|
||||
},
|
||||
onTogglePinned(){
|
||||
if(this.pinned == 0){
|
||||
@@ -161,6 +219,7 @@
|
||||
}
|
||||
//Update last note hash, this will tell note to save next update
|
||||
this.lastNoteHash = 0
|
||||
this.save()
|
||||
},
|
||||
onToggleArchived(){
|
||||
if(this.archived == 0){
|
||||
@@ -170,18 +229,14 @@
|
||||
}
|
||||
//Update last note hash, this will tell note to save next update
|
||||
this.lastNoteHash = 0
|
||||
this.save()
|
||||
},
|
||||
onChangeColor(event){
|
||||
//Grab the color of the button clicked
|
||||
const style = getComputedStyle(event.target)
|
||||
this.color = style['background-color']
|
||||
this.fontColor = '#FFF'
|
||||
onChangeColor(newStyleObject){
|
||||
|
||||
//If background is white, default to colors in CSS
|
||||
if(this.color == "rgb(255, 255, 255)" || this.color == '#FFF'){
|
||||
this.color = null
|
||||
this.fontColor = null
|
||||
}
|
||||
//Set new style object for note, page will use some styles, styles will be saved to database
|
||||
this.styleObject = newStyleObject
|
||||
|
||||
this.setEditorTextColor()
|
||||
|
||||
this.lastNoteHash = 0 //Update hash to force note update on next save
|
||||
this.save()
|
||||
@@ -190,45 +245,34 @@
|
||||
|
||||
let vm = this
|
||||
|
||||
let doing = ['Loading','Loading','Getting','Fetching','Grabbing','Sequencing','Organizing','Untangling','Processing','Refining','Extracting','Fusing','Pruning','Expanding','Enlarging','Transfiguring','Quantizing','Ingratiating']
|
||||
let doing = ['Loading','Loading','Getting','Fetching','Grabbing','Sequencing','Organizing','Untangling','Processing','Refining','Extracting','Fusing','Pruning','Expanding','Enlarging','Transfiguring','Quantizing','Ingratiating','Lumping']
|
||||
let thing = ['Note','Note','Note','Note','Data','Text','Document','Algorithm','Buffer','Client','Download','File','Frame','Graphics','Hardware','HTML','Interface','Logic','Mainframe','Memory','Media','Nodes','Network','Chaos']
|
||||
let p1 = doing[Math.floor(Math.random() * doing.length)]
|
||||
let p2 = thing[Math.floor(Math.random() * thing.length)]
|
||||
vm.loadingMessage = p1 + ' ' + p2
|
||||
|
||||
|
||||
//Component is activated with NoteId in place, lookup text with associated ID
|
||||
if(this.$store.getters.getLoggedIn){
|
||||
axios.post('/api/note/get', {'noteId': noteId})
|
||||
.then(response => {
|
||||
|
||||
vm.loading = false
|
||||
|
||||
//Set up local data
|
||||
vm.currentNoteId = noteId
|
||||
vm.noteText = response.data.text
|
||||
vm.updated = response.data.updated
|
||||
vm.lastNoteHash = vm.hashString(response.data.text)
|
||||
vm.color = response.data.color
|
||||
if(response.data.color){
|
||||
vm.styleObject = JSON.parse(response.data.color) //Load styles json from DB
|
||||
}
|
||||
|
||||
if(response.data.pinned != null){
|
||||
vm.pinned = response.data.pinned
|
||||
}
|
||||
vm.archived = response.data.archived
|
||||
vm.attachmentCount = response.data.attachment_count
|
||||
|
||||
this.fontColor = '#FFF'
|
||||
if(this.color == "rgb(255, 255, 255)" || this.color == '#FFF' || this.color == null){
|
||||
this.color = null
|
||||
this.fontColor = null
|
||||
}
|
||||
|
||||
if(response.data.raw_input == 1){
|
||||
this.fancyInput = 1
|
||||
}
|
||||
|
||||
//Put focus on note, at the end of the note text
|
||||
vm.$nextTick(() => {
|
||||
|
||||
// vm.$refs['custom-input'].focus()
|
||||
this.initTinyMce()
|
||||
})
|
||||
|
||||
})
|
||||
@@ -236,79 +280,53 @@
|
||||
console.log('Could not fetch note')
|
||||
}
|
||||
},
|
||||
onReady(editor){
|
||||
|
||||
let vm = this
|
||||
|
||||
// Insert the toolbar before the editable area.
|
||||
editor.ui.getEditableElement().parentElement.insertBefore(
|
||||
editor.ui.view.toolbar.element,
|
||||
editor.ui.getEditableElement()
|
||||
);
|
||||
|
||||
editor.editing.view.focus()
|
||||
|
||||
// const editor = this.editor;
|
||||
const view = editor.editing.view;
|
||||
const viewDocument = view.document;
|
||||
|
||||
//Insert 5 spaces when tab is pressed
|
||||
viewDocument.on( 'keyup', ( evt, data ) => {
|
||||
|
||||
vm.onKeyup(event)
|
||||
|
||||
//Optional data bindings for tab key
|
||||
if( (data.keyCode == 9) && viewDocument.isFocused ){
|
||||
|
||||
//Insert 5 spaces to simulate tab
|
||||
//editor.execute( 'input', { text: " " } );
|
||||
|
||||
evt.stop(); // Prevent executing the default handler.
|
||||
data.preventDefault();
|
||||
view.scrollToTheSelection();
|
||||
}
|
||||
|
||||
} );
|
||||
},
|
||||
//Used by simple editor
|
||||
onKeyup(){
|
||||
let vm = this
|
||||
vm.statusText = 'Modified'
|
||||
|
||||
this.statusText = 'Modified'
|
||||
|
||||
//Each note, save after 5 seconds, focus lost or 30 characters typed.
|
||||
clearTimeout(vm.editDebounce)
|
||||
vm.editDebounce = setTimeout(() => {
|
||||
vm.save()
|
||||
clearTimeout(this.editDebounce)
|
||||
this.editDebounce = setTimeout(() => {
|
||||
this.save()
|
||||
}, 5000)
|
||||
|
||||
//Save after 30 keystrokes
|
||||
vm.keyPressesCounter = (vm.keyPressesCounter + 1)
|
||||
if(vm.keyPressesCounter > 30){
|
||||
vm.keyPressesCounter = 0
|
||||
vm.save()
|
||||
this.keyPressesCounter = (this.keyPressesCounter + 1)
|
||||
if(this.keyPressesCounter > 30){
|
||||
this.keyPressesCounter = 0
|
||||
this.save()
|
||||
}
|
||||
},
|
||||
save(){
|
||||
return new Promise((resolve, reject) => {
|
||||
//Clear other debounced events to prevent double calling of save
|
||||
clearTimeout(this.editDebounce)
|
||||
|
||||
//Don't save note if its hash doesn't change
|
||||
if( this.lastNoteHash == this.hashString(this.noteText) ){
|
||||
resolve(false)
|
||||
return
|
||||
const currentNoteText = this.getText()
|
||||
if( this.lastNoteHash == this.hashString( currentNoteText )){
|
||||
return resolve(true)
|
||||
}
|
||||
|
||||
//If user accidentally clears note, it won't delete it
|
||||
if(currentNoteText == ''){
|
||||
this.statusText = 'Empty'
|
||||
console.log('Prevented from saving empty note.')
|
||||
return resolve(true)
|
||||
}
|
||||
|
||||
const postData = {
|
||||
'noteId':this.currentNoteId,
|
||||
'text': this.noteText,
|
||||
'fancyInput': this.fancyInput,
|
||||
'color': this.color,
|
||||
'text': currentNoteText,
|
||||
'color': JSON.stringify(this.styleObject), //Save little json color object
|
||||
'pinned': this.pinned,
|
||||
'archived':this.archived,
|
||||
}
|
||||
|
||||
let vm = this
|
||||
//Only save every 1 second
|
||||
clearTimeout(this.saveDebounce)
|
||||
this.saveDebounce = setTimeout(() => {
|
||||
//Debounce save to prevent spamming
|
||||
// clearTimeout(this.saveDebounce)
|
||||
// this.saveDebounce = setTimeout(() => {
|
||||
//Only notify user if saving - may help with debugging in the future
|
||||
vm.statusText = 'Saving'
|
||||
axios.post('/api/note/update', postData).then( response => {
|
||||
@@ -316,39 +334,44 @@
|
||||
vm.updated = Math.round((+new Date)/1000)
|
||||
|
||||
//Update last saved note hash
|
||||
vm.lastNoteHash = vm.hashString(vm.noteText)
|
||||
resolve(true)
|
||||
return
|
||||
vm.lastNoteHash = vm.hashString( currentNoteText )
|
||||
return resolve(true)
|
||||
})
|
||||
}, 300)
|
||||
// }, 300)
|
||||
})
|
||||
|
||||
},
|
||||
hashString(text){
|
||||
|
||||
var hash = 0;
|
||||
if (text.length == 0) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
//Simplified for speed
|
||||
return text.length
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
let char = text.charCodeAt(i);
|
||||
hash = ((hash<<5)-hash)+char;
|
||||
hash = hash & hash; // Convert to 32bit integer
|
||||
}
|
||||
|
||||
return hash;
|
||||
},
|
||||
close(){
|
||||
this.sizeDown = true
|
||||
|
||||
// this.loading = true
|
||||
// this.loadingMessage = 'Save and Close'
|
||||
|
||||
this.save().then( result => {
|
||||
//Save has a 300 ms timeout, if it saves animation will complete
|
||||
if(result){
|
||||
|
||||
this.sizeDown = true
|
||||
//This timeout allows animation to play before closing
|
||||
setTimeout(() => {
|
||||
this.$bus.$emit('close_active_note', this.position)
|
||||
return
|
||||
} else {
|
||||
//If save is not called, set timeout manually and then close after animation
|
||||
setTimeout(() => {
|
||||
this.$bus.$emit('close_active_note', this.position)
|
||||
}, 300)
|
||||
}
|
||||
}, 300)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -357,24 +380,20 @@
|
||||
</script>
|
||||
|
||||
<style type="text/css" scoped>
|
||||
|
||||
.no-flow {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.raw-edit {
|
||||
font-family: 'Open Sans' !important;
|
||||
font-size: 1.3rem !important;
|
||||
background: rgba(0,0,0,0);
|
||||
width: 100%;
|
||||
resize: none;
|
||||
padding: 15px;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.note-top-menu {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
height: 37px;
|
||||
border-left: 3px solid var(--border_color);
|
||||
}
|
||||
.note-top-menu .ui.basic.button {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
border-right: 1px solid var(--border_color);
|
||||
margin: 0px -2px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
/* container styles change based on mobile and number of open screens */
|
||||
@@ -386,17 +405,18 @@
|
||||
height: 100vh;
|
||||
box-shadow: 0px 0px 5px 2px rgba(140,140,140,1);
|
||||
z-index: 1001;
|
||||
/*overflow-x: scroll;*/
|
||||
}
|
||||
.loading-note {
|
||||
position: absolute;
|
||||
top: 38px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 50px;
|
||||
bottom: 0;
|
||||
}
|
||||
/* One note open, in the middle of the screen */
|
||||
.master-note-edit.position-0 {
|
||||
left: 30%;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
}
|
||||
@media only screen and (max-width: 740px) {
|
||||
@@ -424,12 +444,14 @@
|
||||
|
||||
@keyframes size-down {
|
||||
0% {
|
||||
opacity: 1;
|
||||
/*opacity: 1;*/
|
||||
/*top: 0;*/
|
||||
top: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
top: 30vh;
|
||||
/*opacity: 0;*/
|
||||
/*top: 30vh;*/
|
||||
top: 150vh;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user