Skip to content

Commit 939be8a

Browse files
committed
added first framework for the dev-studio
1 parent 9be3e30 commit 939be8a

File tree

3 files changed

+327
-5
lines changed

3 files changed

+327
-5
lines changed

dist/breinify-dev-studio.js

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,159 @@
22

33
(function () {
44

5+
class BreinifyDevConsole extends HTMLElement {
6+
constructor() {
7+
super();
8+
9+
this.attachShadow({mode: 'open'});
10+
11+
// SVG brein icon (16x16)
12+
this.isVisible = true;
13+
14+
this.render();
15+
this.hookConsole();
16+
}
17+
18+
render() {
19+
this.shadowRoot.innerHTML = `
20+
<style>
21+
:host { all: initial; }
22+
div.title { display: flex; flex-flow: row; font-weight: bold; font-size: 14px; line-height: 14px; padding: 6px 10px; }
23+
button.close-btn { background: transparent; border: none; color: #ccc; font-size: 18px; cursor: pointer; padding: 0 6px; user-select: none; }
24+
button.close-btn:hover { color: white; }
25+
#panel { position: fixed; bottom: 0; right: 0; width: 400px; height: 80vh; max-height: 1000px; font-family: monospace; font-size: 12px; color: #fff; background: #1e1e1e; box-shadow: 0 0 10px rgba(0,0,0,0.5); border-top-left-radius: 6px; display: flex; flex-direction: column; z-index: 999999; transition: transform 0.2s ease-out, opacity 0.2s ease-out; overflow: hidden; }
26+
header { background: #111; padding: 6px 10px; display: flex; align-items: center; user-select: none; border-top-left-radius: 6px; color: #eee; }
27+
header > .tabs { display: flex; gap: 10px; flex-grow: 1; }
28+
header button.tab { background: transparent; border: none; color: #ccc; cursor: pointer; padding: 4px 8px; font-size: 12px; border-bottom: 2px solid transparent; transition: border-color 0.15s ease; }
29+
header button.tab.active { border-bottom-color: #fff; color: white; }
30+
header button.tab:hover:not(.active) { color: #fff; }
31+
#log-container { flex-grow: 1; background: #1e1e1e; padding: 10px; overflow-y: auto; white-space: pre-wrap; word-break: break-word; color: white; }
32+
#toggle-button { position: fixed; bottom: 10px; right: 10px; width: 32px; height: 32px; background: #333; border-radius: 50%; align-items: center; justify-content: center; cursor: pointer; z-index: 1000000; box-shadow: 0 0 5px rgba(0,0,0,0.3); transition: opacity 0.2s ease-out; display: none; }
33+
#toggle-button:hover svg path { fill: #ccc; }
34+
::-webkit-scrollbar { width: 6px; }
35+
::-webkit-scrollbar-thumb { background: #888; border-radius: 3px; }
36+
::-webkit-scrollbar-thumb:hover { background: #555; }
37+
</style>
38+
<div id="panel">
39+
<div class="title">
40+
<div style="flex-grow: 1; align-content: center;">Breinify DevStudio</div>
41+
<button class="close-btn" title="Hide Breinify DevStudio">&#x2715;</button>
42+
</div>
43+
<header>
44+
<div class="tabs">
45+
<button class="tab active" data-tab="console">Console</button>
46+
<button class="tab" data-tab="info">Info</button>
47+
</div>
48+
</header>
49+
<div id="log-container"></div>
50+
</div>
51+
<div id="toggle-button" title="Show Breinify DevStudio" role="button" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" fill="white" width="16" height="16" viewBox="0 0 24 24"><path d="M12 2C8.1 2 6 4.4 6 7v5c0 .5-.2.9-.5 1.3-.3.4-.5.9-.5 1.4v.3c.1.6.5 1.1 1 1.5.5.4.8 1 .8 1.6 0 .6.2 1.1.5 1.5s.7.7 1.2.9V21c0 .6.4 1 1 1s1-.4 1-1v-1h2v1c0 .6.4 1 1 1s1-.4 1-1v-1.5c.5-.2.9-.5 1.2-.9s.5-.9.5-1.5c0-.6.3-1.2.8-1.6.5-.4.9-.9 1-1.5v-.3c0-.5-.2-1-.5-1.4-.3-.4-.5-.9-.5-1.3V7c0-2.6-2.1-5-6-5z"/></svg></div>`;
52+
53+
this.logContainer = this.shadowRoot.querySelector('#log-container');
54+
this.toggleButton = this.shadowRoot.querySelector('#toggle-button');
55+
this.panel = this.shadowRoot.querySelector('#panel');
56+
this.closeBtn = this.shadowRoot.querySelector('button.close-btn');
57+
this.tabs = this.shadowRoot.querySelectorAll('button.tab');
58+
59+
this.closeBtn.addEventListener('click', () => this.toggleConsole());
60+
this.toggleButton.addEventListener('click', () => this.toggleConsole());
61+
62+
this.tabs.forEach(tab => tab.addEventListener('click', e => this.switchTab(e)));
63+
}
64+
65+
toggleConsole() {
66+
this.isVisible = !this.isVisible;
67+
68+
if (this.isVisible) {
69+
this.panel.style.transform = 'translateY(0)';
70+
this.panel.style.opacity = '1';
71+
this.toggleButton.style.display = 'none';
72+
} else {
73+
this.panel.style.transform = 'translateY(100%)';
74+
this.panel.style.opacity = '0';
75+
this.toggleButton.style.display = 'flex';
76+
}
77+
}
78+
79+
switchTab(event) {
80+
const selectedTab = event.target.dataset.tab;
81+
this.tabs.forEach(tab => {
82+
tab.classList.toggle('active', tab.dataset.tab === selectedTab);
83+
});
84+
85+
// For now, just clear or keep logs on console tab, and show placeholder on info tab
86+
if (selectedTab === 'console') {
87+
this.logContainer.style.display = 'block';
88+
if (this.infoDiv) this.infoDiv.style.display = 'none';
89+
} else if (selectedTab === 'info') {
90+
91+
// Lazy create info div
92+
if (!this.infoDiv) {
93+
this.infoDiv = document.createElement('div');
94+
this.infoDiv.textContent = 'Information tab content goes here.';
95+
this.infoDiv.style.padding = '10px';
96+
this.infoDiv.style.color = '#ddd';
97+
this.infoDiv.style.height = '100%';
98+
this.infoDiv.style.overflowY = 'auto';
99+
this.logContainer.after(this.infoDiv);
100+
}
101+
102+
this.logContainer.style.display = 'none';
103+
this.infoDiv.style.display = 'block';
104+
}
105+
}
106+
107+
hookConsole() {
108+
['log', 'warn', 'error', 'info'].forEach(method => {
109+
const original = console[method];
110+
console[method] = (...args) => {
111+
const msg = args.map(arg => {
112+
try {
113+
if (typeof arg === 'object' && arg !== null) {
114+
return JSON.stringify(arg, null, 2);
115+
}
116+
return String(arg);
117+
} catch {
118+
return '[object]';
119+
}
120+
}).join(' ');
121+
122+
const entry = document.createElement('div');
123+
entry.textContent = `[${method.toUpperCase()}] ${msg}`;
124+
entry.style.color = {
125+
log: 'white',
126+
warn: 'orange',
127+
error: 'red',
128+
info: 'lightblue'
129+
}[method];
130+
131+
if (this.logContainer) {
132+
this.logContainer.appendChild(entry);
133+
this.logContainer.scrollTop = this.logContainer.scrollHeight;
134+
}
135+
136+
original.apply(console, args);
137+
};
138+
});
139+
}
140+
}
141+
5142
const DevStudio = {
143+
devStudio: null,
6144

7145
init: function () {
8-
if (Breinify.UTL.internal.isDevMode() !== true) {
146+
// if (Breinify.UTL.internal.isDevMode() !== true) {
147+
// return;
148+
// } else
149+
if (this.devStudio !== null) {
9150
return;
10151
}
11152

12-
console.log('DevStudio is being loaded');
153+
const elementName = 'breinify-dev-console';
154+
customElements.define(elementName, BreinifyDevConsole);
155+
156+
this.devStudio = document.createElement(elementName);
157+
document.body.appendChild(this.devStudio);
13158
}
14159
}
15160

dist/breinify-dev-studio.min.js

Lines changed: 33 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)