diff --git a/apps/web/src/lib/guideLinks.ts b/apps/web/src/lib/guideLinks.ts index e5d43393..34f5657c 100644 --- a/apps/web/src/lib/guideLinks.ts +++ b/apps/web/src/lib/guideLinks.ts @@ -99,7 +99,7 @@ export const GUIDE_SECTIONS = { sketchCurve: { chapter: "sketches", de: "eine-gerade-seite-kruemmen", en: "curving-a-straight-side", nl: "een-rechte-zijde-buigen", ru: "izgib-pryamoy-storony", cs: "prohnuti-prime-strany", sl: "ukrivljanje-ravne-stranice", hu: "egyenes-oldal-goerbitese", es: "curvar-un-lado-recto" }, commandSearch: { chapter: "shortcuts", de: "befehlssuche", en: "command-search", nl: "opdrachten-zoeken", ru: "poisk-komand", cs: "vyhledavani-prikazu", sl: "iskanje-ukazov", hu: "parancskereso", es: "busqueda-de-comandos" }, interactiveHelp: { chapter: "shortcuts", de: "interaktive-hilfe", en: "interactive-help", nl: "interactieve-hulp", fr: "aide-interactive", ru: "interaktivnaya-spravka", cs: "interaktivni-napoveda", sl: "interaktivna-pomoc", es: "ayuda-interactiva" }, - whatsNew: { chapter: "start", de: "neu-seit-deinem-letzten-besuch", en: "new-since-your-last-visit", nl: "nieuw-sinds-je-laatste-bezoek", ru: "novoe-s-vashego-poslednego-vizita", cs: "novinky-od-posledni-navstevy", sl: "novo-od-tvojega-zadnjega-obiska", hu: "ujdonsagok-a-legutobbi-latogatasod-ota", es: "novedades-desde-tu-ultima-visita" }, + whatsNew: { chapter: "start", de: "neu-seit-deinem-letzten-besuch", en: "new-since-your-last-visit", nl: "nieuw-sinds-je-laatste-bezoek", "pt-br": "novidades-desde-a-sua-ultima-visita", ru: "novoe-s-vashego-poslednego-vizita", cs: "novinky-od-posledni-navstevy", sl: "novo-od-tvojega-zadnjega-obiska", hu: "ujdonsagok-a-legutobbi-latogatasod-ota", es: "novedades-desde-tu-ultima-visita" }, } as const satisfies Record>>; export type GuideSection = keyof typeof GUIDE_SECTIONS; diff --git a/docs/guide/pt-br/01-getting-started.md b/docs/guide/pt-br/01-getting-started.md new file mode 100644 index 00000000..a77e69e0 --- /dev/null +++ b/docs/guide/pt-br/01-getting-started.md @@ -0,0 +1,114 @@ +--- +title: Primeiros passos +summary: Da folha em branco à sua primeira peça para a impressora 3D, em cinco minutos, sem conta e sem instalar nada. +--- + +layerling é um programa de modelagem para impressão 3D que roda direto no seu navegador. Você monta uma peça a partir de formas simples, abre furos nela, arredonda as arestas e manda para o seu fatiador. Não há nada para instalar nem cadastro para fazer. O que você cria fica no seu computador. + +![A página inicial do layerling: "Criar novo projeto 3D" no topo, seus projetos e o guia rápido abaixo.](shot:start-page) + +## Criando um projeto + +Abra [layerling.com](https://layerling.com/). Na página inicial, clique em {{ui:dashboard.createDesign}}. O editor abre com um plano de trabalho vazio, a grade sobre a qual tudo toma forma. + +Se você já tem um arquivo para continuar, use {{ui:dashboard.importGeometry}}. Isso funciona tanto para projetos do layerling (`.lyl`) quanto para arquivos STL, OBJ, 3MF, STEP ou SVG. + +Depois, todos os seus projetos aparecem na página inicial com uma miniatura. Eles ficam guardados no seu navegador e são salvos automaticamente a cada alteração, por isso não há botão de salvar. **layerling não se responsabiliza pelos projetos guardados no navegador.** Um navegador pode falhar, ou uma atualização pode causar problemas, então faça backup dos seus projetos de vez em quando com {{ui:dashboard.backupAll}} na página inicial, ou salve-os como arquivos. Para restaurar um backup, use {{ui:dashboard.restoreBackup}}. Como juntar projetos num arquivo e passá-los adiante está em [Arquivos e salvamento](chapter:files-and-saving). + +## Conhecendo o editor + +![O editor com duas formas no plano de trabalho. A barra de opções no topo, os controles da câmera à esquerda, as configurações da forma selecionada à direita.](shot:editor-overview) + +- **No topo** fica a barra de opções. Ela é organizada por tarefa: {{ui:editor.group.clipboard}}, {{ui:editor.group.history}}, {{ui:editor.group.shapes}}, {{ui:editor.group.visibility}}, {{ui:editor.group.combine}}, {{ui:editor.group.modify}}, {{ui:editor.group.arrange}}, {{ui:editor.group.manage}} e {{ui:editor.group.help}}. Passe o mouse sobre um ícone para ver o nome dele. O pequeno ponto de interrogação, por exemplo nas configurações de uma forma, na biblioteca de formas ou nos painéis de ferramentas, leva direto ao capítulo correspondente deste guia. +- **No centro** fica o plano de trabalho. É aqui que você posiciona as formas, dá forma a elas e vê o resultado. +- **À direita** fica o **painel de propriedades**, com as configurações da forma selecionada: cor, dimensões, posição e tudo o mais que compõe a forma. Digitar números é mais exato do que arrastar. +- **À esquerda** ficam os controles da câmera, com o cubo de visualização acima deles. Eles levam você pela cena; mais em [Vista e plano de trabalho](chapter:view-and-workplane). +- **Bem no topo** você alterna entre {{ui:editor.modeGeometry}} e {{ui:editor.modeSketch}}, renomeia o projeto e escolhe o idioma e o tema de cores. + +## Os botões em volta da área de trabalho + +Passe o mouse sobre um botão para ver o nome dele. Se não tiver certeza do que um botão faz, clique em {{ui:interactiveHelp.title}} na área {{ui:editor.group.help}} ([[Shift]]+[[F1]]) e depois no botão. Estes são os botões que mais geram perguntas. + +### Colar + +{{ui:editor.tool.paste}} ([[Ctrl]]+[[V]]) adiciona ao projeto o que você copiou com {{ui:editor.tool.copy}}. {{ui:common.duplicate}} copia e cola num só passo. + +### Excluir + +{{ui:common.delete}} ([[Delete]]) remove as formas selecionadas. {{ui:editor.tool.undo}} as traz de volta. + +### Desagrupar + +{{ui:editor.tool.ungroup}} ([[Ctrl]]+[[Shift]]+[[G]]) desfaz o grupo de união selecionado, separando as formas que o compõem. + +### Configurações da área de trabalho + +{{ui:editor.workspaceSettings}} abre as configurações da área de trabalho: unidade, tamanho da mesa, impressora, grade, cores, luz e mais. Mais em [Vista e plano de trabalho](chapter:view-and-workplane). + +### Tema + +{{ui:common.theme}}, bem no topo, escolhe a aparência do layerling: igual ao sistema, claro, escuro ou grafite. + +### Renomear projeto + +{{ui:editor.renameProject}}: o lápis ao lado do nome, bem no topo. Digite o novo nome e pressione [[Enter]]. + +### Nome do projeto + +O nome do projeto ({{ui:confirm.projectName}}) fica bem no topo. Clique nele, digite, e [[Enter]] mantém o nome. + +### Opções de visibilidade + +Em {{ui:editor.visibilityOptions}}, na seta ao lado do ícone de olho, você encontra o que pode mostrar ou ocultar: a lista de objetos, tudo o que você ocultou, as anotações e as saliências da impressão. Mais em [Selecionar e organizar](chapter:select-and-arrange). + +### Ocultar selecionados + +{{ui:editor.tool.hideSelected}} ([[Ctrl]]+[[H]]) oculta as formas selecionadas. Elas continuam no projeto e na lista de objetos; {{ui:editor.visibilityOptions}} as mostram de novo. + +### Pesquisar comandos + +{{ui:palette.open}}: digite o que você procura, uma ferramenta, uma forma ou uma configuração, e clique no resultado. + +### Ocultar controles da câmera + +{{ui:camera.hide}} recolhe os controles da câmera à esquerda e dá mais espaço à área de trabalho; {{ui:camera.show}} os traz de volta. + +### Grade de encaixe + +{{ui:inspector.snapGrid}}, no fim do painel de propriedades, define o incremento usado ao mover e redimensionar as formas. Ao lado, a pequena chave **mm | in** troca a unidade. Mais em [Vista e plano de trabalho](chapter:view-and-workplane). + +### Unidade: milímetros ou polegadas + +A chave **mm | in** ao lado de {{ui:inspector.snapGrid}} troca a unidade, a grade da mesa e o incremento de encaixe, para este projeto. + +### Rodapé + +No rodapé você encontra: {{ui:dashboard.sponsor}}, que leva à página onde você pode apoiar o projeto; {{ui:dashboard.userGuide}}, que abre este guia; {{ui:dashboard.forum}}, o lugar para perguntas, ideias e relatos de erros (as discussões no GitHub; em alemão, o fórum do drucktipps3d); {{ui:editor.bugReport}}, que cria um ZIP para um relato de erro; {{ui:dashboard.projectOnGitHub}}, que leva ao projeto no GitHub; e o número da versão, que abre as notas da versão. Os links para as informações legais e a política de privacidade são de quem mantém a cópia do layerling que você usa. + +## Sua primeira peça + +Por exemplo, vamos montar um cubo com um furo. + +1. Clique em {{ui:editor.addShape}} na barra de opções e escolha {{ui:shape.box}}. A forma agora fica presa ao ponteiro do mouse. Um clique no plano de trabalho a coloca ali. +2. No painel de propriedades, defina as dimensões, por exemplo 40 mm de comprimento, 40 mm de largura e 20 mm de altura. +3. Coloque um {{ui:shape.cylinder}} no centro do mesmo jeito, com 14 mm de diâmetro e 30 mm de altura. Ele deve ser mais alto que o cubo, para atravessá-lo de ponta a ponta. +4. Selecione o cilindro e clique em {{ui:inspector.hole}} no painel de propriedades. Ele fica transparente: o sólido virou uma ferramenta que tira material. +5. Selecione as duas formas e clique em {{ui:editor.tool.group}}. Agora o cubo tem um furo. + +![O cilindro é um orifício e sai pelo topo do cubo.](shot:hole-before) + +![Depois do agrupamento, o cubo tem um furo.](shot:hole-after) + +É assim que se fazem furos, rasgos e cavidades. O capítulo [Sólidos e orifícios](chapter:solids-and-holes) explica isso em detalhes. + +## Novidades desde a sua última visita + +Quando você abre o layerling de novo depois de uma atualização, um cartão na página inicial lista o que foi adicionado desde a sua última visita: cada versão desde então, a mais nova primeiro. Depois de muito tempo fora, você rola dentro do cartão. Abaixo delas, {{ui:whatsNew.earlier}} acrescenta também as versões de antes da sua última visita. Feche o cartão com {{ui:whatsNew.dismiss}} e ele não aparece mais até a próxima atualização. {{ui:whatsNew.footerLink}}, no rodapé da página inicial, mostra as últimas novidades de novo a qualquer momento. O navegador lembra a última versão que você viu, e nada sobre você sai dele. + +Numa cópia do layerling no seu próprio computador ou servidor, o aviso "Atualização disponível" tem um botão, {{ui:update.previewShow}}, que lista o que a atualização traz antes de você instalá-la. A lista só é buscada no GitHub quando você clica no botão. + +## Do projeto à impressão + +Quando a peça estiver pronta, clique em {{ui:editor.export}}, escolha STL ou 3MF e baixe o arquivo. Abra-o no seu fatiador, por exemplo Bambu Studio, PrusaSlicer, OrcaSlicer ou Cura. Se você escolher sua impressora nas configurações, dá para ver enquanto modela se a peça cabe na mesa de impressão. Mais em [Impressão](chapter:printing). + +> **Dica:** Se você vem do Tinkercad, vai se achar rapidinho: a mesa, as formas, sólido e orifício, agrupar, alinhar e espelhar funcionam quase igual. O que é novo é principalmente chanfro e arredondamento, vazar, roscas e esboços. diff --git a/tests/unit/guideAllLanguages.test.ts b/tests/unit/guideAllLanguages.test.ts index 32a09476..f448103a 100644 --- a/tests/unit/guideAllLanguages.test.ts +++ b/tests/unit/guideAllLanguages.test.ts @@ -1,8 +1,9 @@ import { readdirSync, statSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; +import { GUIDE_SECTIONS, guideHref, type GuideSection } from "@/lib/guideLinks"; // @ts-expect-error the guide build is a plain .mjs module -import { headingIds, loadMessages, loadValues, readChapters, renderBlocks } from "../../scripts/build-guide.mjs"; +import { effectiveChapters, headingIds, loadMessages, loadValues, readChapters, renderBlocks } from "../../scripts/build-guide.mjs"; // @ts-expect-error the tool list is a plain .mjs module import { tools } from "../../scripts/layerling-mcp-tools.mjs"; @@ -16,11 +17,13 @@ const root = join(__dirname, "..", ".."); const guideRoot = join(root, "docs", "guide"); const LANGUAGES = readdirSync(guideRoot).filter((name) => name !== "images" && statSync(join(guideRoot, name)).isDirectory()); -type Chapter = { file: string; number: string; body: string }; +type Chapter = { file: string; number: string; slug: string; body: string }; + +const AI_CHAPTER_NUMBER = "14"; describe("the guide in every language", () => { - it("covers the twelve guide languages", () => { - expect(LANGUAGES.sort()).toEqual(["ar", "cs", "da", "de", "en", "es", "fr", "hu", "nl", "pl", "ru", "sl"]); + it("covers the thirteen guide languages", () => { + expect(LANGUAGES.sort()).toEqual(["ar", "cs", "da", "de", "en", "es", "fr", "hu", "nl", "pl", "pt-br", "ru", "sl"]); }); it("writes headings with a plain space, so they render as headings", async () => { @@ -50,11 +53,22 @@ describe("the guide in every language", () => { } }); - it("names every MCP tool in the AI chapter", async () => { + it("names every MCP tool in the AI chapter each language builds", async () => { + const chaptersByLanguage = Object.fromEntries(await Promise.all(LANGUAGES.map(async (language) => [language, await readChapters(language)]))); for (const language of LANGUAGES) { - const chapter = ((await readChapters(language)) as Chapter[]).find((entry) => entry.number === "14"); - expect(chapter, language).toBeDefined(); - for (const tool of tools as { name: string }[]) expect(chapter!.body, `${language}: ${tool.name}`).toContain(`\`${tool.name}\``); + const builtAiChapter = (effectiveChapters(language, chaptersByLanguage) as Chapter[]).find((entry) => entry.number === AI_CHAPTER_NUMBER); + expect(builtAiChapter, language).toBeDefined(); + for (const tool of tools as { name: string }[]) expect(builtAiChapter!.body, `${language}: ${tool.name}`).toContain(`\`${tool.name}\``); + } + }); + + it("lands every question mark on a heading of the Brazilian Portuguese chapters translated so far", async () => { + const translatedChapters = (await readChapters("pt-br")) as Chapter[]; + for (const sectionName of Object.keys(GUIDE_SECTIONS) as GuideSection[]) { + const [page, anchor] = guideHref("pt-br", undefined, sectionName).split("#"); + const translatedChapter = translatedChapters.find((chapter) => page.endsWith(`/${chapter.slug}.html`)); + if (!translatedChapter) continue; + expect(headingIds(translatedChapter.body), sectionName).toContain(anchor); } });