Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • pleroma/pleroma-fe
  • eal/pleroma-fe
  • peterspark/pleroma-fe
  • hb2k8/pleroma-fe
  • tibike/pleroma-fe
  • obrez/pleroma-fe
  • partial/pleroma-fe
  • href/pleroma-fe
  • hakabahitoyo/pleroma-fe
  • hsgw/pleroma-fe
  • Azurolu/pleroma-fe
  • cobalto/pleroma-fe
  • qwexvf/pleroma-fe
  • boner.engineer/pleroma-fe
  • f0x/pleroma-fe
  • ataalik/pleroma-fe
  • normandy/pleroma-fe
  • Sir_Boops/pleroma-fe
  • morguldir/pleroma-fe
  • csaurus/pleroma-fe
  • kaniini/pleroma-fe
  • bhtooefr/pleroma-fe
  • andarna/pleroma-fe
  • ktsukik/pleroma-fe
  • Steph/pleroma-fe
  • andrewzah/pleroma-fe
  • lanodan/pleroma-fe
  • pea/pleroma-fe
  • fotfd/pleroma-fe
  • pizzaiolo/pleroma-fe
  • Syldexia/pleroma-fe
  • riking/pleroma-fe
  • dr1ft/pleroma-fe
  • animeirl/pleroma-fe
  • elomatreb/pleroma-fe
  • viv/pleroma-fe
  • goofy/pleroma-fe
  • hoodie/pleroma-fe
  • stolas/pleroma-fe
  • peterpan/pleroma-fe
  • Lumitas/pleroma-fe
  • Toromino/pleroma-fe
  • galen/pleroma-fe
  • scarlett/pleroma-fe
  • ButterflyOfFire/pleroma-fe
  • vaartis/pleroma-fe
  • meireikei/pleroma-fe
  • darko/pleroma-fe
  • pony/pleroma-fe
  • succfemboi/pleroma-fe
  • fadelkon/pleroma-fe
  • dgold/pleroma-fe
  • nebula_moe/pleroma-fe
  • vinzv/pleroma-fe
  • slice/pleroma-fe
  • rinpatch/pleroma-fe
  • maxf/pleroma-fe
  • raeno/pleroma-fe
  • oceanvald/pleroma-fe
  • nuklearfiziks/pleroma-fe
  • feld/pleroma-fe
  • minibikini/pleroma-fe
  • link0ff/pleroma-fe
  • qadeer/pleroma-fe
  • FloatingGhost/pleroma-fe
  • cascode/pleroma-fe
  • hikaruaikawa/pleroma-fe
  • kjwon15/pleroma-fe
  • ukrop/pleroma-fe
  • ilja/pleroma-fe
  • shadowfacts/pleroma-fe
  • edijs/pleroma-fe
  • jdorman632/pleroma-fe
  • xruselfmadex/pleroma-fe
  • futureweb/pleroma-fe
  • eugenijm/pleroma-fe
  • tae/pleroma-fe
  • Dave/pleroma-fe
  • jasper/pleroma-fe
  • Lidar/pleroma-fe
  • parallel588/pleroma-fe
  • jaredr/pleroma-fe
  • rondnelly/pleroma-fe
  • Aditoo/pleroma-fe
  • FongWan/pleroma-fe
  • mkljczk/pleroma-fe
  • nik/pleroma-fe
  • brendenbice1222/pleroma-fe
  • Satak/pleroma-fe
  • xse/pleroma-fe
  • moonman/pleroma-fe
  • Artik/pleroma-fe
  • ssuprunenko/pleroma-fe
  • uncletrunks/pleroma-fe
  • absturztaube/pleroma-fe
  • wyatt777/pleroma-fe
  • hauvophuoc/pleroma-fe
  • dashie/pleroma-fe
  • shmibs/pleroma-fe
  • Elepow/pleroma-fe
  • raven/pleroma-fe
  • buoyantair/pleroma-fe
  • Exilat_a_Tolosa/pleroma-fe
  • matrixsasuke/pleroma-fe
  • njoseph/pleroma-fe
  • ELR/pleroma-fe
  • sjw/pleroma-fe
  • davidyin/pleroma-fe
  • pescetarian/pleroma-fe
  • kphrx/pleroma-fe
  • mewmew/pleroma-fe
  • h3poteto/pleroma-fe
  • Alexpono/pleroma-fe
  • seven/pleroma-fe
  • mparvin/pleroma-fe
  • tuxcrafting/pleroma-fe
  • nekojanai/pleroma-fe
  • xenofem/pleroma-fe
  • p/pleroma-fe
  • creme/pleroma-fe
  • jp/pleroma-fe
  • Jeder/pleroma-fe
  • gensogrips/pleroma-fe
  • caskd/pleroma-fe
  • arkSong/pleroma-fe
  • Hikali/pleroma-fe
  • Duponin/pleroma-fe
  • gashapwn/pleroma-fe
  • fence/pleroma-fe
  • Duder-onomy/pleroma-fe
  • translate/pleroma-fe
  • okl/pleroma-fe
  • bird/pleroma-fe
  • NEETzsche/pleroma-fe
  • Ewoke19CMR/pleroma-fe
  • shevek/pleroma-fe
  • cutienautica/pleroma-fe
  • Nakaya/pleroma-fe
  • Snow/pleroma-fe
  • seanking/pleroma-fe
  • kkcake/pleroma-fe
  • Testacc/pleroma-fe
  • flxy/pleroma-fe
  • xerz/pleroma-fe
  • maronu/pleroma-fe
  • matildepark/pleroma-fe
  • Craftplacer/pleroma-fe
