@geekapps/silo-elements-nextjs 0.3.2 → 0.3.4

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.
@@ -182,7 +182,7 @@ function ImageOptions({ value, onChange, style }) {
182
182
  ] })
183
183
  ] });
184
184
  }
185
- var CODECS = [
185
+ var VIDEO_CODECS = [
186
186
  {
187
187
  value: "h264",
188
188
  label: "H.264",
@@ -191,15 +191,46 @@ var CODECS = [
191
191
  {
192
192
  value: "h265",
193
193
  label: "H.265",
194
- description: "50% menor que H.264 com a mesma qualidade. Requer player moderno (Chrome, Safari, Firefox)."
194
+ description: "50% menor que H.264 com a mesma qualidade. Requer player moderno."
195
195
  },
196
196
  {
197
197
  value: "av1",
198
198
  label: "AV1",
199
- description: "M\xE1xima efici\xEAncia \u2014 at\xE9 50% menor que H.265. Suportado no Chrome, Firefox e Safari 17+.",
200
- warning: "AV1 n\xE3o \xE9 suportado em iPhones mais antigos (iOS < 16) e Smart TVs antigas."
199
+ description: "M\xE1xima efici\xEAncia \u2014 at\xE9 50% menor que H.265. Chrome 70+, Firefox 67+, Safari 17+.",
200
+ warning: "N\xE3o suportado em iPhones antigos (iOS < 16) e Smart TVs antigas."
201
201
  }
202
202
  ];
203
+ var AUDIO_SIMPLE = [
204
+ {
205
+ value: "passthrough",
206
+ label: "Preservar original",
207
+ badge: "Recomendado",
208
+ description: "Copia o \xE1udio sem reencodar quando compat\xEDvel com HLS (AAC, AC3, E-AC3). Converte para AAC est\xE9reo como fallback."
209
+ },
210
+ {
211
+ value: "aac",
212
+ label: "AAC",
213
+ description: "Compatibilidade m\xE1xima. Funciona em todos os players e dispositivos."
214
+ },
215
+ {
216
+ value: "opus",
217
+ label: "Opus",
218
+ description: "Melhor efici\xEAncia que AAC. Suportado em Chrome, Firefox e Android. N\xE3o suportado em Safari/iOS."
219
+ }
220
+ ];
221
+ var AUDIO_ADVANCED_CODEC = [
222
+ { value: "passthrough", label: "Original", description: "Passthrough quando HLS-compat\xEDvel, AAC como fallback." },
223
+ { value: "aac", label: "AAC", description: "Compatibilidade m\xE1xima." },
224
+ { value: "opus", label: "Opus", description: "Melhor efici\xEAncia que AAC. Chrome/Firefox/Android." },
225
+ { value: "ac3", label: "AC3", description: "Dolby Digital. Compat\xEDvel com HLS e home theaters." },
226
+ { value: "eac3", label: "E-AC3", description: "Dolby Digital Plus. Suporta Atmos. Netflix, Disney+, Apple TV+." }
227
+ ];
228
+ var AUDIO_CHANNELS = [
229
+ { value: "original", label: "Original", description: "Mant\xE9m os canais do arquivo fonte." },
230
+ { value: "stereo", label: "Est\xE9reo", description: "2.0 \u2014 compat\xEDvel com todos os dispositivos." },
231
+ { value: "5.1", label: "5.1", description: "Surround 5.1." },
232
+ { value: "7.1", label: "7.1", description: "Surround 7.1." }
233
+ ];
203
234
  var RESOLUTIONS = ["144", "240", "360", "480", "720", "1080", "1440", "2160"];
204
235
  var RESOLUTION_LABELS = {
205
236
  "144": "144p",
@@ -212,20 +243,40 @@ var RESOLUTION_LABELS = {
212
243
  "2160": "4K"
213
244
  };
214
245
  function optBtnStyle(active) {
215
- return active ? { border: "1px solid #6366f1", background: "#6366f1", color: "#fff", padding: "4px 10px", borderRadius: 6, fontSize: 12, fontWeight: 600, cursor: "pointer", minWidth: 36 } : { border: "1px solid rgba(255,255,255,0.2)", background: "rgba(255,255,255,0.06)", color: "rgba(255,255,255,0.8)", padding: "4px 10px", borderRadius: 6, fontSize: 12, fontWeight: 600, cursor: "pointer", minWidth: 36 };
246
+ return active ? { border: "1px solid #6366f1", background: "#6366f1", color: "#fff", padding: "4px 10px", borderRadius: 6, fontSize: 12, fontWeight: 600, cursor: "pointer" } : { border: "1px solid rgba(255,255,255,0.2)", background: "rgba(255,255,255,0.06)", color: "rgba(255,255,255,0.8)", padding: "4px 10px", borderRadius: 6, fontSize: 12, fontWeight: 600, cursor: "pointer" };
247
+ }
248
+ function SectionLabel({ children }) {
249
+ return /* @__PURE__ */ jsx("div", { style: { fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 6, color: "rgba(255,255,255,0.35)" }, children });
250
+ }
251
+ function Hint({ children }) {
252
+ return /* @__PURE__ */ jsx("p", { style: { marginTop: 5, fontSize: 11, color: "rgba(255,255,255,0.4)", lineHeight: 1.5 }, children });
216
253
  }
217
- function Toggle({ checked, onToggle, label }) {
218
- return /* @__PURE__ */ jsxs("div", { style: { display: "inline-flex", alignItems: "center", gap: 8, cursor: "pointer", userSelect: "none" }, onClick: onToggle, children: [
219
- /* @__PURE__ */ jsx("span", { style: { position: "relative", display: "inline-block", width: 32, height: 18, borderRadius: 9, flexShrink: 0, cursor: "pointer", background: checked ? "#6366f1" : "rgba(255,255,255,0.15)", transition: "background 150ms" }, children: /* @__PURE__ */ jsx("span", { style: { position: "absolute", top: 2, left: checked ? 16 : 2, width: 14, height: 14, borderRadius: "50%", background: "#fff", boxShadow: "0 1px 3px rgba(0,0,0,.3)", transition: "left 150ms" } }) }),
220
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12, fontWeight: 500, color: "rgba(255,255,255,0.85)" }, children: label })
254
+ function Warning({ children }) {
255
+ return /* @__PURE__ */ jsx("div", { style: { marginTop: 5, display: "flex", gap: 5, background: "rgba(251,191,36,0.08)", border: "1px solid rgba(251,191,36,0.2)", borderRadius: 6, padding: "5px 8px" }, children: /* @__PURE__ */ jsxs("span", { style: { fontSize: 11, color: "#fbbf24", lineHeight: 1.5 }, children: [
256
+ "\u26A0 ",
257
+ children
258
+ ] }) });
259
+ }
260
+ function Toggle({ checked, onToggle, label, hint }) {
261
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: 8, cursor: "pointer", userSelect: "none" }, onClick: onToggle, children: [
262
+ /* @__PURE__ */ jsx("span", { style: { position: "relative", display: "inline-block", width: 32, height: 18, borderRadius: 9, flexShrink: 0, marginTop: 1, background: checked ? "#6366f1" : "rgba(255,255,255,0.15)", transition: "background 150ms" }, children: /* @__PURE__ */ jsx("span", { style: { position: "absolute", top: 2, left: checked ? 16 : 2, width: 14, height: 14, borderRadius: "50%", background: "#fff", boxShadow: "0 1px 3px rgba(0,0,0,.3)", transition: "left 150ms" } }) }),
263
+ /* @__PURE__ */ jsxs("div", { children: [
264
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12, fontWeight: 500, color: "rgba(255,255,255,0.85)" }, children: label }),
265
+ hint && /* @__PURE__ */ jsx("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.4)", marginTop: 1, lineHeight: 1.4 }, children: hint })
266
+ ] })
221
267
  ] });
