@silexlabs/silex-dashboard
Version:
Dashboard for Silex v3
360 lines (337 loc) • 15.8 kB
HTML
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/css/connectors-c1d5f4c520a9a86d99b7201d30a8fe25a5779b7b2373b73262868f446fe3f855.css" />
<!-- font google -->
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;700&display=swap" rel="stylesheet">
<style>
.before-js > * {
visibility: hidden;
opacity: 0;
transition: opacity .5s ease;
}
.before-js[data-gjs-type] > *, /* This is only inside the editor, .before-js needs to be on the body */
.after-js > * {
visibility: visible;
opacity: 1;
}
.before-js:before {
content: 'Loading';
position: absolute;
top: 49%;
left: 49%;
}
.before-js[data-gjs-type]:before, /* This is only inside the editor, .before-js needs to be on the body */
.after-js:before {
content: none;
}
/*BTNS*/
.button, .pointer {
cursor: pointer}
.button{
min-width:110px;
}
details {
max-height: 2em;
display: block;
overflow: hidden;
transition: max-height .75s ease;
}
details[open] {
max-height: 40em;
}
/*BTNS*/
a {
text-decoration: none;
color:#8873FE;
}
a:hover {
text-decoration: underline;
}
.uppercase {
text-transform: uppercase;
}
.underline:hover{
text-decoration: underline;
text-decoration-thickness: from-font;
text-underline-position: under;
}
/*footer position*/
.main-min-height {
min-height: calc(100vh - 560px);
}
/*footer position*/
/*label*/
::placeholder {
color: #8873FE;
}
input:focus {
border: 2px solid #9977FE;
background-color:#ffffff;
}
:focus {
outline: none;
}
/*label*/
.skeleton-anim:after {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
content: "";
background:
linear-gradient(0.25turn, transparent, rgba(255,255,255,.75), transparent),
linear-gradient(transparent, transparent),
radial-gradient(38px circle at 19px 19px, transparent 50%, transparent 51%),
linear-gradient(transparent, transparent);
background-repeat: no-repeat;
background-size: 315px 250px, 315px 180px, 100px 100px, 225px 30px;
background-position: -315px 0, 0 0, 0px 190px, 50px 195px;
animation: loading 1.5s infinite;
}
@keyframes loading {
to {
background-position: 200% 0, 0 0, 0 190px, 50px 195px;
}
}
/*FX ANIMATIONS*/
/*scale-round-inside_pour-BTN*/
.fx-scale-round {
position:relative;
z-index: 10;
overflow: hidden;
}
.fx-scale-round::after {
content: "";
background: #ffffff;
position: absolute;
z-index: -1;
border-radius: 50%;
left: -50%;
right: -50%;
top: -100%;
bottom: -100%;
transform: scale(0, 0);
transform-origin: center bottom;
transition: all 0.3s ease-out;
}
.fx-scale-round:hover {
transform-origin: center bottom;
transform: scale(1.1);
transition: transform 0.2s cubic-bezier(0, -0.530, 0.405, 2.8);
}
.fx-scale-round:hover::after {
transform: scale(1, 1);
transition: transform 0.2s cubic-bezier(0, -0.530, 0.405, 2.8);
}
/*scale-round-inside_pour-BTN*/
/*scale*/
.fx-scale:hover {
transform-origin: center bottom;
transform: scale(1.1);
transition: transform 0.2s cubic-bezier(0, -0.530, 0.405, 2.8);
}
/*flash*/
.fx-flash:hover {
animation: flash-in .25s ;
}
/*flash-in animation*/
@keyframes flash-in{
0% {
opacity:.25;
}
100% {
opacity:1;
}
}
/*flash-in animation*/
/*FX ANIMATIONS*/
</style>
<script src="/js/vue.global.prod.js"></script>
<script src="/js/main.js"></script>
<script type="module">
const CONNECTORS_PATH = ''
const { createApp } = Vue;
const { api, constants, types } = silex;
const {
ConnectorType,
} = types
const {
setServerUrl,
getUser,
logout,
websiteDelete,
websiteDuplicate,
websiteList,
websiteCreate,
websiteMetaWrite,
connectorList,
} = api
function toSafeId(name) {
return name.replace(/[/\\?%*:|"<>]/g, '_')
}
const App = {
data() {
return {
websites: [],
connectors: [],
newWebsiteName: '',
showCreationForm: false,
error: null,
message: null,
loggedIn: false,
loading: true,
storage: null,
user: null,
showMenu: false,
empty: false,
rgpdFeedback: false,
rgpdNL: false,
}
},
mounted() {
this.init()
},
methods: {
async init() {
try {
// Init Silex server path
// Go up one level because of the language prefix
setServerUrl(window.location.origin)
await this.getConnectors()
this.setRgpd('nl', this.getRgpd('nl') ?? true)
this.setRgpd('feedback', this.getRgpd('feedback') ?? true)
} catch (error) {
console.error(error)
this.loading = false
this.error = `Failed to start dashboard - ${error.message}`
this.message = ''
}
},
getIcon(connector) {
return decodeURIComponent(connector.icon.split(',').slice(1).join(','))
},
getHref(connector) {
if(connector.isLoggedIn) return '/'
if(connector.oauthUrl) return connector.oauthUrl
return '/api/connector/login/?type=STORAGE&connectorId=' + connector.connectorId
},
getConnectorStyle(connector) {
return {
backgroundImage: `url(${connector.icon})`,
//color: connector.color,
//backgroundColor: connector.background
}
},
async getConnectors() {
try {
this.loading = true
const connectors = await connectorList({ type: ConnectorType.STORAGE })
this.connectors = connectors
// this.connectors = [{"connectorId":"gitlab","type":"STORAGE","displayName":"GitLab.com","icon":"/assets/gitlab.png","disableLogout":false,"isLoggedIn":true,"oauthUrl":"https://gitlab.com/oauth/authorize?client_id=55cb55ab5fd12ab93883378513212d0c85833ef1f4084375f973618e938af107&redirect_uri=https%3A%2F%2Fv3.silex.me%2Fapi%2Fconnector%2Flogin%2Fcallback%3FconnectorId%3Dgitlab%26type%3DSTORAGE&response_type=code&state=6z1oajr7s9q75vl47i5065&scope=api&code_challenge=APGn3qQ0O5zDzkLelHIMtjKMo2WmFJj4XxFqAd3bQJ4&code_challenge_method=S256","color":"#2B1B63","background":"rgba(252, 109, 38, 0.2)"},{"connectorId":"gitlab2","type":"STORAGE","displayName":"Framagit","icon":"/assets/gitlab.png","disableLogout":false,"isLoggedIn":false,"oauthUrl":"https://framagit.org/oauth/authorize?client_id=13484ab1c802362f0292cbf637fd348a3bca46dfb2c2466a361ab89a799a8925&redirect_uri=https%3A%2F%2Fv3.silex.me%2Fapi%2Fconnector%2Flogin%2Fcallback%3FconnectorId%3Dgitlab2%26type%3DSTORAGE&response_type=code&state=1mzpmxpuymoy2ss07wv01f&scope=api&code_challenge=dkwe8iS7dOH8Cmm5YVIv39huEkLCJ1xx276h1jok7oQ&code_challenge_method=S256","color":"#2B1B63","background":"rgba(252, 109, 38, 0.2)"},{"connectorId":"ftp","type":"STORAGE","displayName":"Ftp","icon":"/assets/ftp.png","disableLogout":false,"isLoggedIn":false,"oauthUrl":null,"color":"#ffffff","background":"#0066CC"}]
this.loading = false
} catch (error) {
this.loading = false
console.error(error)
this.error = ` - ${error.message}`
this.message = ''
}
},
openLogin() {},
// name: "nl" | "feedback", value: Boolean
setRgpd(name, value) {
const errorDiv = document.getElementById('errorDiv');
console.log('set RGPD', {name, value, errorDiv})
if (errorDiv) errorDiv.textContent = ''; // Clear previous errors
if(name === 'feedback') this.rgpdFeedback = value.toString()
if(name === 'nl') this.rgpdNL = value.toString()
if (typeof Storage !== 'undefined') {
try {
localStorage.setItem(name, JSON.stringify(value));
console.log(`RGPD setting saved: ${name} = ${value}`);
} catch (e) {
if (errorDiv) {
errorDiv.textContent = 'Error saving to localStorage: ' + e.message;
}
console.error('Error saving to localStorage', e);
}
} else {
const warning = 'Local storage is not supported in this browser.';
if (errorDiv) {
errorDiv.textContent = warning;
}
console.warn(warning);
}
},
getRgpd(name) {
const errorDiv = document.getElementById('errorDiv');
if (errorDiv) errorDiv.textContent = ''; // Clear previous errors
console.log('getRgpd', name)
if (typeof Storage !== 'undefined') {
try {
const value = localStorage.getItem(name);
return value !== null ? JSON.parse(value) : null; // Return parsed value or null if not found
} catch (e) {
if (errorDiv) {
errorDiv.textContent = 'Error retrieving from localStorage: ' + e.message;
}
console.error('Error retrieving from localStorage', e);
return null;
}
} else {
const warning = 'Local storage is not supported in this browser.';
if (errorDiv) {
errorDiv.textContent = warning;
}
console.warn(warning);
return null;
}
},
},
};
// Prepare elements for vue
document.querySelectorAll('[v-text], [v-html]')
.forEach(el => el.innerText = '')
document.querySelectorAll('[data-remove-href]')
.forEach(el => {
el.removeAttribute('href')
el.removeAttribute('data-remove-href')
})
// Create the app
const app = createApp(App);
// Mount the app
app.mount('.app');
// Remove loading
setTimeout(() => {
document.querySelector('.before-js').classList.add('after-js')
}, 100)
</script>
<title>Silex Dashboard</title>
<link rel="icon" href="/assets/favicon-32x32.png" />
<meta name="og:title" property="og:title" content="Silex Dashboard"/>
<link href="https://fonts.googleapis.com" rel="preconnect" ><link href="https://fonts.gstatic.com" rel="preconnect" crossorigin ><link href="https://fonts.googleapis.com/css?family=Ubuntu&display=swap" rel="stylesheet" ></head>
<body id="i2hcfw" class="body app before-js"><A id="ixzhcr" href="/" class="button button-bar__item--secondary">< Back</A><div id="imawg3" class="bg-silex-purpel"><div id="imgx81" style="min-height:100vh;display:flex;justify-content:center;align-items:center;flex-direction:column;" class=""><div id="iikf0s" class="box box_login"><div id="ie0dxn" class="text-centered"><img id="ior0hl" src="/assets/logo-silex.svg"/><p id="it2175" style="margin:15px 0px 0px 0px;font-size:1rem;" class="subtitle-16">Please login to continue</p></div><h3 id="iqc1xf" style="display:none;" class="margin-top">Recommended and free</h3><div id="in62y2"><div id="isqe61" class="full-width margin-30" v-for="(connector, index) in connectors.slice(0, 1)"><a id="i44y9w" href="https://" class="connector__card" :href="getHref(connector)" data-remove-href="true"><div id="io3lid" class="button-bar__item__icon" :style="getConnectorStyle(connector)"></div><div id="i87asw" class="connector__description" v-text="connector.displayName">Login with <span href="" id="i0tt68">Name</span><br/></div></a></div><div id="i9fpn7" class="rgpd-checks"><input type="checkbox" id="feedback-check" name="feedback-check" checked class="rgpd-checks__check" v-on:change="(event) => setRgpd('feedback', event.target.checked)" v-model="rgpdFeedback"></input><label id="iv7hwn" for="feedback-check" class="">Allow contact for debugging and feedback</label></div><div id="iahvhn" class="rgpd-checks"><input type="checkbox" name="nl-check" id="nl-check" checked class="rgpd-checks__check" v-on:change="(event) => setRgpd('nl', event.target.checked)" v-model="rgpdNL"></input><label for="nl-check" id="isjk6j" class="">Subscribe to our newsletter</label></div><div id="errorDiv"></div></div><DETAILS id="ihn6fj"><summary id="i8w75b" class="margin-30">Advanced users</summary><div id="ibi9qh" class="full-width" v-for="(connector, index) in connectors.slice(1)"><a href="https://" class="connector__card" :href="getHref(connector)" data-remove-href="true"><div class="button-bar__item__icon" :style="getConnectorStyle(connector)"></div><div class="connector__description" v-text="connector.displayName">Login with <span href="">Name</span><br/></div></a></div></DETAILS><div id="i3cney" class="button-bar"><a id="iacshy" class="button big-button connector__card" v-if="!loading" :key="index" :style="{ backgroundColor: connector.background, color: connector.color }" v-for="(connector, index) in connectors" v-on-click="openLogin(connector)"><div id="iiwn36"><div class="button-bar__item__icon" :style="`background: url('${connector.icon}'); background-repeat: no-repeat; background-size: contain;`"></div><div id="if4gvb" class="" v-text="connector.displayName">Name<br/></div></div><div id="isndui">This connector is about blablabla<br/></div></a></div><div id="ijflxq" style="font-size:0.85rem;text-align:left;margin:30px 0px 0px 0px;" class="text-centered">Do you need help? Check <a href="https://docs.silex.me/en/user/login" target="_blank">the documentation</a>. <br><br> By logging in, you agree to the <a href="https://docs.silex.me/en/terms" target="_blank">terms of use</a> and the <a href="https://docs.silex.me/en/security" target="_blank">privacy policy</a>.</div></div><div id="i9msnk" style="padding:10px;display:inline;" class="text-white top-space-20" v-if="error" v-text="message" :test="message">Insert your text here</div><div id="i6akll" style="padding:10px;display:inline;" class="button button--tertiary text-centered" v-if="error" v-on:click="logout()">Logout</div></div></div><FOOTER class="footer">
<div id="iprzeh" style="min-height:100px;" class="footer__column"><h3 href="" class="footer__item">Social & community</h3>
<a href="https://www.silex.me/" class="footer__item" target="_blank">About Silex, official website</a>
<a href="mailto:contact+silex-dashboard-footer@silex.me" class="footer__item" target="">Email the team</a>
<a href="https://short.silex.me/sponsors" class="footer__item" target="_blank">Sponsors</a>
<a href="https://short.silex.me/donate" class="footer__item" target="">Donate</a>
<a href="https://short.silex.me/community" class="footer__item" target="_blank">Community forum</a>
<a href="https://news.silex.me/forms/nfrm_weLJnLY5" class="footer__item" target="_blank">Newsletter</a>
<a href="https://events.silex.me/" class="footer__item" target="_blank">Meetups/ Events</a>
<a href="https://short.silex.me/mastodon" class="footer__item" target="_blank">Mastodon</a>
<a href="https://short.silex.me/lemmy" class="footer__item" target="_blank">Lemmy</a></div>
<div id="iprzeh" style="min-height:100px;" class="footer__column"><h3 href="" class="footer__item">Resources</h3>
<a href="https://short.silex.me/code" class="footer__item" target="_blank">Source code</a>
<a href="http://docs.silex.me/" class="footer__item" target="_blank">Documentation</a>
<a href="https://video.silex.me/my-library/video-playlists" class="footer__item" target="_blank">Videos</a>
<a href="https://short.silex.me/roadmap" class="footer__item" target="_blank">Roadmap</a>
<a href="https://short.silex.me/contribute" class="footer__item" target="_blank">Contribute</a></div>
<div id="iprzeh" style="min-height:100px;" class="footer__column"><h3 href="" class="footer__item">Articles and reviews</h3>
<a href="https://short.silex.me/alternatives" class="footer__item" target="_blank">Silex alternatives</a>
<a href="https://short.silex.me/reviews" class="footer__item" target="_blank">Silex reviews</a>
<a href="https://short.silex.me/press" class="footer__item" target="_blank">Silex in the press</a></div></FOOTER></body>
</html>