diff --git a/.gitignore b/.gitignore index 664a12f27e4..7a19eaec876 100644 --- a/.gitignore +++ b/.gitignore @@ -59,8 +59,11 @@ deploy_key jsdocs/ site/ -# Custom files -docs/pages/CLI.md - -# Needed for packages/server & packages/project -!**/test/fixtures/**/node_modules \ No newline at end of file +# Needed for packages/server +!packages/**/test/fixtures/**/node_modules + +# Documentation +packages/documentation/docs/pages/CLI.md +packages/documentation/.vitepress/dist +packages/documentation/.vitepress/cache +packages/documentation/dist diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index 515ba010b7f..00000000000 --- a/mkdocs.yml +++ /dev/null @@ -1,92 +0,0 @@ -site_name: UI5 CLI -site_url: 'https://ui5.github.io/cli/' # required for working 404 page -repo_name: 'UI5/cli' -repo_url: 'https://github.com/UI5/cli' -edit_uri: ./edit/main/docs # default points to "master" branch -docs_dir: 'docs' # default -site_dir: 'site' # default -copyright: '© Copyright 2025, SAP SE and UI5 CLI Contributors' -nav: - - Home: index.md - - Getting Started: pages/GettingStarted.md - - UI5 CLI: pages/CLI.md - - Configuration: pages/Configuration.md - - Development: - - Overview: pages/Overview.md - - OpenUI5: pages/OpenUI5.md - - SAPUI5: pages/SAPUI5.md - - Workspace: pages/Workspace.md - - Extensibility: - - Custom Tasks: pages/extensibility/CustomTasks.md - - Custom Server Middleware: pages/extensibility/CustomServerMiddleware.md - - Project Shims: pages/extensibility/ProjectShims.md - - Modules: - - Server: pages/Server.md - - Builder: pages/Builder.md - - Project: pages/Project.md - - File System: pages/FileSystem.md - - Upgrade Guides: - - Migrate to v4: updates/migrate-v4.md - - Migrate to v3: updates/migrate-v3.md - - Migrate to v2: updates/migrate-v2.md - - Migrate to v1: updates/migrate-v1.md - - FAQ: pages/FAQ.md - - Miscellaneous: - - Troubleshooting: pages/Troubleshooting.md - - Benchmarking: pages/Benchmarking.md - - ECMAScript Support: pages/ESSupport.md - - Code Analysis: pages/CodeAnalysis.md - - API Reference: 'api/index.html' # only available in final build, not serve - -theme: - name: 'material' - custom_dir: 'overrides' - palette: - primary: 'blue' - accent: 'blue' - logo: 'images/logo.svg' - favicon: 'images/favicon.png' - font: false - features: - - navigation.expand - -extra_css: - - 'stylesheets/extra.css' - -extra: - version: - provider: mike - -plugins: - - search - - minify: - minify_html: true - - mike: - canonical_version: null - version_selector: true - css_dir: stylesheets - javascript_dir: js - -markdown_extensions: - - admonition - - attr_list - - codehilite: - guess_lang: false - - toc: - permalink: true - # PyMdown Extensions Documentation: https://facelessuser.github.io/pymdown-extensions/extensions/betterem/ - - pymdownx.betterem: - smart_enable: all - - pymdownx.details - - pymdownx.inlinehilite - - pymdownx.magiclink - - pymdownx.mark - - pymdownx.keys - - pymdownx.smartsymbols - - pymdownx.tabbed: - alternate_style: true - - pymdownx.superfences - - pymdownx.tasklist: - custom_checkbox: true - - pymdownx.tilde - - pymdownx.caret diff --git a/overrides/partials/footer.html b/overrides/partials/footer.html deleted file mode 100644 index 0be1a43854f..00000000000 --- a/overrides/partials/footer.html +++ /dev/null @@ -1,58 +0,0 @@ -{#- - This file was initialy copied from https://github.com/squidfunk/mkdocs-material/blob/-/material/partials/footer.html - and adjusted to offer a customized footer according to the SAP Web Presence Policy. - See also the corresponding stylesheet content in /docs/stylesheets/extra.css. --#} - diff --git a/package.json b/package.json index c770b1f7139..b07efce20fc 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,6 @@ "jsdoc-generate": "node ./scripts/isWorkspace.js && npm run jsdoc-generate-workspace || npm run jsdoc-generate-local", "jsdoc-generate-local": "jsdoc -c ./jsdoc.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ./ || (echo 'Error during JSDoc generation! Check log.' && exit 1)", "jsdoc-generate-workspace": "jsdoc -c ./jsdoc-workspace.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ../ || (echo 'Error during JSDoc generation! Check log.' && exit 1)", - "docs": "bash ./scripts/serveDocs.sh", - "docs-generate": "bash ./scripts/buildDocs.sh && open-cli http://localhost:8000 && ws --compress -d site", "schema-generate": "node ./scripts/buildSchema.js ui5", "schema-workspace-generate": "node ./scripts/buildSchema.js ui5-workspace", "generate-cli-doc": "node ./scripts/generateCliDoc.js", diff --git a/packages/documentation/.vitepress/config.ts b/packages/documentation/.vitepress/config.ts new file mode 100644 index 00000000000..a4fbfcce5f8 --- /dev/null +++ b/packages/documentation/.vitepress/config.ts @@ -0,0 +1,283 @@ +// using the defineConfig helper will provide TypeScript-powered +// intellisense for config options +import { defineConfig } from "vitepress"; + +// markdown +import MarkdownItImplicitFigures from "markdown-it-implicit-figures"; + +export default defineConfig({ + + base: "/cli/v5/", // GitHub Pages deployment base path + srcDir: "docs", + outDir: "dist", + lang: "en-US", + title: "UI5 CLI", + + description: "An open and modular toolchain to develop state-of-the-art applications based on the UI5 framework.", + lastUpdated: false, // disable git author info + cleanUrls: true, + + vue: { + template: { + compilerOptions: { + // treat all tags with a "ui5-" prefix as custom elements + isCustomElement: (tag: string) => tag.includes("ui5-"), + }, + }, + }, + + + head: [ + [ + "link", + { rel: "icon", type: "image/png", href: "./images/favicon.png" } + + ] + ], + + themeConfig: { + + + logo: { + light: "/images/Logo_B_RGB.png", + dark: "/images/Logo_O_RGB.png" + }, + externalLinkIcon: false, + outline: [1, 3], + + nav: nav(), + + sidebar: { + "/": guide(), + }, + + socialLinks: [ + + { icon: "github", link: "https://github.com/UI5/cli" }, + ], + + footer: { + + message: ` + © Copyright ${new Date().getFullYear()}, SAP SE and UI5 CLI Contributors
+ Legal Disclosure + Terms of Use + Privacy + Trademarks + `, + + + }, + + search: { + provider: "local", + //hotKeys: [], // disable hotkeys to avoid search while using UI5 web components input + }, + + + + }, + + markdown: { + // Configure the Markdown-it instance + config: (md) => { + // https://www.npmjs.com/package/markdown-it-implicit-figures + md.use(MarkdownItImplicitFigures, { + figcaption: true, + }); + }, + }, + + + vite: { + build: { + chunkSizeWarningLimit: 4000, // chunk for local search index dominates + } + } +}); + +function nav() { + return [ + { + + text: 'V5', + items: [ + { + text: 'V4', + link: '../v4/', + target: "_self" + }, + { + text: 'V3', + link: '../v3/', + target: "_self" + }, + { + text: 'V2', + link: '../v2/', + target: "_self" + } + ] + }, + ]; +} + +function guide() { + + return [ + + { + text: "Introduction", + collapsed: false, + + items: [ + + { + text: "Home", + link: "/", + }, + { + text: "Getting Started", + link: "/pages/GettingStarted", + }, + + ], + + }, + { + text: "UI5 CLI", + collapsed: true, + link: "/pages/CLI", + + + }, + { + text: "Configuration", + collapsed: true, + + link: "/pages/Configuration", + + }, + { + text: "Development", + collapsed: false, + items: [ + { + text: "Overview", + link: "/pages/Overview", + }, + { + text: "OpenUI5", + link: "/pages/OpenUI5", + }, + { + text: "SAPUI5", + link: "/pages/SAPUI5", + }, + { + text: "Workspace", + link: "/pages/Workspace", + }, + + ], + }, + + { + text: "Extensibility", + collapsed: false, + items: [ + { + text: "Custom Tasks", + link: "/pages/extensibility/CustomTasks", + }, + { + text: "Custom Server Middleware", + link: "/pages/extensibility/CustomServerMiddleware", + }, + { + text: "Project Shims", + link: "/pages/extensibility/ProjectShims", + }, + ], + }, + { + text: "Modules", + collapsed: false, + items: [ + { + text: "Server", + link: "/pages/Server", + }, + { + text: "Builder", + link: "/pages/Builder", + }, + { + text: "Project", + link: "/pages/Project", + }, + { + text: "File System", + link: "/pages/FileSystem", + }, + ], + }, + { + text: "FAQ", + collapsed: false, + link: "/pages/FAQ", + + }, + { + text: "Upgrade Guides", + collapsed: false, + items: [ + { + text: "Migrate to v4", + link: "/updates/migrate-v4", + }, + { + text: "Migrate to v3", + link: "/updates/migrate-v3", + }, + { + text: "Migrate to v2", + link: "/updates/migrate-v2", + }, + { + text: "Migrate to v1", + link: "/updates/migrate-v1", + }, + ], + }, + { + text: "Miscellaneous", + collapsed: false, + items: [ + { + text: "Troubleshooting", + link: "/pages/Troubleshooting", + }, + { + text: "Benchmarking", + link: "/pages/Benchmarking", + }, + { + text: "ECMAScript Support", + link: "/pages/ESSupport", + }, + { + text: "Code Analysis", + link: "/pages/CodeAnalysis", + }, + ], + }, + { + text: "API Reference", + link: "https://ui5.github.io/cli/api/index.html", + + }, + + ]; +} + diff --git a/packages/documentation/.vitepress/theme/components/Badgen.vue b/packages/documentation/.vitepress/theme/components/Badgen.vue new file mode 100644 index 00000000000..db0dda9a8a0 --- /dev/null +++ b/packages/documentation/.vitepress/theme/components/Badgen.vue @@ -0,0 +1,83 @@ + + + + + \ No newline at end of file diff --git a/packages/documentation/.vitepress/theme/custom.css b/packages/documentation/.vitepress/theme/custom.css new file mode 100644 index 00000000000..e666cba1d66 --- /dev/null +++ b/packages/documentation/.vitepress/theme/custom.css @@ -0,0 +1,303 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + /** + * Colors + * -------------------------------------------------------------------------- */ + :root { + /* Fire */ + --ui5-fire-main: #ff5a37; /* outrageous-orange-400 */ + --ui5-fire-secondary: #ffa42c; /* sunshade-400 */ + --ui5-fire-background: #000000; /* black */ + + /* Water */ + --ui5-water-main: #1873b4; /* denim-600 */ + --ui5-water-secondary: #53b8de; /* viking-400 */ + --ui5-water-background: #ffffff; /* white */ + + /* Tailwind CSS Color Generator + ** https://uicolors.app/create + */ + + /* VP */ + /* The most solid color used mainly for colored text. */ + --vp-c-brand-1: #1873b4; /* lochmara-600 */ + /* The color used mainly for hover state of the button. */ + --vp-c-brand-2: #53b8de; /* lochmara-500 */ + /* The color for solid background, such as bg color of the button. */ + --vp-c-brand-3: #1873b4; /* endeavour-700 */ + /* The color used for subtle background such as custom container or badges. */ + /* The soft color must be semi transparent alpha channel. */ + /*--vp-c-brand-soft: rgba(12, 72, 120, 0.14);*/ /* --brand-dark-blue */ + --vp-c-brand-soft: rgba(3, 103, 161, 0.14); /* lochmara-700 */ + } + .dark { + /* The most solid color used mainly for colored text. */ + --vp-c-brand-1: #ff5a37; /* lochmara-600 */ + /* The color used mainly for hover state of the button. */ + --vp-c-brand-2: #ffa42c; /* lochmara-500 */ + /* The color for solid background, such as bg color of the button. */ + --vp-c-brand-3: #ff5a37; /* endeavour-700 */ + + /* The bg color used for main screen */ + --vp-c-bg: #000000; + /* The alternative bg color used in places such as "sidebar" or "code block". */ + + /* The elevated bg color. This is used at parts where it "floats", such as "dialog". */ + /*--vp-c-bg-elv: red;*/ /* #1d2025;*/ + /* The bg color to slightly ditinguish some components from the page. + ** Used for things like "carbon ads" or "table". + */ + --vp-c-bg-soft: #2b313a; /* 202127 */ + /* This is used for separators. This is used to divide sections within the same components, + ** such as having separator on "h2" heading. + */ + --vp-c-divider: rgba(82,82,89,0.32); /*#2e2e32;*/ + /* This is designed for borders on interactive components. + ** For example this should be used for a button outline. */ + /*--vp-c-border: #3c3f44; */ + /* This is used to divide components in the page. For example the header and the rest of the page. */ + /*--vp-c-gutter: var(--vp-c-bg-alt);*/ /* #000000 */ + --vp-c-gutter: transparent; /* #000000 */ + } + + img { + @apply rounded-md; + } + + /* fix Tailwind default issue for Search button */ + .DocSearch.button, + .DocSearch[type="button"] { + background-color: var(--vp-c-bg-alt); + } +} + +/* Implement udina design language by avoiding repeated utility patterns */ +@layer components { + /* reset vpdoc */ + .vp-doc .u-list-reset { + @apply list-none list-image-none p-0 m-0; + } + + .vp-doc .u-list-reset li + li { + @apply mt-0; + } + + /* Default KBD + ** https://flowbite.com/docs/components/kbd/ + */ + .u-kbd { + @apply px-2 py-1 text-xs font-semibold text-gray-800 bg-gray-50 border border-gray-300 rounded-lg dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500; + } + + /* udina design language */ + .udina { + @apply font-sans font-extrabold; + } + + .u-right-brand { + @apply float-right ml-4 w-12 md:ml-8 md:w-20 lg:w-24; + } + + .u-p-white { + @apply p-2 bg-white; + } + + .u-bar { + @apply flex flex-col md:flex-row md:justify-between md:items-center space-y-2 md:space-y-0; + } + + .u-bar-content { + @apply flex items-center; + } + + .u-bar-singleLineContent { + @apply flex md:items-center flex-col md:flex-row space-y-2 md:space-y-0; + } +} + +/** + * Prototypes + * -------------------------------------------------------------------------- */ + +/* disable anchor undeline */ +.vp-doc a { + text-decoration: none; +} + +.u-pi { + color: transparent; + font-size: 1rem; + transition: all .2s ease-in-out; +} + +.u-pi:hover { + font-size: 2rem; + color: inherit; +} + +/** +* Custom Block +* -------------------------------------------------------------------------- */ +.vp-doc .custom-block { + padding: 16px; +} + +.vp-doc .custom-block.tip { + border-color: var(--vp-c-tip-1); +} + +.vp-doc .custom-block.warning { + border-color: var(--vp-c-warning-1); +} + +.vp-doc .custom-block.danger { + border-color: var(--vp-c-danger-1); +} + +.vp-doc .custom-block:not(.info) { + /*font-size: 95%;*/ + border-width: 0 0 0 7px; +} + +/* allow blue/udina color links in blocks */ +.vp-doc .custom-block a { + color: var(--vp-c-brand); +} + +/* clearfix to avoid overlapping float-right image inside custom block */ +.vp-doc .custom-block:after { + content: ""; + display: table; + clear: both; +} + +/** +* zoom vanilla +* -------------------------------------------------------------------------- */ +img[data-action="zoom"] { + cursor: zoom-in; +} + +.zoom-img, +.zoom-img-wrap { + position: relative; + z-index: 666; + /*z-index: 20;*/ + transition: all 300ms; +} + +img.zoom-img { + cursor: zoom-out; + /* UDINA */ + /*z-index: 21;*/ + /* reset u-right-brand margin-left */ + margin: 0; +} + +.zoom-overlay { + cursor: zoom-out; + z-index: 420; + background: #fff; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + filter: "alpha(opacity=0)"; + opacity: 0; + transition: opacity 300ms; + /* UDINA */ + background-color: var(--vp-c-bg); +} + +.zoom-overlay-open .zoom-overlay { + filter: "alpha(opacity=100)"; + opacity: 1; +} + +/** +* Blockquotes +* -------------------------------------------------------------------------- */ +.udina-quote { + font-family: Georgia, Times, "Times New Roman", serif; + font-size: 1.25em; + font-style: italic; + position: relative; + z-index: 0; +} + +.udina-quote:before { + content: ""; + position: absolute; + top: 50%; + left: -4px; + height: 1em; + background-color: var(--c-bg); + width: 5px; + margin-top: -0.5em; +} + +.udina-quote:after { + content: "“"; + position: absolute; + top: 50%; + left: -0.5em; + color: var(--c-border-dark); + font-size: 2em; + line-height: 2em; + text-align: center; + text-indent: -2px; + width: 0.8em; + margin-top: -0.75em; +} + +.udina-quote cite { + display: block; + font-size: 0.75em; + margin-top: 0.5em; +} + +/** +* Figure (used by markdown-it-figure) +* -------------------------------------------------------------------------- */ +figure { + margin-inline-start: 0; + margin-inline-end: 0; + text-align: center; + text-align: -webkit-center; + margin: 1rem 0; +} + +figcaption { + margin-top: 0.5rem; + font-style: italic; + font-size: small; + text-align: center; + text-align: -webkit-center; +} + +/** +* Learn more +* -------------------------------------------------------------------------- */ +.learn-more { + font-style: italic; + margin-top: -5px; + margin-bottom: 5px; + display: block; +} + +li .learn-more { + margin-top: 0; +} + +.learn-more:before { + content: url(/learn-more.svg); + display: inline-block; + width: 20px; + height: 20px; + margin-right: 5px; + vertical-align: middle; +} diff --git a/packages/documentation/.vitepress/theme/index.ts b/packages/documentation/.vitepress/theme/index.ts new file mode 100644 index 00000000000..82c2a17338e --- /dev/null +++ b/packages/documentation/.vitepress/theme/index.ts @@ -0,0 +1,52 @@ +import DefaultTheme from "vitepress/theme"; +import { EnhanceAppContext } from 'vitepress/dist/client/index.js' +import { useRoute } from "vitepress"; +import { onMounted, watch, nextTick } from "vue"; + +// custom css +import "./custom.css"; + +// global components +import Badgen from "@theme/components/Badgen.vue"; + +export default { + ...DefaultTheme, + + enhanceApp(ctx: EnhanceAppContext) { + // app is the Vue 3 app instance from `createApp()`. + // router is VitePress' custom router. `siteData` is + // a `ref` of current site-level metadata. + + // extend default theme custom behaviour. + DefaultTheme.enhanceApp(ctx); + + // register your custom global components + ctx.app.component("Badgen", Badgen); + }, + + setup() { + // this function will be executed inside VitePressApp's setup hook. + // all composition APIs are available here. + const route = useRoute(); + let initZoom: () => void; + + onMounted(async () => { + // initialize components based on data attribute selectors + //initCarousels(); + + (await import("./mixins/u-zoom-vanilla.js")).default; + initZoom = () => { + // no zoom inside links or disabled by class=".no-zoom" + document.querySelectorAll(".main img:not(a>img):not(.no-zoom)").forEach(el => { + el.setAttribute("data-action", "zoom"); + }); + }; + + initZoom(); + }); + watch( + () => route.path, + () => nextTick(() => initZoom()) + ); + }, +}; diff --git a/packages/documentation/.vitepress/theme/mixins/u-zoom-vanilla.js b/packages/documentation/.vitepress/theme/mixins/u-zoom-vanilla.js new file mode 100644 index 00000000000..b8a9493e835 --- /dev/null +++ b/packages/documentation/.vitepress/theme/mixins/u-zoom-vanilla.js @@ -0,0 +1,265 @@ +export default +function () { + "use strict"; + var OFFSET = 80 + + // From http://youmightnotneedjquery.com/#offset + function offset(element) { + var rect = element.getBoundingClientRect() + var scrollTop = window.pageYOffset || + document.documentElement.scrollTop || + document.body.scrollTop || + 0 + var scrollLeft = window.pageXOffset || + document.documentElement.scrollLeft || + document.body.scrollLeft || + 0 + return { + top: rect.top + scrollTop, + left: rect.left + scrollLeft + } + } + + function zoomListener() { + var activeZoom = null + var initialScrollPosition = null + var initialTouchPosition = null + + function listen() { + document.body.addEventListener('click', function (event) { + if (event.target.getAttribute('data-action') !== 'zoom' || + event.target.tagName !== 'IMG') return + + zoom(event) + }) + } + + function zoom(event) { + event.stopPropagation() + + if (document.body.classList.contains('zoom-overlay-open')) return + + if (event.metaKey || event.ctrlKey) return openInNewWindow() + + closeActiveZoom({ forceDispose: true }) + + activeZoom = vanillaZoom(event.target) + activeZoom.zoomImage() + + addCloseActiveZoomListeners() + } + + function openInNewWindow() { + window.open(event.target.getAttribute('data-original') || + event.target.currentSrc || + event.target.src, + '_blank') + } + + function closeActiveZoom(options) { + options = options || { forceDispose: false } + if (!activeZoom) return + + activeZoom[options.forceDispose ? 'dispose' : 'close']() + removeCloseActiveZoomListeners() + activeZoom = null + } + + function addCloseActiveZoomListeners() { + // todo(fat): probably worth throttling this + window.addEventListener('scroll', handleScroll) + document.addEventListener('click', handleClick) + document.addEventListener('keyup', handleEscPressed) + document.addEventListener('touchstart', handleTouchStart) + document.addEventListener('touchend', handleClick) + } + + function removeCloseActiveZoomListeners() { + window.removeEventListener('scroll', handleScroll) + document.removeEventListener('keyup', handleEscPressed) + document.removeEventListener('click', handleClick) + document.removeEventListener('touchstart', handleTouchStart) + document.removeEventListener('touchend', handleClick) + } + + function handleScroll(event) { + if (initialScrollPosition === null) initialScrollPosition = window.pageYOffset + var deltaY = initialScrollPosition - window.pageYOffset + if (Math.abs(deltaY) >= 40) closeActiveZoom() + } + + function handleEscPressed(event) { + if (event.keyCode == 27) closeActiveZoom() + } + + function handleClick(event) { + event.stopPropagation() + event.preventDefault() + closeActiveZoom() + } + + function handleTouchStart(event) { + initialTouchPosition = event.touches[0].pageY + event.target.addEventListener('touchmove', handleTouchMove) + } + + function handleTouchMove(event) { + if (Math.abs(event.touches[0].pageY - initialTouchPosition) <= 10) return + closeActiveZoom() + event.target.removeEventListener('touchmove', handleTouchMove) + } + + return { listen: listen } + } + + var vanillaZoom = (function () { + var fullHeight = null + var fullWidth = null + var overlay = null + var imgScaleFactor = null + + var targetImage = null + var targetImageWrap = null + var targetImageClone = null + + function zoomImage() { + var img = document.createElement('img') + img.onload = function () { + fullHeight = Number(img.height) + fullWidth = Number(img.width) + zoomOriginal() + } + img.src = targetImage.currentSrc || targetImage.src + } + + function zoomOriginal() { + targetImageWrap = document.createElement('div') + targetImageWrap.className = 'zoom-img-wrap' + targetImageWrap.style.position = 'absolute' + targetImageWrap.style.top = offset(targetImage).top + 'px' + targetImageWrap.style.left = offset(targetImage).left + 'px' + + targetImageClone = targetImage.cloneNode() + targetImageClone.style.visibility = 'hidden' + + targetImage.style.width = targetImage.offsetWidth + 'px' + targetImage.parentNode.replaceChild(targetImageClone, targetImage) + + document.body.appendChild(targetImageWrap) + targetImageWrap.appendChild(targetImage) + + targetImage.classList.add('zoom-img') + targetImage.setAttribute('data-action', 'zoom-out') + + overlay = document.createElement('div') + overlay.className = 'zoom-overlay' + + document.body.appendChild(overlay) + + calculateZoom() + triggerAnimation() + } + + function calculateZoom() { + // UDINA + var maxWidth = window.innerWidth * 0.8 + var ratio = targetImage.width / targetImage.height + var isSVG = targetImage?.src?.endsWith(".svg") + + targetImage.offsetWidth // repaint before animating + + //var originalFullImageWidth = fullWidth + var originalFullImageWidth = (isSVG) ? maxWidth : fullWidth + //var originalFullImageHeight = fullHeight + var originalFullImageHeight = (isSVG) ? maxWidth / ratio : fullHeight + + var maxScaleFactor = originalFullImageWidth / targetImage.width + //var maxScaleFactor = originalFullImageWidth / originalFullImageHeight + + var viewportHeight = window.innerHeight - OFFSET + var viewportWidth = window.innerWidth - OFFSET + + var imageAspectRatio = originalFullImageWidth / originalFullImageHeight + var viewportAspectRatio = viewportWidth / viewportHeight + + if (originalFullImageWidth < viewportWidth && originalFullImageHeight < viewportHeight) { + imgScaleFactor = maxScaleFactor + } else if (imageAspectRatio < viewportAspectRatio) { + imgScaleFactor = (viewportHeight / originalFullImageHeight) * maxScaleFactor + } else { + imgScaleFactor = (viewportWidth / originalFullImageWidth) * maxScaleFactor + } + } + + function triggerAnimation() { + targetImage.offsetWidth // repaint before animating + + var imageOffset = offset(targetImage) + var scrollTop = window.pageYOffset + + var viewportY = scrollTop + (window.innerHeight / 2) + var viewportX = (window.innerWidth / 2) + + var imageCenterY = imageOffset.top + (targetImage.height / 2) + var imageCenterX = imageOffset.left + (targetImage.width / 2) + + var translateY = Math.round(viewportY - imageCenterY) + var translateX = Math.round(viewportX - imageCenterX) + + var targetImageTransform = 'scale(' + imgScaleFactor + ')' + var targetImageWrapTransform = + 'translate(' + translateX + 'px, ' + translateY + 'px) translateZ(0)' + + targetImage.style.webkitTransform = targetImageTransform + targetImage.style.msTransform = targetImageTransform + targetImage.style.transform = targetImageTransform + + targetImageWrap.style.webkitTransform = targetImageWrapTransform + targetImageWrap.style.msTransform = targetImageWrapTransform + targetImageWrap.style.transform = targetImageWrapTransform + + document.body.classList.add('zoom-overlay-open') + } + + function close() { + document.body.classList.remove('zoom-overlay-open') + document.body.classList.add('zoom-overlay-transitioning') + + targetImage.style.webkitTransform = '' + targetImage.style.msTransform = '' + targetImage.style.transform = '' + + targetImageWrap.style.webkitTransform = '' + targetImageWrap.style.msTransform = '' + targetImageWrap.style.transform = '' + + if (!'transition' in document.body.style) return dispose() + + targetImageWrap.addEventListener('transitionend', dispose) + targetImageWrap.addEventListener('webkitTransitionEnd', dispose) + } + + function dispose() { + targetImage.removeEventListener('transitionend', dispose) + targetImage.removeEventListener('webkitTransitionEnd', dispose) + + if (!targetImageWrap || !targetImageWrap.parentNode) return + + targetImage.classList.remove('zoom-img') + targetImage.style.width = '' + targetImage.setAttribute('data-action', 'zoom') + + targetImageClone.parentNode.replaceChild(targetImage, targetImageClone) + targetImageWrap.parentNode.removeChild(targetImageWrap) + overlay.parentNode.removeChild(overlay) + + document.body.classList.remove('zoom-overlay-transitioning') + } + + return function (target) { + targetImage = target + return { zoomImage: zoomImage, close: close, dispose: dispose } + } + }()) + + zoomListener().listen() +}() \ No newline at end of file diff --git a/packages/documentation/docs/images/Logo_B_RGB.png b/packages/documentation/docs/images/Logo_B_RGB.png new file mode 100755 index 00000000000..088e1078b55 Binary files /dev/null and b/packages/documentation/docs/images/Logo_B_RGB.png differ diff --git a/packages/documentation/docs/images/Logo_O_RGB.png b/packages/documentation/docs/images/Logo_O_RGB.png new file mode 100755 index 00000000000..f83bc539455 Binary files /dev/null and b/packages/documentation/docs/images/Logo_O_RGB.png differ diff --git a/packages/documentation/docs/images/O_UI5_H_noBG.png b/packages/documentation/docs/images/O_UI5_H_noBG.png new file mode 100755 index 00000000000..b0aa012e1b9 Binary files /dev/null and b/packages/documentation/docs/images/O_UI5_H_noBG.png differ diff --git a/packages/documentation/docs/index.md b/packages/documentation/docs/index.md index b5d4500e27d..421519b3921 100644 --- a/packages/documentation/docs/index.md +++ b/packages/documentation/docs/index.md @@ -1,22 +1,38 @@ -![UI5 logo](images/UI5_logo_wide.png) +--- +next: + text: 'Getting Started' + link: '/pages/GettingStarted' +--- + + + +UI5 logo # UI5 CLI An open and modular toolchain to develop state-of-the-art applications based on the [UI5](https://ui5.sap.com) framework. -!!! abstract "Project Rename" - **UI5 Tooling has been renamed to UI5 CLI 🚨** +::: warning Project Rename +**UI5 Tooling has been renamed to UI5 CLI 🚨** - Read the announcement blog post: **[SAP Community: Goodbye UI5 Tooling - Hello UI5 CLI!](https://community.sap.com/t5/technology-blog-posts-by-sap/goodbye-ui5-tooling-hello-ui5-cli/ba-p/14211769)** +Read the announcement blog post: **[SAP Community: Goodbye UI5 Tooling - Hello UI5 CLI!](https://community.sap.com/t5/technology-blog-posts-by-sap/goodbye-ui5-tooling-hello-ui5-cli/ba-p/14211769)** +::: -!!! tip "New Release" - **UI5 CLI V4 is here 🎉** +::: tip New Release +**UI5 CLI V4 is here 🎉** - Read the announcement blog post: **[SAP Community: UI5 CLI 4.0](https://community.sap.com/t5/technology-blogs-by-sap/ui5-tooling-4-0/ba-p/13769578)** +Read the announcement blog post: **[SAP Community: UI5 CLI 4.0](https://community.sap.com/t5/technology-blogs-by-sap/ui5-tooling-4-0/ba-p/13769578)** - And checkout the **[Migrate to v4](./updates/migrate-v4.md)** documentation. +And checkout the **[Migrate to v4](./updates/migrate-v4.md)** documentation. +::: -[**Get Started**](./pages/GettingStarted.md){: .md-button .md-button--primary .sap-icon-initiative } +
+ +
## Main Features @@ -99,40 +115,38 @@ info ProjectBuilder Executing cleanup tasks... Most UI5 CLI modules provide JavaScript APIs for direct consumption in other Node.js projects. This allows you to rely on UI5 CLI for UI5-specific build functionality and project handling, while creating your own tools to perfectly match the needs of your project. -All available APIs are documented in the [UI5 CLI API Reference](https://ui5.github.io/cli/v4/api/index.html). - -=== "ESM" - - ```js linenums="1" - import {graphFromPackageDependencies} from "@ui5/project/graph"; - - async function buildApp(projectPath, destinationPath) { - const graph = await graphFromPackageDependencies({ - cwd: projectPath - }); - await graph.build({ - destPath: destinationPath, - selfContained: true, - excludedTasks: ["transformBootstrapHtml"], - includedDependencies: ["*"] - }); - } - ``` - -=== "CommonJS" - - ```js linenums="1" - async function buildApp(projectPath, destinationPath) { - const {graphFromPackageDependencies} = - await import("@ui5/project/graph"); - const graph = await graphFromPackageDependencies({ - cwd: projectPath - }); - await graph.build({ - destPath: destinationPath, - selfContained: true, - excludedTasks: ["transformBootstrapHtml"], - includedDependencies: ["*"] - }); - } - ``` +All available APIs are documented in the [UI5 CLI API Reference](https://ui5.github.io/cli/v5/api/index.html). + +::: code-group +```js [ESM] +import {graphFromPackageDependencies} from "@ui5/project/graph"; + +async function buildApp(projectPath, destinationPath) { + const graph = await graphFromPackageDependencies({ + cwd: projectPath + }); + await graph.build({ + destPath: destinationPath, + selfContained: true, + excludedTasks: ["transformBootstrapHtml"], + includedDependencies: ["*"] + }); +} +``` + +```js [CommonJS] +async function buildApp(projectPath, destinationPath) { + const {graphFromPackageDependencies} = + await import("@ui5/project/graph"); + const graph = await graphFromPackageDependencies({ + cwd: projectPath + }); + await graph.build({ + destPath: destinationPath, + selfContained: true, + excludedTasks: ["transformBootstrapHtml"], + includedDependencies: ["*"] + }); +} +``` +::: \ No newline at end of file diff --git a/packages/documentation/docs/pages/Benchmarking.md b/packages/documentation/docs/pages/Benchmarking.md index 321ff98497f..364b9ec8fe9 100644 --- a/packages/documentation/docs/pages/Benchmarking.md +++ b/packages/documentation/docs/pages/Benchmarking.md @@ -102,11 +102,11 @@ The following is a walk-through on how to evaluate the performance impact of an 1. Prepare your change 1. Switch to the branch that contains your change ```sh - (cd ../ui5-builder && git checkout my-change) + (cd ../packages/builder && git checkout my-change) ``` 1. If your change requires different npm dependencies, reinstall them ```sh - (cd ../ui5-builder && npm install) + (cd ../packages/builder && npm install) ``` 1. The link from UI5 CLI is still in place. However, if you have changes in **multiple** UI5 CLI modules, you might need to `npm link` those again diff --git a/packages/documentation/docs/pages/Builder.md b/packages/documentation/docs/pages/Builder.md index b007bdac38a..ea77a9a7ff8 100644 --- a/packages/documentation/docs/pages/Builder.md +++ b/packages/documentation/docs/pages/Builder.md @@ -2,11 +2,17 @@ The [UI5 Builder](https://github.com/SAP/ui5-builder) module takes care of building your project. + + Based on a project's type, the UI5 Builder defines a series of build steps to execute; these are also called "tasks". For every type there is a set of default tasks. You can disable single tasks using the `--exclude-task` [CLI parameter](./CLI.md#ui5-build), and you can include tasks using the `--include-task` parameter. -[**API Reference**](https://ui5.github.io/cli/v4/api/index.html){: .md-button .sap-icon-initiative } +
+ +
## Tasks Tasks are specific build steps to be executed during build phase. @@ -17,7 +23,7 @@ A project can add custom tasks to the build by using the [Custom Tasks Extensibi ### Standard Tasks -All available standard tasks are documented [in the API reference](https://ui5.github.io/cli/v4/api/index.html). Search for `@ui5/builder/tasks/` to filter the API reference for all available tasks. The list below offers the actual order of their execution: +All available standard tasks are documented [in the API reference](https://ui5.github.io/cli/v5/api/index.html). Search for `@ui5/builder/tasks/` to filter the API reference for all available tasks. The list below offers the actual order of their execution: | Task | Type `application` | Type `library` | Type `theme-library` | | ------------------------------ | :----------------: | :------------: | :------------------: | @@ -65,24 +71,30 @@ Related to this, the bundling tasks will also incorporate the generated source m #### Input Source Maps -!!! info - Support for input source maps has been added in UI5 CLI [`v3.7.0`](https://github.com/SAP/ui5-cli/releases/tag/v3.7.0). +::: info Info +Support for input source maps has been added in UI5 CLI [`v3.7.0`](https://github.com/SAP/ui5-cli/releases/tag/v3.7.0). + +::: For projects facilitating transpilation (such as TypeScript-based projects), it is commonly desired to debug in the browser using the original sources, e.g. TypeScript files. To make this work, the transpilation process first needs to create source maps and reference them in the generated JavaScript code. UI5 CLI's `minify` task will then find this reference and incorporate the source map into the minification process. In the end, the minified JavaScript resources will reference an updated source map, which reflects the transpilation as well as the minification. The browser can use this to map every statement back to the original TypeScript file, making debugging a breeze. -!!! warning - If a resource has been modified by another build task before `minify` is executed, any referenced source map will be ignored. This is to ensure the integrity of the source maps in the build result. +::: warning Warning +If a resource has been modified by another build task before `minify` is executed, any referenced source map will be ignored. This is to ensure the integrity of the source maps in the build result. + +It is possible that the modification of the resource content is not reflected in the associated source map, rendering it corrupted. A corrupt source map can make it impossible to properly analyze and debug a resource in the browser development tools. - It is possible that the modification of the resource content is not reflected in the associated source map, rendering it corrupted. A corrupt source map can make it impossible to properly analyze and debug a resource in the browser development tools. +Standard tasks which may modify resources without updating the associated source maps currently include `replaceVersion`, `replaceCopyright` and `replaceBuildtime`. - Standard tasks which may modify resources without updating the associated source maps currently include `replaceVersion`, `replaceCopyright` and `replaceBuildtime`. +::: Expand the block below to view a diagram illustrating the minification process and source map handling. -??? info "Minification Activity Diagram" - ![minify Task Activity](../images/UI5_CLI/Task_Minify.svg){ loading=lazy } +::: info Minification Activity Diagram + ![minify Task Activity](../images/UI5_CLI/Task_Minify.svg) + +::: ### Generation of Supported Locales @@ -145,7 +157,7 @@ Processors work with provided resources. They contain the actual build step logi Processors can be implemented generically. The string replacer is an example for that. Since string replacement is a common build step, it can be useful in different contexts, e.g. code, version, date, and copyright replacement. A concrete replacement operation could be achieved by passing a custom configuration to the processor. This way, multiple tasks can make use of the same processor to achieve their build step. -To get a list of all available processors, please visit [the API reference](https://ui5.github.io/cli/v4/api/index.html) and search for `@ui5/builder/processors/`. +To get a list of all available processors, please visit [the API reference](https://ui5.github.io/cli/v5/api/index.html) and search for `@ui5/builder/processors/`. ## Legacy Bundle Tooling (lbt) JavaScript port of the "legacy" Maven/Java based bundle tooling. @@ -166,17 +178,24 @@ If you see this error message, please adjust your code by applying one of the fo **Option 2**: Wrap the respective files manually in `sap.ui.define` modules as shown below: -!!! example - **Before**: - ```js - const myFancyModule = {}; - ``` +::: details Example +**Before**: +```js +const myFancyModule = {}; +``` - **After**: - ```js - sap.ui.define([], () => { - "use strict"; - const myFancyModule = {}; - return myFancyModule; - }); - ``` +**After**: +```js +sap.ui.define([], () => { + "use strict"; + const myFancyModule = {}; + return myFancyModule; +}); +``` + +::: + diff --git a/packages/documentation/docs/pages/CLI.md b/packages/documentation/docs/pages/CLI.md deleted file mode 100644 index 1ab4eef2089..00000000000 --- a/packages/documentation/docs/pages/CLI.md +++ /dev/null @@ -1,393 +0,0 @@ -# UI5 CLI -## Requirements -- [Node.js](https://nodejs.org/) version v20.11.0 and higher or v22.0.0 and higher (v21 is not supported) -- [npm](https://www.npmjs.com/) version v8.0.0 or higher - -## Installation - -Install the CLI using the npm package manager: - -```sh -npm install --global @ui5/cli - -# Verify installation -ui5 --help -``` - -## Usage/Syntax - -` - ui5 [options] -` - -The CLI automatically checks for updates using [update-notifier](https://github.com/yeoman/update-notifier). While this is skipped in CI environments, you might also opt-out manually by following the steps described [here](https://github.com/yeoman/update-notifier/blob/-/readme.md#user-settings). - -## Common options - -These options you can use with each command. - -| Option | Description | Details | -| --- | --- | --- | -| -h, --help | Show help | [boolean] | -| -v, --version | Show version number | [boolean] | -| -c, --config | Path to project configuration file in YAML format | [string] | -| --dependency-definition | Path to a YAML file containing the project's dependency tree. This option will disable resolution of node package dependencies. | [string] | -| --workspace-config | Path to workspace configuration file in YAML format | [string] | -| -w, --workspace | Name of the workspace configuration to use | [string] [default: "default"] | -| --loglevel, --log-level | Set the logging level | [string] [choices: "silent", "error", "warn", "info", "perf", "verbose", "silly"] [default: "info"] | -| --verbose | Enable verbose logging. | [boolean] [default: false] | -| --perf | Enable performance measurements and related logging. | [boolean] [default: false] | -| --silent | Disable all log output. | [boolean] [default: false] | - -## Examples - -Execute command using a static dependency tree instead of resolving node package dependencies -``` -ui5 --dependency-definition /path/to/projectDependencies.yaml -``` -Execute command using a project configuration from custom path -``` -ui5 --config /path/to/ui5.yaml -``` -Execute command using the 'dolphin' workspace of a ui5-workspace.yaml -``` -ui5 --workspace dolphin -``` -Execute command with the maximum log output -``` -ui5 --log-level silly -``` - -## Commands - -### ui5 add - -**Description** - -Add SAPUI5/OpenUI5 framework libraries to the project configuration. - -**Usage** - -` -ui5 add [--development] [--optional] -` - - -**Options** - -| Option | Description | Details | -| --- | --- | --- | -| -D, --development, --dev | Add as development dependency | [boolean] [default: false] | -| -O, --optional | Add as optional dependency | [boolean] [default: false] | - -**Positionals** - -| Positional | Description | Details | -| --- | --- | --- | -| framework-libraries | Framework library names | [array] [required] [default: []] | - -**Examples** - -Add the framework libraries sap.ui.core and sap.m as dependencies -``` -ui5 add sap.ui.core sap.m -``` -Add the framework library sap.ui.support as development dependency -``` -ui5 add -D sap.ui.support -``` -Add the framework library themelib_sap_fiori_3 as optional dependency -``` -ui5 add --optional themelib_sap_fiori_3 -``` -### ui5 build - -**Description** - -Build project in current directory - -**Usage** - -` -ui5 build -` - -**Child Commands** - -| Command | Description | -| --- | --- | -| ui5 build jsdoc | Build JSDoc resources | -| ui5 build preload | (default) Build project and create preload bundles | -| ui5 build self-contained | Build project and create self-contained bundle. Recommended to be used in conjunction with --include-all-dependencies | - -**Options** - -| Option | Description | Details | -| --- | --- | --- | -| -a, --include-all-dependencies, --all | Include all dependencies in the build result. This is equivalent to '--include-dependency "*"' | [boolean] [default: false] | -| --include-dependency | A list of dependencies to be included in the build result. You can use the asterisk '*' as an alias for including all dependencies in the build result. The listed dependencies cannot be overruled by dependencies defined in 'exclude-dependency'. The provided name must match with the dependency name shown in 'ui5 ls --flat' | [array] | -| --include-dependency-regexp | A list of regular expressions defining dependencies to be included in the build result. This list is prioritized like 'include-dependency'. | [array] | -| --include-dependency-tree | A list of dependencies to be included in the build result. Transitive dependencies are implicitly included and do not need to be part of this list. These dependencies overrule the selection of 'exclude-dependency-tree' but can be overruled by 'exclude-dependency'. | [array] | -| --exclude-dependency | A list of dependencies to be excluded from the build result. The listed dependencies can be overruled by dependencies defined in 'include-dependency'. The provided name must match with the dependency name shown in 'ui5 ls --flat' | [array] | -| --exclude-dependency-regexp | A list of regular expressions defining dependencies to be excluded from the build result. This list is prioritized like 'exclude-dependency'. | [array] | -| --exclude-dependency-tree | A list of dependencies to be excluded from the build result. Transitive dependencies are implicitly included and do not need to be part of this list. | [array] | -| --dest | Path of build destination | [string] [default: "./dist"] | -| --clean-dest | If present, clean the destination directory before building | [boolean] [default: false] | -| --create-build-manifest | Store build metadata in a '.ui5' directory in the build destination, allowing reuse of the build result in other builds | [boolean] [default: false] | -| --include-task | A list of tasks to be added to the default execution set. This option takes precedence over any excludes. | [array] | -| --exclude-task | A list of tasks to be excluded from the default task execution set | [array] | -| --framework-version | Overrides the framework version defined by the project. Takes the same value as the version part of "ui5 use" | [string] | -| --cache-mode | Cache mode to use when consuming SNAPSHOT versions of framework dependencies. The 'Default' behavior is to invalidate the cache after 9 hours. 'Force' uses the cache only and does not create any requests. 'Off' invalidates any existing cache and updates from the repository | [string] [choices: "Default", "Force", "Off"] [default: "Default"] | -| --experimental-css-variables | Generate CSS variables (css-variables.css, css-variables.source.less) and skeleton (library-skeleton(-RTL).css) for all themes | [boolean] [default: false] | -| --output-style | Processes build results into a specific directory structure.
- Flat: Omits the project namespace and the "resources" directory.
- Namespace: Respects the project namespace and the "resources" directory, maintaining the original structure.
- Default: The default directory structure for every project type. For applications, this is identical to "Flat", and for libraries, it is "Namespace". Other types have a more distinct default output style. | [string] [choices: "Default", "Flat", "Namespace"] [default: "Default"] | - - -**Examples** - -Preload build for project without dependencies -``` -ui5 build -``` -Self-contained build for project -``` -ui5 build self-contained -``` -Build project but only apply the minify- and generateComponentPreload tasks -``` -ui5 build --exclude-task=* --include-task=minify generateComponentPreload -``` -Build project by applying all default tasks including the minify task and excluding the generateComponentPreload task -``` -ui5 build --include-task=minify --exclude-task=generateComponentPreload -``` -Preload build with experimental CSS variables artifacts -``` -ui5 build --experimental-css-variables -``` -### ui5 config - -**Description** - -Get and set UI5 CLI configuration options - -**Usage** - -` -ui5 config -` - -**Child Commands** - -| Command | Description | -| --- | --- | -| ui5 config set