222
268
  }
223
269
  function VideoOptions({ value, onChange, style }) {
270
+ const [advanced, setAdvanced] = useState(false);
224
271
  const codec = value.codec ?? "h264";
225
272
  const transcoding = value.transcoding ?? "auto";
226
273
  const isAuto = transcoding === "auto";
227
274
  const selectedRes = isAuto ? [] : transcoding;
228
- const selectedCodec = CODECS.find((c) => c.value === codec) ?? CODECS[0];
275
+ const audioCodec = value.audioCodec ?? "passthrough";
276
+ const audioChannels = value.audioChannels ?? "original";
277
+ const preserveAtmos = value.preserveAtmos ?? true;
278
+ const hdrMode = value.hdr ?? "preserve";
279
+ const selectedVideoCodec = VIDEO_CODECS.find((c) => c.value === codec);
229
280
  function toggleRes(r) {
230
281
  if (isAuto) {
231
282
  onChange({ ...value, transcoding: [r] });
@@ -234,13 +285,12 @@ function VideoOptions({ value, onChange, style }) {
234
285
  const next = selectedRes.includes(r) ? selectedRes.filter((x) => x !== r) : [...selectedRes, r];
235
286
  onChange({ ...value, transcoding: next.length === 0 ? "auto" : next });
236
287
  }
237
- function toggleFeature(key) {
238
- onChange({ ...value, [key]: !value[key] });
239
- }
240
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", style, children: [
288
+ const showAtmosOption = audioCodec === "eac3" || audioCodec === "passthrough";
289
+ const showAtmosWarning = audioCodec === "aac" || audioCodec === "opus" || audioCodec === "ac3";
290
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", style, children: [
241
291
  /* @__PURE__ */ jsxs("div", { children: [
242
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 6, color: "rgba(255,255,255,0.4)" }, children: "Codec de v\xEDdeo" }),
243
- /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 flex-wrap", children: CODECS.map((c) => /* @__PURE__ */ jsx(
292
+ /* @__PURE__ */ jsx(SectionLabel, { children: "Codec de v\xEDdeo" }),
293
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 flex-wrap", children: VIDEO_CODECS.map((c) => /* @__PURE__ */ jsx(
244
294
  "button",
245
295
  {
246
296
  type: "button",
@@ -250,38 +300,117 @@ function VideoOptions({ value, onChange, style }) {
250
300
  },
251
301
  c.value
252
302
  )) }),
