diff --git a/package.json b/package.json index ff6357b4601..2f8590b1588 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "requirejs": "2.3.6", "rollup-plugin-node-polyfills": "0.2.1", "rollup-plugin-visualizer": "5.9.0", - "sass": "1.62.1", + "sass": "1.69.7", "ts-jest": "29.1.1", "ts-node": "10.9.2", "tslib": "2.5.0", diff --git a/packages/design-system/build/build-tokens.js b/packages/design-system/build/build-tokens.js index c32f3ccbc3d..50eb767a5b3 100644 --- a/packages/design-system/build/build-tokens.js +++ b/packages/design-system/build/build-tokens.js @@ -10,12 +10,27 @@ StyleDictionary.extend({ parsers: [ { pattern: /\.yaml$/, - parse: ({ contents }) => yaml.parse(contents) + parse: ({ contents, filePath }) => { + // This is a bit of a hack to prevent name collisions which would drop the tokens then + if (filePath.split('/').some((n) => n === 'docs')) { + const parsed = yaml.parse(contents) + + Object.keys(parsed).forEach((k) => { + parsed['docs-' + k] = parsed[k] + + delete parsed[k] + }) + + return parsed + } + + return yaml.parse(contents) + } } ], source: [path.join(__dirname, '../src/tokens/**/*.yaml')], platforms: { - default: { + ods: { transforms: ['name/cti/kebab', 'transform/ods/namespace'], buildPath: 'src/assets/tokens/', files: [ diff --git a/packages/design-system/build/build-tokens/transform-namespace.js b/packages/design-system/build/build-tokens/transform-namespace.js index 03f54109245..16439600a5c 100644 --- a/packages/design-system/build/build-tokens/transform-namespace.js +++ b/packages/design-system/build/build-tokens/transform-namespace.js @@ -2,8 +2,6 @@ module.exports = { name: 'transform/ods/namespace', type: 'name', transformer: function (prop) { - return ['oc', prop.filePath.split('/').some((n) => n === 'docs') ? 'docs' : '', prop.name] - .filter(Boolean) - .join('-') + return ['oc', prop.name].filter(Boolean).join('-') } } diff --git a/packages/design-system/build/utils.js b/packages/design-system/build/utils.js index c3cf1e3ae69..3a54cc483de 100644 --- a/packages/design-system/build/utils.js +++ b/packages/design-system/build/utils.js @@ -41,8 +41,6 @@ exports.cssLoaders = function (options) { // (which is the case during production build) if (options.extract) { loaders.push(MiniCssExtractPlugin.loader) - } else { - loaders.push('vue-style-loader') } loaders.push(cssLoader) diff --git a/packages/design-system/build/webpack.base.conf.js b/packages/design-system/build/webpack.base.conf.js index a16ac9b3cd4..001dc76187b 100644 --- a/packages/design-system/build/webpack.base.conf.js +++ b/packages/design-system/build/webpack.base.conf.js @@ -12,36 +12,44 @@ function resolve(dir) { module.exports = { mode: process.env.NODE_ENV === 'production' ? config.build.mode : config.dev.mode, context: path.resolve(__dirname, '../'), - entry: { - app: ['./src/system.js'] - }, - output: { - path: config.build.assetsRoot, - filename: '[name].js', - publicPath: - process.env.NODE_ENV === 'production' - ? config.build.assetsPublicPath - : config.dev.assetsPublicPath - }, resolve: { - extensions: ['.js', '.vue', '.json'], + extensions: ['.js', '.vue', '.json', '.ts'], alias: { - vue$: 'vue/dist/vue.esm.js', + vue$: 'vue/dist/vue.esm-bundler.js', '@': resolve('src') + }, + fallback: { + url: require.resolve('url/'), + path: false, + 'process/browser': require.resolve('process/browser') } }, module: { rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: [ + { + loader: 'ts-loader', + options: { + appendTsSuffixTo: [/\.vue$/] + } + } + ] + }, { test: /\.vue$/, - loader: 'vue-loader', - options: { - cacheBusting: config.dev.cacheBusting, - transformAssetUrls: { - video: ['src', 'poster'], - source: 'src', - img: 'src', - image: 'xlink:href' + use: { + loader: 'vue-loader', + options: { + cacheBusting: config.dev.cacheBusting, + transformAssetUrls: { + video: ['src', 'poster'], + source: 'src', + img: 'src', + image: 'xlink:href' + } } } }, @@ -72,45 +80,51 @@ module.exports = { }, { test: /\.(png|jpe?g|gif)(\?.*)?$/, - loader: 'url-loader', - options: { - limit: 10000, - name: utils.assetsPath('img/[name].[hash:7].[ext]') + type: 'asset/resource', + generator: { + filename: 'img/[name].[hash:7][ext]' } }, { test: /\.svg$/, - loader: 'html-loader' + type: 'asset/inline' }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, - loader: 'url-loader', - options: { - limit: 10000, - name: utils.assetsPath('media/[name].[hash:7].[ext]') + type: 'asset/resource', + generator: { + filename: 'media/[name].[hash:7][ext]' } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, - loader: 'url-loader', - options: { - limit: 10000, - name: utils.assetsPath('fonts/[name].[hash:7].[ext]') + type: 'asset/resource', + generator: { + filename: 'fonts/[name].[hash:7][ext]' } + }, + { + test: /\.(css|scss)$/, + use: [ + process.env.NODE_ENV === 'production' ? MiniCssExtractPlugin.loader : 'style-loader', + 'css-loader', + 'sass-loader', + { + loader: 'sass-resources-loader', + options: { + resources: [ + path.join(__dirname, '../src/assets/tokens/docs.scss'), + path.join(__dirname, '../src/assets/tokens/ods.scss'), + path.join(__dirname, '../docs/docs.mixins.scss'), + path.join(__dirname, '../docs/docs.functions.scss'), + path.join(__dirname, '../docs/docs.spacing.scss'), + path.join(__dirname, '../src/styles/styles.scss') + ] + } + } + ] } ] }, - plugins: [new VueLoaderPlugin(), new MiniCssExtractPlugin({ filename: 'style.css' })], - node: { - // prevent webpack from injecting useless setImmediate polyfill because Vue - // source contains it (although only uses it if it's native). - setImmediate: false, - // prevent webpack from injecting mocks to Node native modules - // that does not make sense for the client - dgram: 'empty', - fs: 'empty', - net: 'empty', - tls: 'empty', - child_process: 'empty' - } + plugins: [new VueLoaderPlugin(), new MiniCssExtractPlugin({ filename: 'style.css' })] } diff --git a/packages/design-system/changelog/unreleased/bugfix-docs-build b/packages/design-system/changelog/unreleased/bugfix-docs-build new file mode 100644 index 00000000000..c5d11dceb65 --- /dev/null +++ b/packages/design-system/changelog/unreleased/bugfix-docs-build @@ -0,0 +1,6 @@ +Bugfix: Migrate build process of documentation to the latest versions + +We've bumped build dependencies of the Design system to support Vue 3 and fix the build of documentation. + +https://github.com/owncloud/web/issues/10233 +https://github.com/owncloud/web/pull/10243 diff --git a/packages/design-system/config/docs.config.js b/packages/design-system/config/docs.config.js index 6bc95071d81..cff29e85693 100644 --- a/packages/design-system/config/docs.config.js +++ b/packages/design-system/config/docs.config.js @@ -1,6 +1,5 @@ const path = require('path') const baseConfig = require('../build/webpack.base.conf.js') -const { merge } = require('webpack-merge') const packageConfig = require('../package.json') const chalk = require('chalk') @@ -9,6 +8,7 @@ module.exports = { * Name of your design system. Changes both page title and sidebar logo. */ title: 'ownCloud Design System', + webpackConfig: baseConfig, /** * Most of the styles are defined in /docs/docs.styles.scss */ @@ -21,7 +21,6 @@ module.exports = { monospace: ['Consolas', "'Liberation Mono'", 'Menlo', 'monospace'] } }, - renderRootJsx: path.join(__dirname, '../docs/components/Preview.js'), /** * Define a custom code highlighting theme. */ @@ -37,12 +36,13 @@ module.exports = { * Enabling the below option will break things in ownCloud Design System! */ skipComponentsWithoutExample: false, + renderRootJsx: '../docs/components/Preview.js', /** * We’re defining below JS and SCSS requires for the documentation. */ require: [ - path.join(__dirname, '../docs/docs.helper.js'), - path.join(__dirname, '../docs/docs.styles.scss') + path.join(__dirname, '../docs/docs.styles.scss'), + path.join(__dirname, '../docs/docs.helper.js') ], /** * Enabling the following option splits sections into separate views. @@ -52,9 +52,6 @@ module.exports = { { name: 'Getting Started', content: '../docs/getting-started.md', - // Needs to be loaded in somewhere as this is also shown in - // components overviews. - components: '../docs/components/status/**/[A-Z]*.vue', sectionDepth: 1, exampleMode: 'hide', usageMode: 'hide' @@ -86,12 +83,13 @@ module.exports = { sectionDepth: 1, exampleMode: 'hide', usageMode: 'hide', - components: () => [ - '../docs/components/tokens/IconList.vue', - '../docs/components/tokens/ColorTokens.vue', - '../docs/components/tokens/FontSize.vue', - '../docs/components/tokens/SpacingTokens.vue', - '../docs/components/tokens/AllTokens.vue' + sections: [ + { + name: 'Icons', + content: '../docs/icons.md', + exampleMode: 'hide', + usageMode: 'hide' + } ] }, { @@ -209,34 +207,6 @@ module.exports = { '**/*.spec.js', '**/*.spec.jsx' ], - webpackConfig: merge(baseConfig, { - module: { - rules: [ - { - test: /\.(css?|scss|sass)(\?.*)?$/, - use: [ - 'style-loader', - 'css-loader', - 'postcss-loader', - 'sass-loader', - { - loader: 'sass-resources-loader', - options: { - resources: [ - path.join(__dirname, '../src/assets/tokens/docs.scss'), - path.join(__dirname, '../src/assets/tokens/ods.scss'), - path.join(__dirname, '../docs/docs.mixins.scss'), - path.join(__dirname, '../docs/docs.functions.scss'), - path.join(__dirname, '../docs/docs.spacing.scss'), - path.join(__dirname, '../src/styles/styles.scss') - ] - } - } - ] - } - ] - } - }), styleguideDir: '../dist/docs', printServerInstructions() {}, printBuildInstructions(config) { diff --git a/packages/design-system/docs/components.md b/packages/design-system/docs/components.md index 3777e6fef56..71d738f97bc 100644 --- a/packages/design-system/docs/components.md +++ b/packages/design-system/docs/components.md @@ -5,5 +5,5 @@ You’re looking at ownCloud Design System’s demo UI Components. ## Overview ``` - + ``` diff --git a/packages/design-system/docs/components/Preview.js b/packages/design-system/docs/components/Preview.js index b128e822442..168cec17721 100644 --- a/packages/design-system/docs/components/Preview.js +++ b/packages/design-system/docs/components/Preview.js @@ -1,5 +1,13 @@ -import CodeMirror from 'codemirror' import CodeTabs from '../utils/tabs.js' +import { createApp, h } from 'vue' +import statusLabels from '../utils/statusLabels.js' +import { createGettext } from 'vue3-gettext' +import * as directives from '../../src/directives' +import { EditorView, highlightSpecialChars } from '@codemirror/view' +import { EditorState } from '@codemirror/state' +import { html } from '@codemirror/lang-html' +import { HighlightStyle, syntaxHighlighting } from '@codemirror/language' +import { tags } from '@lezer/highlight' function format(node, level) { const indentBefore = new Array(level++ + 1).join(' ') @@ -21,11 +29,63 @@ function format(node, level) { return node } +function generateObjectId() { + const timestamp = new Date().getTime().toString(16) + const randomValue = Math.floor(Math.random() * 1000000).toString(16) + const objectId = timestamp + randomValue + + return objectId +} + +// This is a dirty hack to be able to extend the Vue app since vue-styleguidist does not provide any way to do so +function setupVueApp(element) { + const app = createApp(h(element)) + + // Components are registered globally only for the styleguidist app... + const componentsContext = require.context('../../src/components/', true, /\.vue$/) + + componentsContext.keys().forEach((key) => { + const component = componentsContext(key).default + + app.component(component.name, component) + }) + + app.component('RouterLink', { + props: { + tag: { type: String, default: 'a' } + }, + render() { + return h(this.tag, {}, this.$slots.default) + } + }) + + for (const name in directives) { + app.directive(name, directives[name]) + } + + app.mixin(statusLabels) + + // Vue-gettext is bundled only in the docs. The design system itself depends on the consuming app in providing it + app.use(createGettext({ translations: {} })) + + return app +} + export default (previewComponent) => { // https://vuejs.org/v2/guide/render-function.html return { - render(createElement) { - return createElement(previewComponent) + render() { + const appId = 'preview-' + generateObjectId() + const app = setupVueApp(previewComponent) + + const previewContainer = h('div', { + id: appId, + onVnodeMounted: () => { + app.mount('#' + appId) + } + }) + + return previewContainer }, mounted() { CodeTabs.clean() @@ -45,33 +105,78 @@ export default (previewComponent) => { const elemText = format(div, 0).innerHTML.replace(/ class=""/g, '') const elem = document.createElement('div') - const pre = document.createElement('pre') const parent = document.querySelector("article div[class^='rsg--tab']") - pre.appendChild(document.createTextNode(elemText.trim())) - elem.appendChild(pre) + if (parent) { // Allow some time to pass to make sure codemirror is visible first setTimeout(() => { parent.appendChild(elem) parent.appendChild(tabs) - CodeMirror( - function (code) { - elem.parentNode.replaceChild(code, elem) - code.className += ' vueds-html vueds-hidden' - }, + const themeNight = EditorView.theme( { - value: pre.innerText || pre.textContent, - mode: 'jsx', - lineNumbers: false, - lineWrapping: true, - readOnly: true, - dragDrop: false, - theme: 'night', - viewportMargin: Infinity - } + '&': { + color: 'white', + backgroundColor: '#041d37', + fontSize: '13px', + padding: '24px' + }, + '.cm-content': { + caretColor: '#ffffff' + }, + '&.cm-focused .cm-cursor': { + borderLeftColor: '#ffffff' + }, + '&.cm-focused .cm-selectionBackground, ::selection': { + backgroundColor: 'rgba(68, 68, 119, .99)' + } + }, + { dark: true } ) + const editorState = EditorState.create({ + doc: elemText.trim(), + extensions: [ + html(), + themeNight, + EditorState.readOnly.of(true), + highlightSpecialChars(), + syntaxHighlighting( + HighlightStyle.define([ + { + tag: [ + tags.atom, + tags.bool, + tags.url, + tags.contentSeparator, + tags.labelName, + tags.attributeValue + ], + color: '#afe74c' + }, + { tag: tags.string, color: '#afe74c' }, + { tag: [tags.typeName, tags.namespace, tags.bracket], color: '#54a3f2' }, + { tag: tags.attributeName, color: '#ffcc4d' } + ]), + { fallback: false } + ) + ] + }) + + try { + // This code is wrapped in try/catch due to sonarcloud reporting this as issue otherwise + // Sonarcloud marks as issues instantiated classes which are not assigned anywhere but we need it like that here due to sideeffects of the class + new EditorView({ + state: editorState, + parent: elem + }) + } catch (error) { + console.error(error) + } + + elem.classList.add('vueds-html') + elem.classList.add('vueds-hidden') + CodeTabs.init() }, 300) } diff --git a/packages/design-system/docs/components/tokens/AllTokens.spec.js b/packages/design-system/docs/components/tokens/AllTokens.spec.js deleted file mode 100644 index 773194ee4d6..00000000000 --- a/packages/design-system/docs/components/tokens/AllTokens.spec.js +++ /dev/null @@ -1,31 +0,0 @@ -import Vue from 'vue' -import AllTokens from './AllTokens.vue' - -const Constructor = Vue.extend(AllTokens) -const vm = new Constructor().$mount() - -describe('AllTokens.vue', () => { - it('should render correct contents', () => { - expect(vm.$el.querySelector('.token')).toBeDefined() - }) - - it('should render multiple tokens', () => { - expect(vm.$el.querySelectorAll('.token').length).toBeGreaterThan(10) - }) - - it('should create code elements for copy pasting', () => { - expect(vm.$el.querySelector('code.name')).toBeDefined() - }) - - it('should create code elements with original values', () => { - expect(vm.$el.querySelector('code.type')).toBeDefined() - }) - - it('should create examples of usage', () => { - expect(vm.$el.querySelector('.example')).toBeDefined() - }) - - it('should apply inline styles', () => { - expect(vm.$el.querySelector('.example.color').style).toBeDefined() - }) -}) diff --git a/packages/design-system/docs/components/tokens/ColorTokens.spec.js b/packages/design-system/docs/components/tokens/ColorTokens.spec.js deleted file mode 100644 index 0bc5a0a802d..00000000000 --- a/packages/design-system/docs/components/tokens/ColorTokens.spec.js +++ /dev/null @@ -1,27 +0,0 @@ -import Vue from 'vue' -import ColorTokens from './ColorTokens.vue' - -const Constructor = Vue.extend(ColorTokens) -const vm = new Constructor().$mount() - -describe('ColorTokens.vue', () => { - it('should render correct contents', () => { - expect(vm.$el.querySelector('.color')).toBeDefined() - }) - - it('should render multiple colors', () => { - expect(vm.$el.querySelectorAll('.color').length).toBeGreaterThan(2) - }) - - it('should create code elements for copy pasting', () => { - expect(vm.$el.querySelector('.color span')).toBeDefined() - }) - - it('should create swatches and apply inline styles', () => { - expect(vm.$el.querySelector('.color .swatch').style).toBeDefined() - }) - - it('should create multiple color groups', () => { - expect(vm.$el.querySelector('.color_group_2')).toBeDefined() - }) -}) diff --git a/packages/design-system/docs/components/tokens/FontSize.spec.js b/packages/design-system/docs/components/tokens/FontSize.spec.js deleted file mode 100755 index c138926bc8e..00000000000 --- a/packages/design-system/docs/components/tokens/FontSize.spec.js +++ /dev/null @@ -1,23 +0,0 @@ -import Vue from 'vue' -import FontSize from './FontSize.vue' - -const Constructor = Vue.extend(FontSize) -const vm = new Constructor().$mount() - -describe('FontSize.vue', () => { - it('should render correct contents', () => { - expect(vm.$el.querySelector('.font')).toBeDefined() - }) - - it('should render multiple sizes', () => { - expect(vm.$el.querySelectorAll('.font').length).toBeGreaterThan(2) - }) - - it('should create px sizes for copy pasting', () => { - expect(vm.$el.querySelector('.font span')).toBeDefined() - }) - - it('should create apply inline styles', () => { - expect(vm.$el.querySelector('.font').style).toBeDefined() - }) -}) diff --git a/packages/design-system/docs/components/tokens/SpacingTokens.spec.js b/packages/design-system/docs/components/tokens/SpacingTokens.spec.js deleted file mode 100644 index 3933cf6a7fd..00000000000 --- a/packages/design-system/docs/components/tokens/SpacingTokens.spec.js +++ /dev/null @@ -1,23 +0,0 @@ -import Vue from 'vue' -import SpacingTokens from './SpacingTokens.vue' - -const Constructor = Vue.extend(SpacingTokens) -const vm = new Constructor().$mount() - -describe('SpacingTokens.vue', () => { - it('should render correct contents', () => { - expect(vm.$el.querySelector('.space')).toBeDefined() - }) - - it('should render multiple sizes', () => { - expect(vm.$el.querySelectorAll('.space').length).toBeGreaterThan(2) - }) - - it('should create px sizes for copy pasting', () => { - expect(vm.$el.querySelector('.space span')).toBeDefined() - }) - - it('should create apply inline styles', () => { - expect(vm.$el.querySelector('.space').style).toBeDefined() - }) -}) diff --git a/packages/design-system/docs/docs.helper.js b/packages/design-system/docs/docs.helper.js index 7144e73c99c..1cee9f0c0ab 100644 --- a/packages/design-system/docs/docs.helper.js +++ b/packages/design-system/docs/docs.helper.js @@ -2,17 +2,8 @@ * This is ownCloud Design System’s JS helper file for docs. * You can add more things if/when needed. */ -import Vue from 'vue' -import statusLabels from './utils/statusLabels' import activeNav from './utils/activeNav' import filterSearch from './utils/filterSearch' -import 'codemirror/mode/jsx/jsx' -// Vue-gettext is bundled only in the docs. The design system itself depends on the consuming app in providing it -import GetTextPlugin from 'vue-gettext' - -Vue.config.productionTip = false -Vue.mixin(statusLabels) -Vue.use(GetTextPlugin, { translations: {} }) document.addEventListener('DOMContentLoaded', () => { filterSearch.methods.init() @@ -23,18 +14,3 @@ window.addEventListener('hashchange', () => { filterSearch.methods.init() activeNav.methods.init() }) - -// mock for the router-link -Vue.component('RouterLink', { - props: { - tag: { type: String, default: 'a' } - }, - render(createElement) { - return createElement(this.tag, {}, this.$slots.default) - } -}) - -const directivesContext = require.context('../src/directives/', true, /\.js$/) -directivesContext.keys().forEach((key) => { - Vue.directive(directivesContext(key).default.name, directivesContext(key).default) -}) diff --git a/packages/design-system/docs/docs.spacing.scss b/packages/design-system/docs/docs.spacing.scss index ae0890d6a4e..132a11bcf04 100644 --- a/packages/design-system/docs/docs.spacing.scss +++ b/packages/design-system/docs/docs.spacing.scss @@ -21,7 +21,7 @@ $spacing-ratio: 1.7; // // @param {Number} inset-squish-space to set @mixin inset-squish-space($value) { - padding: round($value / $spacing-ratio - 1px) $value round($value / $spacing-ratio); + padding: round(calc($value / $spacing-ratio) - 1px) $value round(calc($value / $spacing-ratio)); } // Create stack-space @@ -44,4 +44,4 @@ $spacing-ratio: 1.7; &:last-child { margin-right: 0; } -} +} \ No newline at end of file diff --git a/packages/design-system/docs/docs.styles.scss b/packages/design-system/docs/docs.styles.scss index 4cb4096d132..2258649e08d 100644 --- a/packages/design-system/docs/docs.styles.scss +++ b/packages/design-system/docs/docs.styles.scss @@ -37,7 +37,8 @@ div.rsg--root-1 { // Main content main[class^="rsg--content"] { - display: block; /* IE11 fix */ + display: block; + /* IE11 fix */ padding: $space-s $space-xl; background-color: tint($docs-grey, 90%); @@ -47,14 +48,14 @@ main[class^="rsg--content"] { } // Resetting margins for Styleguidist -header[class^="rsg--header"] > div[class^="rsg--wrapper"], -section > div[class^="rsg--wrapper"] + article[class^="rsg--root"], +header[class^="rsg--header"]>div[class^="rsg--wrapper"], +section>div[class^="rsg--wrapper"]+article[class^="rsg--root"], article[class^="rsg--root"] div[class^="rsg--root"] { margin: 0 !important; } // Display rsg--roots as flex -main section section > div > div[class^="rsg--root"] { +main section section>div>div[class^="rsg--root"] { display: flex; flex-direction: column; } @@ -65,6 +66,7 @@ main section section > div > div[class^="rsg--root"] { // Link color div[class^="rsg--root"] a[class^="rsg--link"] { color: $color-bleu-de-france; + &:hover { color: $color-bleu-de-france-dark; } @@ -72,8 +74,8 @@ div[class^="rsg--root"] a[class^="rsg--link"] { // Main headings // (includes h2 as well since in component views that’s the first heading) -div[class^="rsg--wrapper"] > h1[class^="rsg--heading"], -div[class^="rsg--wrapper"] > h2[class^="rsg--heading"] { +div[class^="rsg--wrapper"]>h1[class^="rsg--heading"], +div[class^="rsg--wrapper"]>h2[class^="rsg--heading"] { display: block; border: 0; line-height: $oc-docs-line-height-small; @@ -82,15 +84,18 @@ div[class^="rsg--wrapper"] > h2[class^="rsg--heading"] { margin: -#{$space-s} -#{$space-xl} $space-l -#{$space-xl}; background: $color-cloud; font-size: $size-xxl; + a:hover { text-decoration: none; cursor: default; } + @media (max-width: 1300px) { padding: $space-l $space-xl; } + @media (max-width: #{$docs-breakpoint}) { - font-size: $size-xl / 1.2; + font-size: calc($size-xl / 1.2); width: calc(100% + #{$space-xl}); padding: $space-l $space-m; margin: -#{$space-s} -#{$space-m} $space-m; @@ -103,10 +108,11 @@ header[class^="rsg--header"] { } // Links inside h1 -div[class^="rsg--wrapper"] > h1[class^="rsg--heading"] a { +div[class^="rsg--wrapper"]>h1[class^="rsg--heading"] a { font-weight: $oc-docs-font-weight-normal; color: $color-oxford-blue; letter-spacing: -1px; + &:hover { text-decoration: none; cursor: default; @@ -123,12 +129,15 @@ h2[class^="rsg--heading"] { font-weight: $oc-docs-font-weight-normal; letter-spacing: -0.5px; width: 100%; + @media (max-width: #{$docs-breakpoint}) { - font-size: $size-xl / 1.3; + font-size: calc($size-xl / 1.3); } + @media (max-width: #{$docs-breakpoint-small}) { - font-size: $size-xl / 1.6; + font-size: calc($size-xl / 1.6); } + a { color: $docs-color-heading; } @@ -144,8 +153,9 @@ h3[class^="rsg--heading"] a { margin: 0 0 $space-l; font-size: $size-l; color: $docs-color-text; + @media (max-width: #{$docs-breakpoint}) { - font-size: $size-l / 1.2; + font-size: calc($size-l / 1.2); margin: 0 0 $space-m; } } @@ -168,9 +178,11 @@ p[class^="rsg--para"] { color: $docs-color-text; margin-bottom: $space-s; line-height: $oc-docs-line-height-medium; + strong a[class^="rsg--link"] { font-weight: $oc-docs-font-weight-semi-bold; } + code { -webkit-font-smoothing: subpixel-antialiased; -moz-osx-font-smoothing: auto; @@ -180,6 +192,7 @@ p[class^="rsg--para"] { border-radius: $oc-docs-border-radius-default; font-size: 87.5%; } + a { overflow-wrap: break-word; word-wrap: break-word; @@ -188,7 +201,8 @@ p[class^="rsg--para"] { -webkit-hyphens: auto; hyphens: auto; } - pre + & { + + pre+& { margin-top: $space-s; } } @@ -200,9 +214,11 @@ h3[class^="rsg--heading"], h4[class^="rsg--heading"] { max-width: 800px; width: 75%; + p[class^="rsg--para"] { width: 100%; } + @media (max-width: 1300px) { width: 100%; } @@ -220,6 +236,7 @@ td[class^="rsg--cell"] p { div[class^="rsg--logo"] { @include inset-space($space-m); border-bottom: 1px solid rgba($color-white, 0.1); + h1 { color: tint($color-bleu-de-france, 90%); font-weight: $oc-docs-font-weight-normal; @@ -248,21 +265,27 @@ div[class^="rsg--search"] input { color: $color-white; border: 1px solid transparent; background: mix($color-bleu-de-france, $color-rich-black, 20%); + &:focus { border: 1px solid $color-bleu-de-france; + &::-webkit-textfield-decoration-container { display: none !important; } + &::-webkit-contacts-auto-fill-button { display: none !important; } } + &::-webkit-input-placeholder { color: rgba(mix($color-white, $color-bleu-de-france, 50%), 0.35); } + &:-ms-input-placeholder { color: rgba(mix($color-white, $color-bleu-de-france, 50%), 0.35); } + &::-moz-placeholder { color: rgba(mix($color-white, $color-bleu-de-france, 50%), 0.35); opacity: 1; @@ -273,6 +296,7 @@ div[class^="rsg--search"] input { div[class^="rsg--sidebar"] { background: mix($color-bleu-de-france, $color-rich-black, 5%); border: 0; + @media (max-width: #{$docs-breakpoint}) { padding-bottom: $space-l; } @@ -280,6 +304,7 @@ div[class^="rsg--sidebar"] { // Sidebar sub navigations ul ul[class^="rsg--list"] { display: none; + &.vueds-visible { display: block; } @@ -302,21 +327,25 @@ div[class^="rsg--sidebar"] { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + &:hover { color: $color-bleu-de-france-lighter; } + &:active { color: $color-bleu-de-france-dark; } } // Sidebar active link - .vueds-active, li[class*="rsg--isSelected-"] { + .vueds-active, + li[class*="rsg--isSelected-"] { ul[class^="rsg--list"] { display: block; } - & > a, - & > a:hover { + + &>a, + &>a:hover { color: tint($color-bleu-de-france, 80%); } } @@ -329,6 +358,7 @@ div[class^="rsg--sidebar"] { ul { padding-left: $space-s; line-height: $oc-docs-line-height-small; + @media (max-width: #{$docs-breakpoint-small}) { padding: 0 0 0 $space-l; width: 90%; @@ -346,6 +376,7 @@ div[class^="rsg--sidebar"] { font-weight: $oc-docs-font-weight-normal; -webkit-font-smoothing: subpixel-antialiased; -moz-osx-font-smoothing: auto; + @media (max-width: #{$docs-breakpoint-small}) { float: left; padding: 0 $space-xs 0 0; @@ -360,7 +391,7 @@ div[class^="rsg--sidebar"] { // Previews of the components div[class^="rsg--preview"] { - padding: $space-l / 1.2; + padding: calc($space-l / 1.2); background-color: $color-white; border: 1px solid tint($docs-grey, 50%); box-shadow: inset 0 0 $space-xs rgba($color-rich-black, 0.05); @@ -381,7 +412,7 @@ div[data-preview="Elements"] { padding: 0; // This hides code previews from the above examples - & + div + div[class^="rsg--tab"] { + &+div+div[class^="rsg--tab"] { display: none !important; } } @@ -399,13 +430,13 @@ table[class^="rsg--table"] { margin-bottom: $space-s; overflow-x: auto; } + thead[class^="rsg--tableHead"] { border: 0; } // Codemirror and markdown code blocks pre[class^="rsg--pre"], -.vueds-html.cm-s-night.CodeMirror, .react-codemirror2 .CodeMirror.CodeMirror { background: mix($color-bleu-de-france, $color-rich-black, 10%); border-bottom-left-radius: $oc-docs-border-radius-default; @@ -418,30 +449,28 @@ pre[class^="rsg--pre"], font-family: Consolas, "Liberation Mono", Menlo, monospace; font-size: $size-s; margin: 0; - min-height: $space-xxl / 1.5; + min-height: calc($space-xxl / 1.5); margin-bottom: $space-m; color: $color-white; padding: $space-m; word-wrap: break-word; white-space: pre-wrap; word-break: normal; + .CodeMirror-scroll, .CodeMirror-vscrollbar { overflow: hidden; } + code { color: $color-white; } } -// HTML preview needs some padding adjustments to match Styleguidist -.vueds-html.cm-s-night.CodeMirror { - padding-left: $space-m - 4px; -} - // VUE & HTML Code tabs div[class^="rsg--tab"] { position: relative; + .vueds-tabs { z-index: 5; border-radius: $oc-docs-border-radius-default; @@ -450,6 +479,7 @@ div[class^="rsg--tab"] { position: absolute; top: $space-m; right: $space-m; + .vueds-tab { border: 0; margin: 0; @@ -462,12 +492,15 @@ div[class^="rsg--tab"] { cursor: pointer; background: mix($color-bleu-de-france, $color-rich-black, 50%); color: $color-white; + &:active { background: mix($color-bleu-de-france, $color-rich-black, 45%); } + &:focus { outline: none; } + &--active { background: mix($color-bleu-de-france, $color-rich-black, 40%); box-shadow: inset 0 2px 8px rgba($color-rich-black, 0.2); @@ -502,6 +535,7 @@ div[class^="rsg--tab"] { .hljs-name { color: $color-bleu-de-france-light !important; } + .hljs-attribute, .hljs-keyword, .hljs-attr, @@ -510,6 +544,7 @@ div[class^="rsg--tab"] { .cm-s-night span.cm-attribute { color: $color-ucla-gold-light !important; } + .cm-s-night span.cm-string, .hljs-string { color: lighten($docs-status-ready, 20%) !important; @@ -520,11 +555,13 @@ span[class^="rsg--type"], code[class^="rsg--code"] { color: $color-silver; } + span[class^="rsg--name"] code[class^="rsg--code"], code.name { font-weight: $oc-docs-font-weight-bold; color: shade($color-silver, 50%); } + span[class^="rsg--type"] code[class^="rsg--code"], code.type { background: tint($docs-grey, 75%); @@ -540,11 +577,13 @@ code.type { header[class^="rsg--header"] { order: 2; } + div[class^="rsg--docs"], article[class^="rsg--root"], button[class^="rsg--button"] { order: 3; } + div[class^="rsg--root"] div[class^="rsg--tabs"] { order: 4; } @@ -558,7 +597,7 @@ div[class^="rsg--root"] div[class^="rsg--tabs"] { cursor: help; line-height: $oc-docs-line-height-xsmall; background: tint($docs-grey, 50%); - padding: $space-xs $space-s $space-xs/1.2; + padding: $space-xs $space-s calc($space-xs / 1.2); text-transform: uppercase; letter-spacing: 1px; font-size: $size-xs; @@ -568,26 +607,32 @@ div[class^="rsg--root"] div[class^="rsg--tabs"] { right: $space-xl; top: $space-xl * 1.2; z-index: 2; + @media (max-width: 1300px) { top: $space-xl; } + @media (max-width: #{$docs-breakpoint}) { top: $space-l * 1.2; right: $space-m; } + &-ready { background: $docs-status-ready; color: $color-white; } + &-review, &-under-review { background: $color-ucla-gold; color: $color-rich-black; } + &-prototype { background: $color-bleu-de-france; color: $color-white; } + &-deprecated { background: $color-vermilion; color: $color-white; @@ -620,22 +665,27 @@ table[class^="rsg--table"] { color: tint($color-oxford-blue, 10%); text-align: left; } + th[class^="rsg--cellHeading"], td { padding: $space-s $space-l $space-s $space-s; background: transparent; } + td { font-size: $size-m; padding: $space-s $space-l $space-s $space-s; + &:first-child { font-weight: $oc-docs-font-weight-bold; white-space: nowrap; } } + tr { border-bottom: 1px solid tint($docs-grey, 50%); } + tbody tr:last-child { border-bottom: 0; } @@ -646,6 +696,7 @@ thead[class^="rsg--thead"] { border-top-left-radius: $oc-docs-border-radius-default; border-bottom-left-radius: $oc-docs-border-radius-default; } + th:last-child { border-top-right-radius: $oc-docs-border-radius-default; border-bottom-right-radius: $oc-docs-border-radius-default; @@ -668,9 +719,9 @@ div[class^="rsg--toolbar"] { // Hide private components .hide-private, -.hide-private + div, +.hide-private+div, a[href="/#/Private%20Components"], -a[href="/#/Private%20Components"] + ul { +a[href="/#/Private%20Components"]+ul { display: none !important; } @@ -686,4 +737,4 @@ ul a[href*="/#/Private%20Components"] { .oc-docs-width-medium { width: 300px -} +} \ No newline at end of file diff --git a/packages/design-system/docs/getting-started.md b/packages/design-system/docs/getting-started.md index be2d0a92074..0baf9d69e1c 100644 --- a/packages/design-system/docs/getting-started.md +++ b/packages/design-system/docs/getting-started.md @@ -5,5 +5,5 @@ You’re looking at [ownCloud Design System’s](https://owncloud.github.io/ownc ## System Overview ``` - + ``` diff --git a/packages/design-system/docs/icons.md b/packages/design-system/docs/icons.md new file mode 100644 index 00000000000..18067d756db --- /dev/null +++ b/packages/design-system/docs/icons.md @@ -0,0 +1,6 @@ +All known icons in the ownCloud Design System +Icons made by [Remixicon](https://remixicon.com/) and, in the case of the `resource-type-*` icons, [Font Awesome](https://fontawesome.com/) (available under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license). + +```vue + +``` diff --git a/packages/design-system/docs/tokens.md b/packages/design-system/docs/tokens.md index 37a2e0a154a..067075dff9e 100644 --- a/packages/design-system/docs/tokens.md +++ b/packages/design-system/docs/tokens.md @@ -5,23 +5,23 @@ You’re looking at ownCloud Design System’s demo design tokens. ## Color Palette ``` - + ``` ## Font Sizes ``` - + ``` ## Spacing ``` - + ``` ## All Tokens ``` - + ``` diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 73211f0f940..9f4ec6dc267 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -45,14 +45,18 @@ "@babel/plugin-transform-runtime": "7.23.7", "@babel/preset-env": "7.23.7", "@babel/runtime": "7.23.7", + "@codemirror/lang-html": "^6.4.7", + "@codemirror/language": "^6.10.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.23.0", + "@lezer/highlight": "^1.2.0", "@popperjs/core": "^2.11.5", "autoprefixer": "10.4.16", "babel-core": "7.0.0-bridge.0", "babel-jest": "29.5.0", "babel-loader": "^9.0.0", "babel-plugin-require-context-hook": "^1.0.0", - "chalk": "^4.1.0", - "codemirror": "^6.0.0", + "chalk": "^4.1.2", "compression-webpack-plugin": "^10.0.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "6.8.1", @@ -77,45 +81,50 @@ "optimize-css-assets-webpack-plugin": "^6.0.1", "postcss-import": "16.0.0", "postcss-loader": "7.3.4", + "postcss-nested": "^6.0.1", "postcss-safe-parser": "7.0.0", + "postcss-simple-vars": "^7.0.1", "postcss-url": "10.1.3", "prettier": "^3.0.0", "process": "^0.11.10", - "react": "^18.0.0", - "react-dom": "^18.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", "rimraf": "^3.0.2", - "sass": "1.62.1", - "sass-loader": "^10.1.0", - "sass-resources-loader": "^2.0.1", + "sass": "1.69.7", + "sass-loader": "10.1.0", + "sass-resources-loader": "^2.2.5", "semver": "7.5.4", "shelljs": "^0.8.3", - "style-dictionary": "^3.0.0-rc.8", + "style-dictionary": "^3.9.1", "style-loader": "^2.0.0", "style-value-types": "^5.0.0", "stylelint": "15.11.0", "stylelint-config-sass-guidelines": "^10.0.0", "stylelint-config-standard": "^34.0.0", - "tinycolor2": "^1.4.2", + "tinycolor2": "^1.6.0", "tippy.js": "^6.3.7", + "ts-loader": "^9.5.1", "typescript": "5.3.3", + "url": "^0.11.3", "url-loader": "^4.1.1", "v-calendar": "github:dschmidt/v-calendar#3ce6e3b8afd5491cb53ee811281d5fa8a45b044d", "vue": "3.3.8", "vue-inline-svg": "3.1.2", - "vue-loader": "^15.9.0", + "vue-loader": "^17.4.2", "vue-router": "4.2.5", "vue-select": "4.0.0-beta.6", - "vue-style-loader": "^4.1.2", - "vue-styleguidist": "^4.44.2", + "vue-style-loader": "^4.1.3", + "vue-styleguidist": "^4.72.4", "vue3-gettext": "2.4.0", "web-test-helpers": "workspace:*", "webfontloader": "^1.6.28", - "webpack": "^4.41.6", - "webpack-bundle-analyzer": "^4.2.0", - "webpack-merge": "^5.4.0", - "webpack-merge-and-include-globally": "^2.1.24", + "webpack": "^5.89.0", + "webpack-bundle-analyzer": "^4.10.1", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.10.0", + "webpack-merge-and-include-globally": "^2.3.4", "webpack-node-externals": "^3.0.0", - "yaml": "^2.0.0" + "yaml": "^2.3.4" }, "peerDependencies": { "@popperjs/core": "^2.11.5", @@ -129,11 +138,10 @@ "vue": "3.3.8", "vue-inline-svg": "3.1.2", "vue-select": "^3.12.0", - "webfontloader": "^1.6.28", - "portal-vue": "*" + "webfontloader": "^1.6.28" }, "engines": { "node": ">= 14.0.0", "npm": ">= 3.0.0" } -} +} \ No newline at end of file diff --git a/packages/design-system/src/components/OcApplicationIcon/OcApplicationIcon.vue b/packages/design-system/src/components/OcApplicationIcon/OcApplicationIcon.vue index 653dfdb8922..07ad5d307ea 100644 --- a/packages/design-system/src/components/OcApplicationIcon/OcApplicationIcon.vue +++ b/packages/design-system/src/components/OcApplicationIcon/OcApplicationIcon.vue @@ -107,13 +107,13 @@ export default defineComponent({ ```js -No color: (color will be hash generated by icon name) +// No color: (color will be hash generated by icon name) -With primary color: +// With primary color: -With primary and secondary color: +// With primary and secondary color: ``` diff --git a/packages/design-system/src/components/OcAvatars/__snapshots__/OcAvatars.spec.ts.snap b/packages/design-system/src/components/OcAvatars/__snapshots__/OcAvatars.spec.ts.snap index a0b58ccb915..b97ab61ffb9 100644 --- a/packages/design-system/src/components/OcAvatars/__snapshots__/OcAvatars.spec.ts.snap +++ b/packages/design-system/src/components/OcAvatars/__snapshots__/OcAvatars.spec.ts.snap @@ -2,39 +2,21 @@ exports[`OcAvatars displays tooltip 1`] = ` - + List of users `; exports[`OcAvatars prefers avatars over links when maxDisplayed is exceeded 1`] = ` - + List of users `; exports[`OcAvatars shows avatars first and links last 1`] = ` - + List of users `; diff --git a/packages/design-system/src/components/OcModal/OcModal.vue b/packages/design-system/src/components/OcModal/OcModal.vue index 98e81417e5f..bae7075888e 100644 --- a/packages/design-system/src/components/OcModal/OcModal.vue +++ b/packages/design-system/src/components/OcModal/OcModal.vue @@ -77,7 +77,7 @@