147 results
Show changes
Showing
with 442 additions and 121 deletions
<template> <template>
<div class="attachment"> <div class="attachment base03-border" :class="{[type]: true, loading}" v-show="!isEmpty">
<a class="image-attachment" v-if="nsfw" v-on:click.prevent="showNsfw()"> <a class="image-attachment" v-if="hidden" @click.prevent="toggleHidden()">
<img :key="nsfwImage" :src="nsfwImage"></img> <img :key="nsfwImage" :src="nsfwImage"/>
</a> </a>
<div class="hider" v-if="nsfw && hideNsfwLocal && !hidden">
<a href="#" @click.prevent="toggleHidden()">Hide</a>
</div>
<a class="image-attachment" v-if="type === 'image' && !nsfw" :href="attachment.url" target="_blank"><img :src="attachment.url"></img></a> <a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank">
<img class="base03-border" referrerpolicy="no-referrer" :src="attachment.large_thumb_url || attachment.url"/>
</a>
<video v-if="type === 'video' && !nsfw" :src="attachment.url" controls></video> <video class="base03" v-if="type === 'video' && !hidden" :src="attachment.url" controls loop></video>
<span v-if="type === 'unknown'">Don't know how to display this...</span> <audio v-if="type === 'audio'" :src="attachment.url" controls></audio>
<div v-if="type === 'html' && attachment.oembed" class="oembed"> <div @click.prevent="linkClicked" v-if="type === 'html' && attachment.oembed" class="oembed">
<div v-if="attachment.thumb_url" class="image"> <div v-if="attachment.thumb_url" class="image">
<img :src="attachment.thumb_url"></img> <img :src="attachment.thumb_url"/>
</div> </div>
<div class="text"> <div class="text">
<h1><a :href="attachment.url">{{attachment.oembed.title}}</a></h1> <h1><a :href="attachment.url">{{attachment.oembed.title}}</a></h1>
...@@ -28,59 +33,91 @@ ...@@ -28,59 +33,91 @@
.attachments { .attachments {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.attachment { margin-right: -0.7em;
.attachment.media-upload-container {
flex: 0 0 auto;
max-height: 300px;
max-width: 100%;
}
.attachment {
flex: 1 0 30%; flex: 1 0 30%;
display: flex; margin: 0.5em 0.7em 0.6em 0.0em;
margin: 0.2em;
align-self: flex-start; align-self: flex-start;
border-style: solid;
border-width: 1px;
border-radius: 5px;
overflow: hidden;
// fixes small gap below video
&.video {
line-height: 0;
}
&.html {
flex-basis: 90%;
width: 100%;
display: flex;
}
&.loading {
cursor: progress;
}
.hider {
position: absolute;
margin: 10px;
padding: 5px;
background: rgba(230,230,230,0.6);
font-weight: bold;
z-index: 4;
}
video { video {
max-height: 500px;
height: 100%; height: 100%;
border: 1px solid;
border-radius: 0.5em;
width: 100%; width: 100%;
z-index: 0;
} }
img.media-upload { audio {
width: 100%; width: 100%;
height: 100%;
flex: 1;
border: 1px solid;
border-radius: 0.5em;
} }
img.media-upload {
margin-bottom: -2px;
max-height: 300px;
max-width: 100%;
}
.oembed { .oembed {
width: 100%;
margin-right: 15px;
display: flex;
img { img {
width: 100%; width: 100%;
height: 100%;
} }
}
.oembed {
border: 1px solid rgba(0, 0, 0, 0.14);
width: 100%;
display: flex;
.image { .image {
flex: 1; flex: 1;
img { img {
border: 0px; border: 0px;
border-radius: 0; border-radius: 5px;
height: 100%;
object-fit: cover;
} }
} }
.text { .text {
flex: 2; flex: 2;
margin: 8px; margin: 8px;
word-break: break-all;
h1 { h1 {
font-size: 14px; font-size: 14px;
margin: 0px; margin: 0px;
a {
color: black;
}
} }
} }
} }
...@@ -90,11 +127,10 @@ ...@@ -90,11 +127,10 @@
flex: 1; flex: 1;
img { img {
object-fit: contain;
width: 100%; width: 100%;
flex: 1; height: 100%; /* If this isn't here, chrome will stretch the images */
border: 1px solid; max-height: 500px;
border-radius: 0.5em;
width: 100%;
} }
} }
} }
......
const chat = {
data () {
return {
currentMessage: '',
channel: null
}
},
computed: {
messages () {
return this.$store.state.chat.messages
}
},
methods: {
submit (message) {
this.$store.state.chat.channel.push('new_msg', {text: message}, 10000)
this.currentMessage = ''
}
}
}
export default chat
<template>
<div class="chat-panel panel panel-default">
<div class="panel-heading timeline-heading base02-background base04">
<div class="title">
{{$t('chat.title')}}
</div>
</div>
<div class="panel-body base01-background">
<div class="chat-window">
<div class="chat-message" v-for="message in messages" :key="message.id">
<span class="chat-avatar">
<img :src="message.author.avatar" />
{{message.author.username}}:
</span>
<span class="chat-text">
{{message.text}}
</span>
</div>
</div>
<div class="chat-input">
<form @submit.prevent="submit(currentMessage)">
<input v-model="currentMessage" type="text" >
</form>
</div>
</div>
</div>
</template>
<script src="./chat.js"></script>
<style lang="scss">
.chat-window {
max-height: 80vh;
overflow-y: auto;
overflow-x: hidden;
}
.chat-message {
padding: 0.2em 0.5em
}
.chat-avatar {
img {
height: 32px;
width: 32px;
border-radius: 5px;
margin-right: 0.5em;
}
}
.chat-input {
display: flex;
form {
flex: auto;
input {
margin: 0.5em;
width: fill-available;
}
}
}
</style>
import Conversation from '../conversation/conversation.vue'
import { find, toInteger } from 'lodash'
const conversationPage = {
components: {
Conversation
},
computed: {
statusoid () {
const id = toInteger(this.$route.params.id)
const statuses = this.$store.state.statuses.allStatuses
const status = find(statuses, {id})
return status
}
}
}
export default conversationPage
<template>
<conversation :collapsable="false" :statusoid="statusoid"></conversation>
</template>
<script src="./conversation-page.js"></script>
import { reduce, filter, sortBy } from 'lodash'
import { statusType } from '../../modules/statuses.js'
import Status from '../status/status.vue'
const sortAndFilterConversation = (conversation) => {
conversation = filter(conversation, (status) => statusType(status) !== 'retweet')
return sortBy(conversation, 'id')
}
const conversation = {
data () {
return {
highlight: null
}
},
props: [
'statusoid',
'collapsable'
],
computed: {
status () { return this.statusoid },
conversation () {
if (!this.status) {
return false
}
const conversationId = this.status.statusnet_conversation_id
const statuses = this.$store.state.statuses.allStatuses
const conversation = filter(statuses, { statusnet_conversation_id: conversationId })
return sortAndFilterConversation(conversation)
},
replies () {
let i = 1
return reduce(this.conversation, (result, {id, in_reply_to_status_id}) => {
const irid = Number(in_reply_to_status_id)
if (irid) {
result[irid] = result[irid] || []
result[irid].push({
name: `#${i}`,
id: id
})
}
i++
return result
}, {})
}
},
components: {
Status
},
created () {
this.fetchConversation()
},
watch: {
'$route': 'fetchConversation'
},
methods: {
fetchConversation () {
if (this.status) {
const conversationId = this.status.statusnet_conversation_id
this.$store.state.api.backendInteractor.fetchConversation({id: conversationId})
.then((statuses) => this.$store.dispatch('addNewStatuses', { statuses }))
.then(() => this.setHighlight(this.statusoid.id))
} else {
const id = this.$route.params.id
this.$store.state.api.backendInteractor.fetchStatus({id})
.then((status) => this.$store.dispatch('addNewStatuses', { statuses: [status] }))
.then(() => this.fetchConversation())
}
},
getReplies (id) {
id = Number(id)
return this.replies[id] || []
},
focused (id) {
if (this.statusoid.retweeted_status) {
return (id === this.statusoid.retweeted_status.id)
} else {
return (id === this.statusoid.id)
}
},
setHighlight (id) {
this.highlight = Number(id)
}
}
}
export default conversation
<template>
<div class="timeline panel panel-default">
<div class="panel-heading base02-background base04 base03-border conversation-heading">
{{ $t('timeline.conversation') }}
<span v-if="collapsable" style="float:right;">
<small><a href="#" @click.prevent="$emit('toggleExpanded')">Collapse</a></small>
</span>
</div>
<div class="panel-body">
<div class="timeline">
<status v-for="status in conversation" @goto="setHighlight" :key="status.id" :statusoid="status" :expandable='false' :focused="focused(status.id)" :inConversation='true' :highlight="highlight" :replies="getReplies(status.id)"></status>
</div>
</div>
</div>
</template>
<script src="./conversation.js"></script>
const DeleteButton = {
props: [ 'status' ],
methods: {
deleteStatus () {
const confirmed = window.confirm('Do you really want to delete this status?')
if (confirmed) {
this.$store.dispatch('deleteStatus', { id: this.status.id })
}
}
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
canDelete () { return this.currentUser.rights.delete_others_notice || this.status.user.id === this.currentUser.id }
}
}
export default DeleteButton
<template>
<div v-if="canDelete">
<a href="#" v-on:click.prevent="deleteStatus()">
<i class='base09 icon-cancel delete-status'></i>
</a>
</div>
</template>
<script src="./delete_button.js" ></script>
<style lang='scss'>
@import '../../_variables.scss';
.icon-cancel,.delete-status {
cursor: pointer;
&:hover {
color: $red;
}
}
</style>
const FavoriteButton = { const FavoriteButton = {
props: [ 'status' ], props: ['status'],
data () {
return {
animated: false
}
},
methods: { methods: {
favorite () { favorite () {
if (!this.status.favorited) { if (!this.status.favorited) {
...@@ -7,13 +12,18 @@ const FavoriteButton = { ...@@ -7,13 +12,18 @@ const FavoriteButton = {
} else { } else {
this.$store.dispatch('unfavorite', {id: this.status.id}) this.$store.dispatch('unfavorite', {id: this.status.id})
} }
this.animated = true
setTimeout(() => {
this.animated = false
}, 500)
} }
}, },
computed: { computed: {
classes () { classes () {
return { return {
'icon-star-empty': !this.status.favorited, 'icon-star-empty': !this.status.favorited,
'icon-star': this.status.favorited 'icon-star': this.status.favorited,
'animate-spin': this.animated
} }
} }
} }
......
<template> <template>
<div> <div>
<i :class='classes' class='favorite-button fa' v-on:click.prevent='favorite()'></i> <i :class='classes' class='favorite-button base09' @click.prevent='favorite()'/>
<span v-if='status.fave_num > 0'>{{status.fave_num}}</span> <span v-if='status.fave_num > 0'>{{status.fave_num}}</span>
</div> </div>
</template> </template>
...@@ -8,14 +8,15 @@ ...@@ -8,14 +8,15 @@
<script src="./favorite_button.js" ></script> <script src="./favorite_button.js" ></script>
<style lang='scss'> <style lang='scss'>
@import '../../_variables.scss';
.favorite-button { .favorite-button {
cursor: pointer; cursor: pointer;
animation-duration: 0.6s;
&:hover { &:hover {
color: $main-color; color: orange;
} }
} }
.icon-star { .favorite-button.icon-star {
color: $main-color; color: orange;
} }
</style> </style>
<template> <template>
<div class="timeline panel panel-default"> <Timeline :title="$t('nav.timeline')" v-bind:timeline="timeline" v-bind:timeline-name="'friends'"/>
<div class="panel-heading">Friends Timeline</div>
<div class="panel-body">
<Timeline v-bind:timeline="timeline" v-bind:timeline-name="'friends'"/>
</div>
</div>
</template> </template>
<script src="./friends_timeline.js"></script> <script src="./friends_timeline.js"></script>
export default {
name: 'hello',
data () {
return {
msg: 'Welcome to Your Vue.js app'
}
}
}
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
<li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
<br>
<li><a href="http://vuejs-templates.github.io/webpack/" target="_blank">Docs for This template</a></li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
<li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
<li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
</ul>
</div>
</template>
<script src='./Hello.js'></script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
const LoginForm = { const LoginForm = {
data: () => ({ data: () => ({
user: {} user: {},
authError: false
}), }),
computed: { computed: {
loggingIn () { return this.$store.state.users.loggingIn } loggingIn () { return this.$store.state.users.loggingIn },
registrationOpen () { return this.$store.state.config.registrationOpen }
}, },
methods: { methods: {
submit () { submit () {
this.$store.dispatch('loginUser', this.user).then(() => { this.$store.dispatch('loginUser', this.user).then(
this.$router.push('/main/friends') () => {},
}) (error) => {
this.authError = error
this.user.username = ''
this.user.password = ''
}
)
} }
} }
} }
......
<template> <template>
<div class="login panel panel-default"> <div class="login panel panel-default base00-background">
<!-- Default panel contents --> <!-- Default panel contents -->
<div class="panel-heading"> <div class="panel-heading base02-background base04">
Log in {{$t('login.login')}}
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form v-on:submit.prevent='submit(user)'> <form v-on:submit.prevent='submit(user)' class='login-form'>
<div class='form-group'> <div class='form-group'>
<label for='username'>Username</label> <label for='username'>{{$t('login.username')}}</label>
<input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'> <input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'>
</div> </div>
<div class='form-group'> <div class='form-group'>
<label for='password'>Password</label> <label for='password'>{{$t('login.password')}}</label>
<input :disabled="loggingIn" v-model='user.password' class='form-control' id='password' type='password'> <input :disabled="loggingIn" v-model='user.password' class='form-control' id='password' type='password'>
</div> </div>
<div class='form-group'> <div class='form-group'>
<button :disabled="loggingIn" type='submit' class='btn btn-default'>Submit</button> <div class='login-bottom'>
<div><router-link :to="{name: 'registration'}" v-if='registrationOpen' class='register'>{{$t('login.register')}}</router-link></div>
<button :disabled="loggingIn" type='submit' class='btn btn-default base04 base02-background'>{{$t('login.login')}}</button>
</div>
</div>
<div v-if="authError" class='form-group'>
<div class='error base05'>{{authError}}</div>
</div> </div>
</form> </form>
</div> </div>
...@@ -23,3 +29,42 @@ ...@@ -23,3 +29,42 @@
</template> </template>
<script src="./login_form.js" ></script> <script src="./login_form.js" ></script>
<style lang="scss">
.login-form {
input {
border-width: 1px;
border-style: solid;
border-color: silver;
border-radius: 5px;
padding: 0.1em 0.2em 0.2em 0.2em;
}
.btn {
min-height: 28px;
width: 10em;
}
.error {
border-radius: 5px;
text-align: center;
background-color: rgba(255, 48, 16, 0.65);
min-height: 28px;
line-height: 28px;
}
.register {
flex: 1 1;
}
.login-bottom {
margin-top: 1.0em;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
}
</style>
...@@ -3,12 +3,22 @@ import statusPosterService from '../../services/status_poster/status_poster.serv ...@@ -3,12 +3,22 @@ import statusPosterService from '../../services/status_poster/status_poster.serv
const mediaUpload = { const mediaUpload = {
mounted () { mounted () {
const store = this.$store
const input = this.$el.querySelector('input') const input = this.$el.querySelector('input')
const self = this
input.addEventListener('change', ({target}) => { input.addEventListener('change', ({target}) => {
const file = target.files[0] const file = target.files[0]
this.uploadFile(file)
})
},
data () {
return {
uploading: false
}
},
methods: {
uploadFile (file) {
const self = this
const store = this.$store
const formData = new FormData() const formData = new FormData()
formData.append('media', file) formData.append('media', file)
...@@ -19,15 +29,34 @@ const mediaUpload = { ...@@ -19,15 +29,34 @@ const mediaUpload = {
.then((fileData) => { .then((fileData) => {
self.$emit('uploaded', fileData) self.$emit('uploaded', fileData)
self.uploading = false self.uploading = false
}, (error) => { }, (error) => { // eslint-disable-line handle-callback-err
self.$emit('upload-failed') self.$emit('upload-failed')
self.uploading = false self.uploading = false
}) })
}) },
fileDrop (e) {
if (e.dataTransfer.files.length > 0) {
e.preventDefault() // allow dropping text like before
this.uploadFile(e.dataTransfer.files[0])
}
},
fileDrag (e) {
let types = e.dataTransfer.types
if (types.contains('Files')) {
e.dataTransfer.dropEffect = 'copy'
} else {
e.dataTransfer.dropEffect = 'none'
}
}
}, },
data () { props: [
return { 'dropFiles'
uploading: false ],
watch: {
'dropFiles': function (fileInfos) {
if (!this.uploading) {
this.uploadFile(fileInfos[0])
}
} }
} }
} }
......
<template> <template>
<div class="media-upload"> <div class="media-upload" @drop.prevent @dragover.prevent="fileDrag" @drop="fileDrop">
<label class="btn btn-default"> <label class="btn btn-default">
<i class="fa icon-spin4 animate-spin" v-if="uploading"></i> <i class="base09 icon-spin4 animate-spin" v-if="uploading"></i>
<i class="fa icon-upload" v-if="!uploading"></i> <i class="base09 icon-upload" v-if="!uploading"></i>
<input type=file style="position: fixed; top: -100em"></input> <input type=file style="position: fixed; top: -100em"></input>
</label> </label>
</div> </div>
...@@ -15,4 +15,8 @@ ...@@ -15,4 +15,8 @@
font-size: 26px; font-size: 26px;
flex: 1; flex: 1;
} }
.icon-upload {
cursor: pointer;
}
</style> </style>