253
- /* @__PURE__ */ jsx("div", { style: { marginTop: 6, fontSize: 11, color: "rgba(255,255,255,0.45)", lineHeight: 1.5 }, children: selectedCodec.description }),
254
- selectedCodec.warning && /* @__PURE__ */ jsx("div", { style: { marginTop: 5, display: "flex", alignItems: "flex-start", gap: 5, background: "rgba(251,191,36,0.08)", border: "1px solid rgba(251,191,36,0.2)", borderRadius: 6, padding: "5px 8px" }, children: /* @__PURE__ */ jsxs("span", { style: { fontSize: 11, color: "#fbbf24", lineHeight: 1.5 }, children: [
255
- "\u26A0 ",
256
- selectedCodec.warning
257
- ] }) })
303
+ selectedVideoCodec && /* @__PURE__ */ jsx(Hint, { children: selectedVideoCodec.description }),
304
+ selectedVideoCodec?.warning && /* @__PURE__ */ jsx(Warning, { children: selectedVideoCodec.warning })
258
305
  ] }),
259
306
  /* @__PURE__ */ jsxs("div", { children: [
260
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 6, color: "rgba(255,255,255,0.4)" }, children: "Resolu\xE7\xF5es" }),
307
+ /* @__PURE__ */ jsx(SectionLabel, { children: "Resolu\xE7\xF5es" }),
261
308
  /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 flex-wrap", children: [
262
309
  /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onChange({ ...value, transcoding: "auto" }), style: optBtnStyle(isAuto), children: "Auto" }),
