primocode 7.18.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/primocode.js +0 -0
- package/lib/catalogo.js +12 -0
- package/lib/studio.js +198 -0
- package/lib/tools.js +15 -0
- package/lib/ui.js +3 -1
- package/package.json +2 -1
- package/studio/PRIMOCODE.md +58 -0
- package/studio/README.md +154 -0
- package/studio/__pycache__/server.cpython-311.pyc +0 -0
- package/studio/ferramentas/00-protocolo.md +111 -0
- package/studio/ferramentas/01-modelos.md +202 -0
- package/studio/ferramentas/README.md +32 -0
- package/studio/ferramentas/corte.md +193 -0
- package/studio/ferramentas/grade.md +92 -0
- package/studio/ferramentas/prisma.md +99 -0
- package/studio/ferramentas/prosa.md +86 -0
- package/studio/ferramentas/tela.md +72 -0
- package/studio/ferramentas/traco.md +79 -0
- package/studio/server.py +792 -0
- package/studio/web/core.css +723 -0
- package/studio/web/home.html +149 -0
- package/studio/web/js/audio.js +262 -0
- package/studio/web/js/editor.js +1270 -0
- package/studio/web/js/exportar.js +135 -0
- package/studio/web/js/ferramentas.js +105 -0
- package/studio/web/js/icones.js +91 -0
- package/studio/web/js/midia.js +157 -0
- package/studio/web/js/narracao.js +254 -0
- package/studio/web/js/player.js +504 -0
- package/studio/web/js/render-grade.js +243 -0
- package/studio/web/js/render-prosa.js +104 -0
- package/studio/web/js/render.js +622 -0
- package/studio/web/render.css +565 -0
- package/studio/web/tool.html +70 -0
- package/studio/web/view.html +20 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
exportar.js — transforma uma cena renderizada em PNG ou JPG.
|
|
3
|
+
|
|
4
|
+
Exportar.imagem(cenaEl, {largura, altura, escala, formato, nome})
|
|
5
|
+
|
|
6
|
+
Caminho: clona a cena → embute as imagens como data URI → empacota num
|
|
7
|
+
<foreignObject> de SVG com o CSS junto → desenha em canvas → baixa.
|
|
8
|
+
Sem biblioteca externa.
|
|
9
|
+
========================================================================== */
|
|
10
|
+
|
|
11
|
+
var Exportar = (function () {
|
|
12
|
+
"use strict";
|
|
13
|
+
|
|
14
|
+
var cssCache = null;
|
|
15
|
+
|
|
16
|
+
function css() {
|
|
17
|
+
if (cssCache) return Promise.resolve(cssCache);
|
|
18
|
+
return Promise.all([
|
|
19
|
+
fetch("/core.css").then(function (r) { return r.text(); }),
|
|
20
|
+
fetch("/render.css").then(function (r) { return r.text(); }),
|
|
21
|
+
]).then(function (partes) {
|
|
22
|
+
cssCache = partes.join("\n");
|
|
23
|
+
return cssCache;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function paraDataURI(url) {
|
|
28
|
+
if (!url || /^data:/.test(url)) return Promise.resolve(url);
|
|
29
|
+
return fetch(url)
|
|
30
|
+
.then(function (r) { return r.blob(); })
|
|
31
|
+
.then(function (b) {
|
|
32
|
+
return new Promise(function (ok, falha) {
|
|
33
|
+
var l = new FileReader();
|
|
34
|
+
l.onload = function () { ok(l.result); };
|
|
35
|
+
l.onerror = falha;
|
|
36
|
+
l.readAsDataURL(b);
|
|
37
|
+
});
|
|
38
|
+
})
|
|
39
|
+
.catch(function () { return url; });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Toda imagem precisa virar data URI: dentro de um SVG carregado como
|
|
43
|
+
imagem, referência externa não é buscada. */
|
|
44
|
+
function embutirImagens(raiz) {
|
|
45
|
+
var tarefas = [];
|
|
46
|
+
|
|
47
|
+
Array.prototype.forEach.call(raiz.querySelectorAll("img"), function (img) {
|
|
48
|
+
tarefas.push(paraDataURI(img.getAttribute("src")).then(function (d) {
|
|
49
|
+
img.setAttribute("src", d);
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
Array.prototype.forEach.call(raiz.querySelectorAll("*"), function (no) {
|
|
54
|
+
var bg = no.style && no.style.backgroundImage;
|
|
55
|
+
if (!bg || bg.indexOf("url(") < 0) return;
|
|
56
|
+
var m = bg.match(/url\(["']?([^"')]+)["']?\)/);
|
|
57
|
+
if (!m || /^data:/.test(m[1])) return;
|
|
58
|
+
tarefas.push(paraDataURI(m[1]).then(function (d) {
|
|
59
|
+
no.style.backgroundImage = 'url("' + d + '")';
|
|
60
|
+
}));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return Promise.all(tarefas);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function imagem(cenaEl, op) {
|
|
67
|
+
op = op || {};
|
|
68
|
+
var L = op.largura || cenaEl.offsetWidth || 1920;
|
|
69
|
+
var A = op.altura || cenaEl.offsetHeight || 1080;
|
|
70
|
+
var escala = op.escala || 2;
|
|
71
|
+
var formato = op.formato === "jpg" ? "image/jpeg" : "image/png";
|
|
72
|
+
|
|
73
|
+
var clone = cenaEl.cloneNode(true);
|
|
74
|
+
clone.classList.remove("animar");
|
|
75
|
+
clone.style.transform = "none";
|
|
76
|
+
clone.style.position = "static";
|
|
77
|
+
clone.style.width = L + "px";
|
|
78
|
+
clone.style.height = A + "px";
|
|
79
|
+
// animação parada no estado final, senão sai tudo transparente
|
|
80
|
+
Array.prototype.forEach.call(clone.querySelectorAll("*"), function (n) {
|
|
81
|
+
n.style.animation = "none";
|
|
82
|
+
n.style.opacity = n.style.opacity === "0" ? "1" : n.style.opacity;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
var caixa = document.createElement("div");
|
|
86
|
+
caixa.appendChild(clone);
|
|
87
|
+
|
|
88
|
+
return embutirImagens(caixa)
|
|
89
|
+
.then(css)
|
|
90
|
+
.then(function (folha) {
|
|
91
|
+
var html = new XMLSerializer().serializeToString(clone);
|
|
92
|
+
var svg =
|
|
93
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="' + L + '" height="' + A + '">' +
|
|
94
|
+
"<foreignObject width='100%' height='100%'>" +
|
|
95
|
+
'<div xmlns="http://www.w3.org/1999/xhtml">' +
|
|
96
|
+
"<style>" + folha.replace(/<\/style>/gi, "") + "</style>" +
|
|
97
|
+
html +
|
|
98
|
+
"</div></foreignObject></svg>";
|
|
99
|
+
|
|
100
|
+
return new Promise(function (ok, falha) {
|
|
101
|
+
var img = new Image();
|
|
102
|
+
img.onload = function () { ok(img); };
|
|
103
|
+
img.onerror = function () { falha(new Error("não consegui montar a imagem")); };
|
|
104
|
+
img.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
|
|
105
|
+
});
|
|
106
|
+
})
|
|
107
|
+
.then(function (img) {
|
|
108
|
+
var tela = document.createElement("canvas");
|
|
109
|
+
tela.width = L * escala;
|
|
110
|
+
tela.height = A * escala;
|
|
111
|
+
var c = tela.getContext("2d");
|
|
112
|
+
if (formato === "image/jpeg") {
|
|
113
|
+
c.fillStyle = "#ffffff";
|
|
114
|
+
c.fillRect(0, 0, tela.width, tela.height);
|
|
115
|
+
}
|
|
116
|
+
c.drawImage(img, 0, 0, tela.width, tela.height);
|
|
117
|
+
return new Promise(function (ok) {
|
|
118
|
+
tela.toBlob(function (b) { ok(b); }, formato, 0.94);
|
|
119
|
+
});
|
|
120
|
+
})
|
|
121
|
+
.then(function (blob) {
|
|
122
|
+
if (!blob) throw new Error("o navegador não gerou o arquivo");
|
|
123
|
+
var url = URL.createObjectURL(blob);
|
|
124
|
+
var a = document.createElement("a");
|
|
125
|
+
a.href = url;
|
|
126
|
+
a.download = (op.nome || "arte").replace(/[^\w\-]+/g, "-").toLowerCase() +
|
|
127
|
+
(formato === "image/jpeg" ? ".jpg" : ".png");
|
|
128
|
+
a.click();
|
|
129
|
+
setTimeout(function () { URL.revokeObjectURL(url); }, 4000);
|
|
130
|
+
return true;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { imagem: imagem };
|
|
135
|
+
})();
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
ferramentas.js — o que cada ferramenta oferece na interface.
|
|
3
|
+
========================================================================== */
|
|
4
|
+
|
|
5
|
+
var TEMAS = ["meia-noite", "claro", "papel", "neon", "brasa", "floresta"];
|
|
6
|
+
|
|
7
|
+
var PALETA = ["#ff5a36", "#ffb03a", "#f4e04d", "#2fbf7f", "#1f8fe0", "#8b5cf6",
|
|
8
|
+
"#f472b6", "#ffffff", "#9aa4b2", "#111318"];
|
|
9
|
+
|
|
10
|
+
var FERR = {
|
|
11
|
+
prisma: {
|
|
12
|
+
nome: "Prisma", papel: "Apresentações", cor: "#FF5A36", icone: "tela", modelo: "cena",
|
|
13
|
+
layouts: ["capa", "titulo", "secao", "duas-colunas", "tres-colunas", "citacao",
|
|
14
|
+
"numeros", "imagem-direita", "imagem-esquerda", "centro", "livre"],
|
|
15
|
+
layoutPadrao: "titulo",
|
|
16
|
+
trilho: [
|
|
17
|
+
{ k: "titulo", i: "titulo", r: "Título", novo: { tipo: "texto", papel: "titulo", texto: "Novo título" } },
|
|
18
|
+
{ k: "texto", i: "texto", r: "Texto", novo: { tipo: "texto", papel: "corpo", texto: "Um parágrafo de apoio." } },
|
|
19
|
+
{ k: "lista", i: "lista", r: "Lista", novo: { tipo: "lista", itens: ["Primeiro ponto", "Segundo ponto"] } },
|
|
20
|
+
{ k: "cartoes", i: "cartao", r: "Cartões", novo: { tipo: "cartoes", itens: ["Título | descrição", "Título | descrição"] } },
|
|
21
|
+
{ k: "numeros", i: "numero", r: "Números", novo: { tipo: "numeros", itens: ["3x | crescimento", "42% | margem"] } },
|
|
22
|
+
{ k: "tabela", i: "tabela", r: "Tabela", novo: { tipo: "tabela", linhas: [["Coluna", "Coluna"], ["dado", "dado"]] } },
|
|
23
|
+
{ k: "citacao", i: "citacao", r: "Citação", novo: { tipo: "citacao", texto: "Uma frase que fica.", autor: "Autor" } },
|
|
24
|
+
{ k: "grafico", i: "grafico", r: "Gráfico", novo: { tipo: "grafico", grafico: "barras", dados: [["A", 30], ["B", 55], ["C", 40]] } },
|
|
25
|
+
{ k: "imagem", i: "imagem", r: "Imagem", novo: { tipo: "imagem", src: "", ajuste: "cobrir" } },
|
|
26
|
+
{ k: "icone", i: "icone", r: "Ícone", novo: { tipo: "icone", nome: "raio", tamanho: 120 } },
|
|
27
|
+
{ k: "codigo", i: "codigo", r: "Código", novo: { tipo: "codigo", texto: "npm install" } },
|
|
28
|
+
{ k: "forma", i: "quadrado", r: "Forma", novo: { tipo: "forma", forma: "retangulo", x: 200, y: 200, l: 400, a: 220, raio: 20 } },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
tela: {
|
|
33
|
+
nome: "Tela", papel: "Design gráfico", cor: "#8B5CF6", icone: "lapis", modelo: "cena",
|
|
34
|
+
layouts: ["livre", "centro", "capa"], layoutPadrao: "livre",
|
|
35
|
+
tamanhos: [["Post 1080", 1080, 1080], ["Story 1080x1920", 1080, 1920],
|
|
36
|
+
["Capa 1920x1080", 1920, 1080], ["Banner 1600x600", 1600, 600]],
|
|
37
|
+
trilho: [
|
|
38
|
+
{ k: "texto", i: "texto", r: "Texto", novo: { tipo: "texto", texto: "Texto", x: 120, y: 120, l: 700, a: 140, tamanho: 88, peso: 700 } },
|
|
39
|
+
{ k: "quadrado", i: "quadrado", r: "Retângulo", novo: { tipo: "forma", forma: "retangulo", x: 160, y: 160, l: 420, a: 300, raio: 24 } },
|
|
40
|
+
{ k: "circulo", i: "circulo", r: "Círculo", novo: { tipo: "forma", forma: "circulo", x: 200, y: 200, l: 320, a: 320 } },
|
|
41
|
+
{ k: "triangulo", i: "triangulo", r: "Triângulo", novo: { tipo: "forma", forma: "triangulo", x: 200, y: 200, l: 320, a: 300 } },
|
|
42
|
+
{ k: "linha", i: "linha", r: "Linha", novo: { tipo: "forma", forma: "linha", x: 160, y: 400, l: 620, a: 6, espessura: 6 } },
|
|
43
|
+
{ k: "seta", i: "seta", r: "Seta", novo: { tipo: "forma", forma: "seta", x: 200, y: 400, l: 460, a: 60 } },
|
|
44
|
+
{ k: "imagem", i: "imagem", r: "Imagem", novo: { tipo: "imagem", src: "", x: 120, y: 120, l: 620, a: 460 } },
|
|
45
|
+
{ k: "icone", i: "icone", r: "Ícone", novo: { tipo: "icone", nome: "estrela", x: 300, y: 300, tamanho: 160 } },
|
|
46
|
+
{ k: "grafico", i: "grafico", r: "Gráfico", novo: { tipo: "grafico", grafico: "rosca", x: 160, y: 200, l: 620, a: 460, dados: [["A", 40], ["B", 30], ["C", 30]] } },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
corte: {
|
|
51
|
+
nome: "Corte", papel: "Vídeo", cor: "#E0397A", icone: "video", modelo: "cena",
|
|
52
|
+
layouts: ["capa", "centro", "titulo", "citacao", "numeros", "imagem-direita", "livre"],
|
|
53
|
+
layoutPadrao: "capa", tempo: true,
|
|
54
|
+
trilho: [
|
|
55
|
+
{ k: "titulo", i: "titulo", r: "Título", novo: { tipo: "texto", papel: "titulo", texto: "Título da cena" } },
|
|
56
|
+
{ k: "texto", i: "texto", r: "Texto", novo: { tipo: "texto", papel: "apoio", texto: "Legenda da cena" } },
|
|
57
|
+
{ k: "lista", i: "lista", r: "Lista", novo: { tipo: "lista", itens: ["Um", "Dois"], revelar: true } },
|
|
58
|
+
{ k: "numeros", i: "numero", r: "Números", novo: { tipo: "numeros", itens: ["100% | atenção"] } },
|
|
59
|
+
{ k: "imagem", i: "imagem", r: "Imagem", novo: { tipo: "imagem", src: "", ajuste: "cobrir" } },
|
|
60
|
+
{ k: "icone", i: "icone", r: "Ícone", novo: { tipo: "icone", nome: "foguete", tamanho: 200 } },
|
|
61
|
+
{ k: "forma", i: "quadrado", r: "Forma", novo: { tipo: "forma", forma: "retangulo", x: 200, y: 200, l: 400, a: 220, raio: 20 } },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
traco: {
|
|
66
|
+
nome: "Traço", papel: "Diagramas", cor: "#D9A21B", icone: "conector", modelo: "cena",
|
|
67
|
+
layouts: ["livre"], layoutPadrao: "livre",
|
|
68
|
+
trilho: [
|
|
69
|
+
{ k: "no", i: "no", r: "Nó", novo: { tipo: "no", texto: "Etapa", x: 300, y: 300, l: 340, a: 150 } },
|
|
70
|
+
{ k: "no-destaque", i: "circulo", r: "Nó destacado", novo: { tipo: "no", texto: "Chave", destaque: true, x: 300, y: 500, l: 340, a: 150 } },
|
|
71
|
+
{ k: "conector", i: "conector", r: "Conector", novo: { tipo: "conector", de: "", para: "" } },
|
|
72
|
+
{ k: "texto", i: "texto", r: "Texto", novo: { tipo: "texto", texto: "Anotação", x: 200, y: 120, l: 500, a: 90, tamanho: 32 } },
|
|
73
|
+
{ k: "forma", i: "quadrado", r: "Área", novo: { tipo: "forma", forma: "retangulo", x: 160, y: 160, l: 700, a: 500, raio: 26, preenchimento: "rgba(255,255,255,.04)", borda: { cor: "var(--c-linha)", largura: 2 } } },
|
|
74
|
+
{ k: "icone", i: "icone", r: "Ícone", novo: { tipo: "icone", nome: "engrenagem", x: 300, y: 300, tamanho: 120 } },
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
prosa: {
|
|
79
|
+
nome: "Prosa", papel: "Documentos", cor: "#2E9E6B", icone: "livro", modelo: "documento",
|
|
80
|
+
trilho: [
|
|
81
|
+
{ k: "titulo", i: "titulo", r: "Título", novo: { tipo: "titulo", texto: "Título" } },
|
|
82
|
+
{ k: "secao", i: "texto", r: "Seção", novo: { tipo: "secao", texto: "Nova seção" } },
|
|
83
|
+
{ k: "subsecao", i: "texto", r: "Subseção", novo: { tipo: "subsecao", texto: "Subseção" } },
|
|
84
|
+
{ k: "paragrafo", i: "texto", r: "Parágrafo", novo: { tipo: "paragrafo", texto: "Escreva aqui." } },
|
|
85
|
+
{ k: "lista", i: "lista", r: "Lista", novo: { tipo: "lista", itens: ["Item um", "Item dois"] } },
|
|
86
|
+
{ k: "numerada", i: "numero", r: "Numerada", novo: { tipo: "numerada", itens: ["Primeiro", "Segundo"] } },
|
|
87
|
+
{ k: "citacao", i: "citacao", r: "Citação", novo: { tipo: "citacao", texto: "Trecho citado.", autor: "Fonte" } },
|
|
88
|
+
{ k: "tabela", i: "tabela", r: "Tabela", novo: { tipo: "tabela", linhas: [["Coluna", "Coluna"], ["dado", "dado"]] } },
|
|
89
|
+
{ k: "codigo", i: "codigo", r: "Código", novo: { tipo: "codigo", texto: "console.log('oi')" } },
|
|
90
|
+
{ k: "destaque", i: "cartao", r: "Destaque", novo: { tipo: "destaque", titulo: "Atenção", texto: "Ponto importante." } },
|
|
91
|
+
{ k: "imagem", i: "imagem", r: "Imagem", novo: { tipo: "imagem", src: "", legenda: "" } },
|
|
92
|
+
{ k: "divisor", i: "linha", r: "Divisor", novo: { tipo: "divisor" } },
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
grade: {
|
|
97
|
+
nome: "Grade", papel: "Planilhas", cor: "#1F8FE0", icone: "tabela", modelo: "planilha",
|
|
98
|
+
trilho: [
|
|
99
|
+
{ k: "linha", i: "mais", r: "Nova linha" },
|
|
100
|
+
{ k: "coluna", i: "tabela", r: "Nova coluna" },
|
|
101
|
+
{ k: "total", i: "numero", r: "Linha de total" },
|
|
102
|
+
{ k: "grafico", i: "grafico", r: "Gráfico" },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
icones.js — biblioteca de ícones em SVG, sem dependência externa.
|
|
3
|
+
Traço de 24x24, herda a cor do texto. Usada na interface e nos documentos.
|
|
4
|
+
========================================================================== */
|
|
5
|
+
|
|
6
|
+
var ICONES = {
|
|
7
|
+
/* interface */
|
|
8
|
+
cursor: "M4 3l7 17 2.5-6.5L20 11z",
|
|
9
|
+
texto: "M5 6V4h14v2M12 4v16M9 20h6",
|
|
10
|
+
titulo: "M5 5v14M13 5v14M5 12h8M17 9h3v10M17 9l3-2",
|
|
11
|
+
lista: "M8 6h12M8 12h12M8 18h12M4 6h.01M4 12h.01M4 18h.01",
|
|
12
|
+
quadrado: "M4 4h16v16H4z",
|
|
13
|
+
circulo: "M12 3a9 9 0 100 18 9 9 0 000-18z",
|
|
14
|
+
triangulo: "M12 4l9 16H3z",
|
|
15
|
+
linha: "M4 20L20 4",
|
|
16
|
+
seta: "M4 12h15M14 6l6 6-6 6",
|
|
17
|
+
imagem: "M3 5h18v14H3zM3 15l5-5 4 4 3-3 6 6",
|
|
18
|
+
icone: "M12 3l2.6 5.6 6.1.8-4.5 4.2 1.2 6.1L12 16.8 6.6 19.7l1.2-6.1L3.3 9.4l6.1-.8z",
|
|
19
|
+
grafico: "M4 20V10M10 20V4M16 20v-7M22 20H2",
|
|
20
|
+
cartao: "M3 5h8v6H3zM13 5h8v6h-8zM3 13h8v6H3zM13 13h8v6h-8z",
|
|
21
|
+
numero: "M6 20V8l-2 1M12 20V4M18 20v-6l-2 1",
|
|
22
|
+
tabela: "M3 5h18v14H3zM3 10h18M9 10v9M15 10v9",
|
|
23
|
+
codigo: "M9 7l-5 5 5 5M15 7l5 5-5 5",
|
|
24
|
+
citacao: "M8 6c-2.5 0-4 2-4 4.5S5.5 15 8 15c0 3-2 4-2 4 5 0 8-3.5 8-9 0-2.5-2-4-3-4zM19 6c-2 0-3 1.5-3 4 0 5.5 3 9 8 9 0 0-2-1-2-4 2.5 0 4-2 4-4.5S21.5 6 19 6z",
|
|
25
|
+
no: "M5 8h14v8H5zM12 3v5M12 16v5",
|
|
26
|
+
conector: "M6 6a3 3 0 100 6 3 3 0 000-6zM18 12a3 3 0 100 6 3 3 0 000-6zM8.5 10.5L15.5 14",
|
|
27
|
+
video: "M3 6h13v12H3zM16 10l5-3v10l-5-3",
|
|
28
|
+
lapis: "M4 20l4-1 11-11-3-3L5 16z",
|
|
29
|
+
cor: "M12 3a9 9 0 000 18c1 0 2-.8 2-1.8 0-1.5-1.4-1.7-1.4-3 0-1 .8-1.7 1.8-1.7H16a5 5 0 005-5c0-3.6-4-6.5-9-6.5z",
|
|
30
|
+
camada: "M12 3l9 5-9 5-9-5zM3 13l9 5 9-5",
|
|
31
|
+
mais: "M12 5v14M5 12h14",
|
|
32
|
+
menos: "M5 12h14",
|
|
33
|
+
lixeira: "M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13",
|
|
34
|
+
duplicar: "M8 8h12v12H8zM4 16V4h12",
|
|
35
|
+
subir: "M12 19V5M6 11l6-6 6 6",
|
|
36
|
+
descer: "M12 5v14M6 13l6 6 6-6",
|
|
37
|
+
play: "M7 4l13 8-13 8z",
|
|
38
|
+
pausa: "M8 5h3v14H8zM13 5h3v14h-3z",
|
|
39
|
+
olho: "M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7zM12 9a3 3 0 100 6 3 3 0 000-6z",
|
|
40
|
+
baixar: "M12 4v11M7 11l5 5 5-5M4 20h16",
|
|
41
|
+
tela: "M3 4h18v13H3zM8 21h8M12 17v4",
|
|
42
|
+
voltar: "M4 9h11a4 4 0 010 8h-6M4 9l4-4M4 9l4 4",
|
|
43
|
+
refazer: "M20 9H9a4 4 0 000 8h6M20 9l-4-4M20 9l-4 4",
|
|
44
|
+
fechar: "M6 6l12 12M18 6L6 18",
|
|
45
|
+
check: "M4 12l5 5L20 6",
|
|
46
|
+
livro: "M4 5h7a2 2 0 012 2v12a2 2 0 00-2-2H4zM20 5h-7a2 2 0 00-2 2v12a2 2 0 012-2h7z",
|
|
47
|
+
raio2: "M13 2L4 14h6l-1 8 9-12h-6z",
|
|
48
|
+
|
|
49
|
+
/* conteúdo — para o elemento "icone" */
|
|
50
|
+
raio: "M13 2L4 14h6l-1 8 9-12h-6z",
|
|
51
|
+
alvo: "M12 3a9 9 0 100 18 9 9 0 000-18zM12 8a4 4 0 100 8 4 4 0 000-8zM12 11.5a.5.5 0 100 1 .5.5 0 000-1z",
|
|
52
|
+
foguete: "M12 3c4 2 6 6 6 10l-3 3H9l-3-3c0-4 2-8 6-10zM9 16l-3 5 4-2M15 16l3 5-4-2M12 9a1.5 1.5 0 100 3 1.5 1.5 0 000-3z",
|
|
53
|
+
escudo: "M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z",
|
|
54
|
+
relogio: "M12 3a9 9 0 100 18 9 9 0 000-18zM12 7v5l3 2",
|
|
55
|
+
usuario: "M12 4a4 4 0 100 8 4 4 0 000-8zM4 21c0-4 3.5-6 8-6s8 2 8 6",
|
|
56
|
+
coracao: "M12 20S3 14 3 8.5A4.5 4.5 0 0112 6a4.5 4.5 0 019 2.5C21 14 12 20 12 20z",
|
|
57
|
+
estrela: "M12 3l2.6 5.6 6.1.8-4.5 4.2 1.2 6.1L12 16.8 6.6 19.7l1.2-6.1L3.3 9.4l6.1-.8z",
|
|
58
|
+
nuvem: "M7 18a4 4 0 010-8 5.5 5.5 0 0110.5 1.5A3.5 3.5 0 0117 18z",
|
|
59
|
+
engrenagem: "M12 9a3 3 0 100 6 3 3 0 000-6zM19 12l2-1.5-2-3.5-2.4.8a7 7 0 00-2-1.2L14 4h-4l-.6 2.6a7 7 0 00-2 1.2L5 7l-2 3.5L5 12l-2 1.5L5 17l2.4-.8a7 7 0 002 1.2L10 20h4l.6-2.6a7 7 0 002-1.2L19 17l2-3.5z",
|
|
60
|
+
lampada: "M9 18h6M10 21h4M12 3a6 6 0 00-4 10.5c.7.8 1 1.5 1 2.5h6c0-1 .3-1.7 1-2.5A6 6 0 0012 3z",
|
|
61
|
+
cadeado: "M5 11h14v10H5zM8 11V8a4 4 0 018 0v3",
|
|
62
|
+
casa: "M4 11l8-7 8 7v9h-5v-6h-6v6H4z",
|
|
63
|
+
email: "M3 6h18v12H3zM3 7l9 6 9-6",
|
|
64
|
+
telefone: "M6 3h4l2 5-2.5 1.5a12 12 0 005 5L16 12l5 2v4a2 2 0 01-2 2C11 20 4 13 4 5a2 2 0 012-2z",
|
|
65
|
+
camera: "M4 8h4l1.5-2h5L16 8h4v11H4zM12 10.5a3.5 3.5 0 100 7 3.5 3.5 0 000-7z",
|
|
66
|
+
fogo: "M12 3s5 4 5 9a5 5 0 01-10 0c0-2 1-3 1-3s.5 2 2 2c0-3 2-5 2-8z",
|
|
67
|
+
globo: "M12 3a9 9 0 100 18 9 9 0 000-18zM3 12h18M12 3c2.5 3 2.5 15 0 18M12 3c-2.5 3-2.5 15 0 18",
|
|
68
|
+
chave: "M14 4a5 5 0 015 5 5 5 0 01-6.5 4.8L11 16H9v2H7v2H3v-4l7.2-7.2A5 5 0 0114 4zM16 8a1 1 0 100 2 1 1 0 000-2z",
|
|
69
|
+
presente: "M3 11h18v9H3zM3 7h18v4H3zM12 7v13M12 7C10 3 6 4 7 7M12 7c2-4 6-3 5 0",
|
|
70
|
+
sino: "M12 3a6 6 0 00-6 6c0 5-2 6-2 6h16s-2-1-2-6a6 6 0 00-6-6zM10 19a2 2 0 004 0",
|
|
71
|
+
mapa: "M9 4L3 6v14l6-2 6 2 6-2V4l-6 2zM9 4v14M15 6v14",
|
|
72
|
+
dinheiro: "M12 4v16M15.5 8c0-1.4-1.6-2.2-3.5-2.2S8.5 6.7 8.5 8.3 10.4 10.5 12 11s3.5 1 3.5 2.7-1.6 2.5-3.5 2.5-3.5-.9-3.5-2.4",
|
|
73
|
+
crescimento: "M4 18l5-5 3 3 8-8M15 8h5v5",
|
|
74
|
+
pessoas: "M9 5a3.5 3.5 0 100 7 3.5 3.5 0 000-7zM2 20c0-3.5 3-5 7-5s7 1.5 7 5M17 6a3 3 0 110 6M18 20c0-2.5-.8-4-2-4.6",
|
|
75
|
+
balao: "M4 5h16v11H9l-5 4z",
|
|
76
|
+
pasta: "M3 6h6l2 3h10v10H3z",
|
|
77
|
+
play2: "M12 3a9 9 0 100 18 9 9 0 000-18zM10 8.5l6 3.5-6 3.5z",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
function svgIcone(nome, cls) {
|
|
81
|
+
var d = ICONES[nome] || ICONES.circulo;
|
|
82
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" ' +
|
|
83
|
+
'stroke-linecap="round" stroke-linejoin="round"' + (cls ? ' class="' + cls + '"' : "") +
|
|
84
|
+
"><path d=\"" + d + '"/></svg>';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function nomesIcones() {
|
|
88
|
+
return Object.keys(ICONES);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (typeof module !== "undefined" && module.exports) module.exports = { ICONES: ICONES, svgIcone: svgIcone };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
midia.js — biblioteca de arquivos do computador (imagem, áudio, vídeo).
|
|
3
|
+
|
|
4
|
+
Midia.escolher({ tipo: "imagem" | "audio" }) → Promise<{url, nome, tipo}>
|
|
5
|
+
Aceita upload por botão ou arrastando o arquivo para dentro da janela.
|
|
6
|
+
========================================================================== */
|
|
7
|
+
|
|
8
|
+
var Midia = (function () {
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
var LIMITE_MB = 60;
|
|
12
|
+
|
|
13
|
+
function el(tag, cls, html) {
|
|
14
|
+
var n = document.createElement(tag);
|
|
15
|
+
if (cls) n.className = cls;
|
|
16
|
+
if (html != null) n.innerHTML = html;
|
|
17
|
+
return n;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function kb(bytes) {
|
|
21
|
+
return bytes > 1048576 ? (bytes / 1048576).toFixed(1) + " MB"
|
|
22
|
+
: Math.max(1, Math.round(bytes / 1024)) + " KB";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function listar() {
|
|
26
|
+
return fetch("/api/midia").then(function (r) { return r.json(); });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Envia um File do computador para o servidor. */
|
|
30
|
+
function enviar(arquivo) {
|
|
31
|
+
if (arquivo.size > LIMITE_MB * 1048576) {
|
|
32
|
+
return Promise.reject(new Error("arquivo acima de " + LIMITE_MB + " MB"));
|
|
33
|
+
}
|
|
34
|
+
return new Promise(function (ok, falha) {
|
|
35
|
+
var leitor = new FileReader();
|
|
36
|
+
leitor.onerror = function () { falha(new Error("não consegui ler o arquivo")); };
|
|
37
|
+
leitor.onload = function () {
|
|
38
|
+
fetch("/api/midia", {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: { "Content-Type": "application/json" },
|
|
41
|
+
body: JSON.stringify({ nome: arquivo.name, dados: leitor.result }),
|
|
42
|
+
}).then(function (r) { return r.json(); })
|
|
43
|
+
.then(function (m) { m.erro ? falha(new Error(m.erro)) : ok(m); })
|
|
44
|
+
.catch(falha);
|
|
45
|
+
};
|
|
46
|
+
leitor.readAsDataURL(arquivo);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function apagar(nome) {
|
|
51
|
+
return fetch("/api/midia/" + encodeURIComponent(nome), { method: "DELETE" });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ------------------------------------------------------------- modal -- */
|
|
55
|
+
|
|
56
|
+
function escolher(op) {
|
|
57
|
+
op = op || {};
|
|
58
|
+
var tipo = op.tipo || "imagem";
|
|
59
|
+
|
|
60
|
+
return new Promise(function (resolver) {
|
|
61
|
+
var folha = el("div", "folha midia on");
|
|
62
|
+
folha.innerHTML =
|
|
63
|
+
'<div class="caixa">' +
|
|
64
|
+
'<div class="midia-topo">' +
|
|
65
|
+
"<h3>" + (tipo === "audio" ? "Áudio do computador" : "Imagens") + "</h3>" +
|
|
66
|
+
'<div style="flex:1"></div>' +
|
|
67
|
+
'<button class="btn" data-x="fechar">Fechar</button>' +
|
|
68
|
+
'<button class="btn primo" data-x="subir">Escolher arquivo</button>' +
|
|
69
|
+
"</div>" +
|
|
70
|
+
'<div class="solta" data-x="solta">Arraste um arquivo aqui — ou clique em ' +
|
|
71
|
+
"<b>Escolher arquivo</b>. Até " + LIMITE_MB + " MB.</div>" +
|
|
72
|
+
'<div class="midia-grade" data-x="grade"></div>' +
|
|
73
|
+
"</div>";
|
|
74
|
+
document.body.appendChild(folha);
|
|
75
|
+
|
|
76
|
+
var entrada = el("input");
|
|
77
|
+
entrada.type = "file";
|
|
78
|
+
entrada.accept = tipo === "audio" ? "audio/*" : "image/*";
|
|
79
|
+
entrada.style.display = "none";
|
|
80
|
+
folha.appendChild(entrada);
|
|
81
|
+
|
|
82
|
+
var grade = folha.querySelector('[data-x="grade"]');
|
|
83
|
+
var solta = folha.querySelector('[data-x="solta"]');
|
|
84
|
+
|
|
85
|
+
function fechar(resultado) {
|
|
86
|
+
folha.remove();
|
|
87
|
+
document.removeEventListener("dragover", pegaArrasto);
|
|
88
|
+
document.removeEventListener("drop", pegaSolta);
|
|
89
|
+
resolver(resultado || null);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function desenhar() {
|
|
93
|
+
grade.innerHTML = '<div class="vazio-midia">carregando…</div>';
|
|
94
|
+
listar().then(function (lista) {
|
|
95
|
+
var itens = lista.filter(function (m) { return m.tipo === tipo; });
|
|
96
|
+
if (!itens.length) {
|
|
97
|
+
grade.innerHTML = '<div class="vazio-midia">Nada aqui ainda. ' +
|
|
98
|
+
(tipo === "audio" ? "Suba uma música que você já tem no computador."
|
|
99
|
+
: "Suba uma imagem para começar.") + "</div>";
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
grade.innerHTML = "";
|
|
103
|
+
itens.forEach(function (m) {
|
|
104
|
+
var c = el("div", "midia-item");
|
|
105
|
+
c.innerHTML = (tipo === "audio"
|
|
106
|
+
? '<div class="mini-audio">' + svgIcone("play2") + "</div>"
|
|
107
|
+
: '<div class="mini-img" style="background-image:url(\'' + m.url + '\')"></div>') +
|
|
108
|
+
'<div class="mini-nome" title="' + m.nome + '">' + m.nome + "</div>" +
|
|
109
|
+
'<div class="mini-meta">' + kb(m.bytes) + "</div>" +
|
|
110
|
+
'<button class="mini-x" title="Apagar">×</button>';
|
|
111
|
+
c.onclick = function (ev) {
|
|
112
|
+
if (ev.target.classList.contains("mini-x")) {
|
|
113
|
+
ev.stopPropagation();
|
|
114
|
+
apagar(m.nome).then(desenhar);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
fechar(m);
|
|
118
|
+
};
|
|
119
|
+
grade.appendChild(c);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function subir(arquivo) {
|
|
125
|
+
if (!arquivo) return;
|
|
126
|
+
solta.textContent = "enviando " + arquivo.name + "…";
|
|
127
|
+
enviar(arquivo).then(function (m) {
|
|
128
|
+
solta.textContent = "pronto: " + m.nome;
|
|
129
|
+
if (op.direto) return fechar(m);
|
|
130
|
+
desenhar();
|
|
131
|
+
}).catch(function (e) {
|
|
132
|
+
solta.textContent = "erro: " + e.message;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
folha.addEventListener("click", function (ev) {
|
|
137
|
+
var acao = (ev.target.dataset || {}).x;
|
|
138
|
+
if (acao === "fechar" || ev.target === folha) fechar(null);
|
|
139
|
+
if (acao === "subir" || acao === "solta") entrada.click();
|
|
140
|
+
});
|
|
141
|
+
entrada.onchange = function () { subir(entrada.files[0]); };
|
|
142
|
+
|
|
143
|
+
function pegaArrasto(ev) { ev.preventDefault(); solta.classList.add("ativo"); }
|
|
144
|
+
function pegaSolta(ev) {
|
|
145
|
+
ev.preventDefault();
|
|
146
|
+
solta.classList.remove("ativo");
|
|
147
|
+
subir(ev.dataTransfer.files[0]);
|
|
148
|
+
}
|
|
149
|
+
document.addEventListener("dragover", pegaArrasto);
|
|
150
|
+
document.addEventListener("drop", pegaSolta);
|
|
151
|
+
|
|
152
|
+
desenhar();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return { escolher: escolher, enviar: enviar, listar: listar, apagar: apagar };
|
|
157
|
+
})();
|