My application has the following structure:
There is a main.cpp which loads a file named main.qml from a qrc file.
Contents of the qrc:
/qml/main.qml
/qml/CustomUiElement.qml
/qml/WidgetQmlInQrc.qml
In this main.qml, i'm loading other qml components/files, which are also stored in the qrc. This works as expected.
main.qml
Component.onCompleted:{
var component=Qt.createComponent("WidgetQmlInQrc.qml")
widget=component.createObject(mainWindow,params)
}
I'd like to use qml components/files stored on the local filesystem in my main.qml.
Local qml file: /mnt/plugin/WidgetQmlExternal.qml
import QtQuick 2.0;
Rectangle {
color:"green";
CustomUiElement {
}
}
First i tried to extend the qml import path:
viewer->engine()->addImportPath("/mnt/plugin/");
This did not work.
After that i tried to load the component by using the full path.
Now the WidgetQmlExternal.qml is found and loaded, but it can't find the CustomUiElement.qml because the external qml can't access files in the qrc.
Component.onCompleted:{
var component=Qt.createComponent("/mnt/plugin/WidgetQmlExternal.qml")
widget=component.createObject(mainWindow,params)
}
How can i solve this issue / what do i have to change of the structure of my application to be able to load external components, which again reuse some of my custom components?
I also struggled with this until I realised that you can simply prefix the url to force it to look at the local file system, e.g.
Loader {
source: "file:/mnt/plugin/WidgetQmlExternal.qml"
}
Using this approach, the component loaded by the Loader will be able to access other components withing the QRC as well. Hope that helps.
Here are some options that come to mind:
Load the internal, QRC-based QML file with a Loader
WidgetQmlExternal.qml:
import QtQuick 2.0
Rectangle {
anchors.fill: parent
color: "red"
Loader {
source: "qrc:/WidgetQmlInQrc.qml"
}
}
Interestingly, Qt itself exposes certain assets this way.
Expose the internal, QRC-based QML files as a QML module
You can read more about this here.
Related
I am able to build vue web component and load it in other pages, but I can't find document how to correctly include a UI framework. It seems the web component is under shadowDOM and import css using style tag won't work.
(Add the CDN link in the template and style is applied)
Any hint on any framework, Vuetify or Ant Design or Tailwind CSS will be appreciated.
Similar question: Vuetify build as Web component style not showing
Using custom elements without Shadow DOM is trivial. Just add like the way you do traditionally. However, with Shadow DOM, things are tricky. Only inheritable CSS styles pass through the Shadow DOM. Everything else is blocked. No straight forward integration with existing design systems (Vuetify, Ant, etc.) is not directly possible if that library is only exposing global CSS.
If the design system or a component library is exposing styles i.e. css files for individual components, then you can that with some effort.
The best solution is to use constructable stylesheet. You can use a bundler like Webpack to load the stylesheet for individual component (if and only if it is provided) as a string and feed it to the stylesheet constructor method as illustrated here.
// Read SCSS file as a raw CSS text using Webpack/Rollup/Parcel
import styleText from './my-component.scss';
const sheet = new CSSStyleSheet();sheet.replaceSync(styleText);
// Use the sheet inside the web component constructor
shadowRoot.adoptedStyleSheets = [sheet];
However, Firefox and Safari are yet to implement it.
If you need a fallback, then there are ways that are not so clean. Approach is same. Import the CSS/SCSS as a string and using the template literal, add it to the element's inner style tag.
import styleText from 'ant/button.css';
class FancyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
<!-- Styles are scoped -->
<style>
${styleText}
</style>
<div>
<p>Hello World</p>
</div>
`;
}
}
customElements.define('fancy-comp', FacyComponent);
This all relies on the assumption that ant/material/veutify is exposing styles as individual files instead of one global file.
Alternately, the browsers have started supporting the link tag inside the Shadow DOM. But again it is really useful if you have styles for individual components. Read more about that here.
I 've added custom page and js for it in stencil bigcommerce.
It works fine locally but when I push it on bigcommerce, it does not work well.
I have added custom template template/pages/custom/page/custom-layout.html and I've added custom js for it in assets/js/custom/custom.js.
I've configured some loading settings in assets/js/app.js as follows:
const customClasses = {
'pages\\custom\\page\\custom-layout': () => import('./custom/custom')
}
It works locally; but, on a server, it does not at all.
Your customClasses object should use forward slashes like so:
"pages/custom/page/custom-layout": () => import("./custom/custom")
You should also make sure that your custom.js file is extending the PageManager class like so:
import PageManager from "../page-manager";
export default class CustomClass extends PageManager {
constructor(context) {
super(context);
// other constructor code here
}
onReady() {
// your code for the onReady event here
}
// ... any other code
}
If this is done properly your custom JS class will be injected to the page. However, once you bundle and upload your theme, you must also make sure to apply your custom template to the page, as the config.stencil.json file is not packaged with your theme. This can be done from within the BigCommerce control panel by going to Storefront > Web Pages > [Your page] and changing the Template Layout File accordingly.
While trying to render a custom HTML tag <my-element> in JSX an error displayed
Property does not exist on type 'JSX.IntrinsicElements'
I've found some examples of how to do that using
declare global {
interface IntrinsicElements {
"my-element": any
}
}
but this produced another error:
ES2015 module syntax is preferred over custom TypeScript modules and namespaces #typescript-eslint/no-namespace
I've found the useful link to Typescript guide which helped me a lot:
The main idea is to create a new file with extension d.ts (e.g. myModule.d.ts) which should contain the following
export as namespace JSX;
export interface IntrinsicElements {
"my-element": any;
}
I have a Vue.js + Electron app (electron-vue boilerplate)
What are the best practices of getting and displaying directory's folders and files?
Basically I want it to behave like a File Explorer (Windows) or Finder (Mac). You open a folder you get all the content displayed.
Let's say we have:
the main view called App.vue with a router inside of it.
there's an open folder button in App.vue.
And we also have FileExplorer.vue component that is getting displayed as a route inside that App.vue
How do I make this FileExplorer.vue component to get and display files and folders of, let's say, directory C:\test folder (on Windows) when we hit that open folder button in App.vue?
I know that I should use Node for that, but how exactly? What do I import and how do I use Vue to make it all work together?
All the projects on Github are too complicated for a newbie to understand how they work. For example this one is quite simple looking, but there's so much code in there that you don't even know where to start
Update:
I managed to get the content of a folder doing this:
<v-btn #click="readDirectory"></v-btn>
[...]
const fs = require('fs-extra')
export default {
name: "FileExplorer",
data () {
return {
dir:'C:/test',
files:[],
file:""
}
},
methods: {
readDirectory() {
fs.readdir(this.dir, (err, dir) => {
console.log(dir);
for(let filePath of dir)
console.log(filePath)
this.files = dir
})
},
}
}
And I displayed it like this:
<v-btn v-for="file in files" :key="file.id">
{{file}}
</v-btn>
But it doesn't really behave like a real file explorer...I get the folders and files on button click but I can't do anything with all those folders and files.
How do I make all the folders that it gets on click to behave in a similar way (to get its content) ?
And how do I display folders and files differently?
If you simply want to allow a user to select a folder in Electron I would suggest using the showOpenDialog API.
In the renderer process, you need to use the remote API to access the dialog API.
const { remote } = require('electron')
remote.dialog.showOpenDialog({
properties: ['openDirectory'],
defaultPath: current
}, names => {
console.log('selected directory:' + names[0]);
});
If you want to display the contents of a directory within your app you're going to have to use the node fs module and read the directory contents.
fs.readdir(path[, options], callback)
Will callback with all the file and directory paths which you'll then have to iterate over to get more info or to traverse recursively to get their contents. There are are node modules which make this process a little easier than writing it all yourself.
Once you've got an object tree containing all your files and directories you can use this to create a UI using vue.js.
I'm facing an issue when I try to bundle Aurelia-hammer with the CLI.
The app still keeps pulling hammer-swipe.js, hammer-tap.js,... from the node_modules folder.
When I inspect the plugin's AMD structure, these are defined as global resources:
function configure(frameworkConfig) {
frameworkConfig.globalResources('./hammer-swipe');
frameworkConfig.globalResources('./hammer-tap');
frameworkConfig.globalResources('./hammer-press');
frameworkConfig.globalResources('./hammer-hold');}
Is there any way to bundle these with the CLI? I tried adding these files to the "resources" element in aurelia.json without success.
the plugin author should export those classes: (HammerPressCustomAttribute...) so they could be traced properly. But you can dummy-import theme yourself as a workaround:
import { HammerPressCustomAttribute } from 'aurelia-hammer/hammer-press';
import { HammerSwipeCustomAttribute } from 'aurelia-hammer/hammer-swipe';
import { HammerTapeCustomAttribute } from 'aurelia-hammer/hammer-tap';
normally you have to do this as well:
import { HammerHoldCustomAttribute } from 'aurelia-hammer/hammer-hold';
but the class exported from hammer-hold.js is named HammerPressCustomAttribute (oops looks like copy-paste issue) so just reference the file even with a non existent class.
import { HammerHoldCustomAttribute } from 'aurelia-hammer/hammer-hold';
this should fix your problem (I hope). It's best to open an issue in the plugin repo and ask the author to export those classes (and rename the duplicate one).