263
- RESOLUTIONS.map((r) => /* @__PURE__ */ jsx(
310
+ RESOLUTIONS.map((r) => /* @__PURE__ */ jsx("button", { type: "button", onClick: () => toggleRes(r), style: optBtnStyle(!isAuto && selectedRes.includes(r)), children: RESOLUTION_LABELS[r] }, r))
311
+ ] }),
312
+ isAuto && /* @__PURE__ */ jsx(Hint, { children: "Gera todas as resolu\xE7\xF5es at\xE9 a resolu\xE7\xE3o original do v\xEDdeo." })
313
+ ] }),
314
+ !advanced && /* @__PURE__ */ jsxs(Fragment, { children: [
315
+ /* @__PURE__ */ jsxs("div", { children: [
316
+ /* @__PURE__ */ jsx(SectionLabel, { children: "\xC1udio" }),
317
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 flex-wrap", children: AUDIO_SIMPLE.map((a) => /* @__PURE__ */ jsxs(
318
+ "button",
319
+ {
320
+ type: "button",
321
+ onClick: () => onChange({ ...value, audioCodec: a.value }),
322
+ style: optBtnStyle(audioCodec === a.value),
323
+ children: [
324
+ a.label,
325
+ "badge" in a && a.badge ? /* @__PURE__ */ jsx("span", { style: { marginLeft: 5, fontSize: 9, fontWeight: 700, background: "rgba(255,255,255,0.15)", borderRadius: 4, padding: "1px 4px", verticalAlign: "middle" }, children: a.badge }) : null
326
+ ]
327
+ },
328
+ a.value
329
+ )) }),
330
+ /* @__PURE__ */ jsx(Hint, { children: AUDIO_SIMPLE.find((a) => a.value === audioCodec)?.description })
331
+ ] }),
332
+ /* @__PURE__ */ jsxs("div", { children: [
333
+ /* @__PURE__ */ jsx(SectionLabel, { children: "HDR" }),
334
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsx(
335
+ Toggle,
336
+ {
337
+ checked: hdrMode === "preserve",
338
+ onToggle: () => onChange({ ...value, hdr: hdrMode === "preserve" ? "sdr" : "preserve" }),
339
+ label: "Preservar HDR",
340
+ hint: "Mant\xE9m HDR10, HDR10+, HLG e Dolby Vision quando o codec de sa\xEDda suporta (H.265 e AV1). Ignorado para H.264."
341
+ }
342
+ ) })
343
+ ] })
344
+ ] }),
345
+ advanced && /* @__PURE__ */ jsxs(Fragment, { children: [
346
+ /* @__PURE__ */ jsxs("div", { children: [
347
+ /* @__PURE__ */ jsx(SectionLabel, { children: "Codec de \xE1udio" }),
348
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 flex-wrap", children: AUDIO_ADVANCED_CODEC.map((a) => /* @__PURE__ */ jsx(
264
349
  "button",
265
350
  {
266
351
  type: "button",
267
- onClick: () => toggleRes(r),
268
- style: optBtnStyle(!isAuto && selectedRes.includes(r)),
269
- children: RESOLUTION_LABELS[r]
352
+ onClick: () => onChange({ ...value, audioCodec: a.value }),
353
+ style: optBtnStyle(audioCodec === a.value),
354
+ children: a.label
270
355
  },
271
- r
272
- ))
356
+ a.value
357
+ )) }),
358
+ /* @__PURE__ */ jsx(Hint, { children: AUDIO_ADVANCED_CODEC.find((a) => a.value === audioCodec)?.description }),
359
+ showAtmosWarning && /* @__PURE__ */ jsx(Warning, { children: "Este codec n\xE3o preserva Dolby Atmos. Use E-AC3 ou Original para manter Atmos." })
273
360
  ] }),
