add FlipCard and Carousel bricks widgets + CSS
This commit is contained in:
parent
0d42a87052
commit
6c94ce66a2
@ -12,7 +12,7 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
|
|||||||
line.js pie.js bar.js gobang.js period.js iconbarpage.js \
|
line.js pie.js bar.js gobang.js period.js iconbarpage.js \
|
||||||
keypress.js asr.js webspeech.js countdown.js progressbar.js \
|
keypress.js asr.js webspeech.js countdown.js progressbar.js \
|
||||||
qaframe.js svg.js videoplayer.js scatter.js radar.js kline.js \
|
qaframe.js svg.js videoplayer.js scatter.js radar.js kline.js \
|
||||||
heatmap.js map.js qr.js textfiles.js agent.js api_doc.js "
|
heatmap.js map.js qr.js textfiles.js agent.js api_doc.js flipcard.js carousel.js "
|
||||||
echo ${SOURCES}
|
echo ${SOURCES}
|
||||||
cat ${SOURCES} > ../dist/bricks.js
|
cat ${SOURCES} > ../dist/bricks.js
|
||||||
# uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js
|
# uglifyjs --compress --mangle -- ../dist/bricks.js > ../dist/bricks.min.js
|
||||||
|
|||||||
75
bricks/carousel.js
Normal file
75
bricks/carousel.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Carousel — auto-rotating FlipCard strip
|
||||||
|
var bricks = window.bricks || {};
|
||||||
|
|
||||||
|
bricks.Carousel = class extends bricks.Layout {
|
||||||
|
/* options: { cards:[{front:{widgettype:...}, back:{widgettype:...}}], cardWidth, cardHeight, interval } */
|
||||||
|
constructor(opts) {
|
||||||
|
super(opts);
|
||||||
|
this.set_css('bricks-carousel');
|
||||||
|
this.set_style('position','relative');
|
||||||
|
this.set_style('overflow','hidden');
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
async _init() {
|
||||||
|
var cd = this.opts.cards || [];
|
||||||
|
if (!cd.length) return;
|
||||||
|
var cw = this.opts.cardWidth || 280;
|
||||||
|
var ch = this.opts.cardHeight || 360;
|
||||||
|
var iv = this.opts.interval || 3000;
|
||||||
|
var sf = this.opts.scaleFactors || [1, 0.85, 0.7, 0.55, 0.4];
|
||||||
|
var ox = this.opts.offsets || [0, 220, 390, 500, 600];
|
||||||
|
var N = cd.length;
|
||||||
|
var mid = Math.floor(N / 2);
|
||||||
|
this._cards = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < N; i++) {
|
||||||
|
var fc = new bricks.FlipCard({ width: cw + 'px', height: ch + 'px' });
|
||||||
|
fc.set_style('position', 'absolute');
|
||||||
|
fc.set_style('left', '50%');
|
||||||
|
fc.set_style('top', '50%');
|
||||||
|
fc.set_style('marginLeft', (-cw / 2) + 'px');
|
||||||
|
fc.set_style('marginTop', (-ch / 2) + 'px');
|
||||||
|
fc.set_style('transition', 'all .5s cubic-bezier(.4,0,.2,1)');
|
||||||
|
fc.set_style('transformOrigin', 'center center');
|
||||||
|
fc._pos = i - mid;
|
||||||
|
|
||||||
|
// Build front/back content asynchronously
|
||||||
|
if (cd[i].front) {
|
||||||
|
var fw = await bricks.widgetBuild(cd[i].front);
|
||||||
|
if (fw) fc.front.appendChild(fw.dom_element);
|
||||||
|
}
|
||||||
|
if (cd[i].back) {
|
||||||
|
var bw = await bricks.widgetBuild(cd[i].back);
|
||||||
|
if (bw) fc.back.appendChild(bw.dom_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cards.push(fc);
|
||||||
|
this.dom_element.appendChild(fc.dom_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sf = sf; this._ox = ox;
|
||||||
|
this._rotate(0);
|
||||||
|
this._timer = setInterval(this._rotate.bind(this, 1), iv);
|
||||||
|
}
|
||||||
|
_rotate(dir) {
|
||||||
|
var cards = this._cards, sf = this._sf, ox = this._ox;
|
||||||
|
if (!cards) return;
|
||||||
|
cards.forEach(function(c) {
|
||||||
|
var np = c._pos - dir;
|
||||||
|
if (np > 4) np = -4; if (np < -4) np = 4;
|
||||||
|
c._pos = np;
|
||||||
|
var a = Math.abs(np), idx = Math.min(a, sf.length - 1);
|
||||||
|
var x = np >= 0 ? ox[idx] : -ox[idx];
|
||||||
|
c.set_styles({
|
||||||
|
transform: 'translateX(' + x + 'px) scale(' + sf[idx] + ')',
|
||||||
|
zIndex: String(5 - idx),
|
||||||
|
opacity: String(idx === 4 ? 0 : sf[idx]),
|
||||||
|
pointerEvents: a > 3 ? 'none' : 'auto'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
create() { this.dom_element = document.createElement('div'); }
|
||||||
|
destroy() { if (this._timer) clearInterval(this._timer); super.destroy(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
bricks.Factory.register('Carousel', bricks.Carousel);
|
||||||
@ -912,3 +912,63 @@ hr {
|
|||||||
height: auto;
|
height: auto;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === FlipCard widget === */
|
||||||
|
.bricks-flipcard {
|
||||||
|
perspective: 1000px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.bricks-flipcard-inner {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
.bricks-flipcard:hover .bricks-flipcard-inner {
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
.bricks-flipcard-front,
|
||||||
|
.bricks-flipcard-back {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
-webkit-backface-visibility: hidden;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.bricks-flipcard-back {
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
.bricks-flipcard-front {
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 18px 54px rgba(90, 60, 160, 0.1), 0 4px 16px rgba(90, 60, 160, 0.05);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.bricks-flipcard-back {
|
||||||
|
background: #3b82f6;
|
||||||
|
box-shadow: 0 18px 54px rgba(59, 130, 246, 0.2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Carousel widget === */
|
||||||
|
.bricks-carousel {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|||||||
34
bricks/flipcard.js
Normal file
34
bricks/flipcard.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// FlipCard — hover to flip, front/back as flat DOM templates
|
||||||
|
var bricks = window.bricks || {};
|
||||||
|
|
||||||
|
bricks.FlipCard = class extends bricks.JsWidget {
|
||||||
|
/* options: { width, height } — front/back styled via CSS child selectors */
|
||||||
|
constructor(opts) {
|
||||||
|
super(opts);
|
||||||
|
this.set_css('bricks-flipcard');
|
||||||
|
var w = this.opts.width || '280px';
|
||||||
|
var h = this.opts.height || '360px';
|
||||||
|
this.set_style('width', w);
|
||||||
|
this.set_style('height', h);
|
||||||
|
this._dom_inner = null;
|
||||||
|
this._dom_front = null;
|
||||||
|
this._dom_back = null;
|
||||||
|
}
|
||||||
|
create() {
|
||||||
|
this.dom_element = document.createElement('div');
|
||||||
|
this._dom_inner = document.createElement('div');
|
||||||
|
this._dom_inner.className = 'bricks-flipcard-inner';
|
||||||
|
this._dom_front = document.createElement('div');
|
||||||
|
this._dom_front.className = 'bricks-flipcard-front';
|
||||||
|
this._dom_back = document.createElement('div');
|
||||||
|
this._dom_back.className = 'bricks-flipcard-back';
|
||||||
|
this._dom_inner.appendChild(this._dom_front);
|
||||||
|
this._dom_inner.appendChild(this._dom_back);
|
||||||
|
this.dom_element.appendChild(this._dom_inner);
|
||||||
|
}
|
||||||
|
// Caller builds front/back content into these containers
|
||||||
|
get front() { return this._dom_front; }
|
||||||
|
get back() { return this._dom_back; }
|
||||||
|
};
|
||||||
|
|
||||||
|
bricks.Factory.register('FlipCard', bricks.FlipCard);
|
||||||
Loading…
x
Reference in New Issue
Block a user