274
- isAuto && /* @__PURE__ */ jsx("div", { style: { marginTop: 6, fontSize: 11, color: "rgba(255,255,255,0.35)", lineHeight: 1.5 }, children: "Modo autom\xE1tico: gera todas as resolu\xE7\xF5es at\xE9 a resolu\xE7\xE3o original do v\xEDdeo." })
361
+ /* @__PURE__ */ jsxs("div", { children: [
362
+ /* @__PURE__ */ jsx(SectionLabel, { children: "Canais" }),
363
+ /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 flex-wrap", children: AUDIO_CHANNELS.map((c) => /* @__PURE__ */ jsx(
364
+ "button",
365
+ {
366
+ type: "button",
367
+ onClick: () => onChange({ ...value, audioChannels: c.value }),
368
+ style: optBtnStyle(audioChannels === c.value),
369
+ children: c.label
370
+ },
371
+ c.value
372
+ )) }),
373
+ /* @__PURE__ */ jsx(Hint, { children: AUDIO_CHANNELS.find((c) => c.value === audioChannels)?.description })
374
+ ] }),
375
+ showAtmosOption && /* @__PURE__ */ jsxs("div", { children: [
376
+ /* @__PURE__ */ jsx(SectionLabel, { children: "Atmos" }),
377
+ /* @__PURE__ */ jsx(
378
+ Toggle,
379
+ {
380
+ checked: preserveAtmos,
381
+ onToggle: () => onChange({ ...value, preserveAtmos: !preserveAtmos }),
382
+ label: "Preservar Dolby Atmos quando dispon\xEDvel",
383
+ hint: "Mant\xE9m os metadados Atmos no E-AC3 de sa\xEDda. Efetivo somente com codec E-AC3 ou Original."
384
+ }
385
+ )
386
+ ] }),
387
+ /* @__PURE__ */ jsxs("div", { children: [
388
+ /* @__PURE__ */ jsx(SectionLabel, { children: "HDR" }),
389
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 flex-wrap", children: [
390
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onChange({ ...value, hdr: "preserve" }), style: optBtnStyle(hdrMode === "preserve"), children: "Preservar HDR" }),
391
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onChange({ ...value, hdr: "sdr" }), style: optBtnStyle(hdrMode === "sdr"), children: "Converter para SDR" })
392
+ ] }),
393
+ /* @__PURE__ */ jsx(Hint, { children: hdrMode === "preserve" ? "HDR10, HDR10+, HLG e Dolby Vision s\xE3o preservados com H.265 e AV1. H.264 ignora HDR." : "Tonemapping para SDR \u2014 compat\xEDvel com todos os displays." })
394
+ ] })
275
395
  ] }),
276
396
  /* @__PURE__ */ jsxs("div", { children: [
277
- /* @__PURE__ */ jsx("div", { style: { fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 8, color: "var(--silo-text-muted)" }, children: "Recursos" }),
278
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
279
- /* @__PURE__ */ jsx(Toggle, { checked: value.thumbnails ?? true, onToggle: () => toggleFeature("thumbnails"), label: "Gerar thumbnails" }),
280
- /* @__PURE__ */ jsx(Toggle, { checked: value.storyboard ?? false, onToggle: () => toggleFeature("storyboard"), label: "Gerar storyboard" }),
281
- /* @__PURE__ */ jsx(Toggle, { checked: value.autoCaptions ?? false, onToggle: () => toggleFeature("autoCaptions"), label: "Legendas autom\xE1ticas (IA)" }),
282
- /* @__PURE__ */ jsx(Toggle, { checked: value.separateAudio ?? false, onToggle: () => toggleFeature("separateAudio"), label: "Separar faixa de \xE1udio" })
397
+ /* @__PURE__ */ jsx(SectionLabel, { children: "Recursos" }),
398
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5", children: [
399
+ /* @__PURE__ */ jsx(Toggle, { checked: value.thumbnails ?? true, onToggle: () => onChange({ ...value, thumbnails: !(value.thumbnails ?? true) }), label: "Gerar thumbnails" }),
400
+ /* @__PURE__ */ jsx(Toggle, { checked: value.storyboard ?? false, onToggle: () => onChange({ ...value, storyboard: !value.storyboard }), label: "Gerar storyboard" }),
401
+ /* @__PURE__ */ jsx(Toggle, { checked: value.autoCaptions ?? false, onToggle: () => onChange({ ...value, autoCaptions: !value.autoCaptions }), label: "Legendas autom\xE1ticas (IA)" }),
402
+ /* @__PURE__ */ jsx(Toggle, { checked: value.separateAudio ?? false, onToggle: () => onChange({ ...value, separateAudio: !value.separateAudio }), label: "Separar faixa de \xE1udio" })
283
403
  ] })
284
- ] })
404
+ ] }),
405
+ /* @__PURE__ */ jsx(
406
+ "button",
407
+ {
408
+ type: "button",
409
+ onClick: () => setAdvanced((v) => !v),
410
+ style: { alignSelf: "flex-start", fontSize: 11, color: "rgba(255,255,255,0.35)", background: "none", border: "none", cursor: "pointer", padding: 0, textDecoration: "underline", textUnderlineOffset: 3 },
411
+ children: advanced ? "\u2190 Modo simples" : "Op\xE7\xF5es avan\xE7adas \u2192"
412
+ }
413
+ )
285
414
  ] });
286
415
  }
287
416