feat(Storybook): add basic Figma integration
After setting Figma private token, Figma desings related to a given Storybook page can be browsed directly via the Storybook app. Closes: #8188
This commit is contained in:
parent
ff9c678a1e
commit
ec38dca735
|
@ -31,10 +31,40 @@ ApplicationWindow {
|
||||||
|
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "ProfileDialogView"
|
title: "ProfileDialogView"
|
||||||
|
|
||||||
|
figma: [
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=733%3A12552"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=682%3A15078"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=682%3A17655"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=682%3A17087"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A23525"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A23932"
|
||||||
|
}
|
||||||
|
]
|
||||||
section: "Views"
|
section: "Views"
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "CommunitiesPortalLayout"
|
title: "CommunitiesPortalLayout"
|
||||||
|
|
||||||
|
figma: [
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=8159%3A415655"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=8159%3A415935"
|
||||||
|
}
|
||||||
|
]
|
||||||
section: "Views"
|
section: "Views"
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
|
@ -55,6 +85,15 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "StatusCommunityCard"
|
title: "StatusCommunityCard"
|
||||||
|
|
||||||
|
figma: [
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=8159%3A416159"
|
||||||
|
},
|
||||||
|
ListElement {
|
||||||
|
link: "https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=8159%3A416160"
|
||||||
|
}
|
||||||
|
]
|
||||||
section: "Panels"
|
section: "Panels"
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
|
@ -87,48 +126,54 @@ ApplicationWindow {
|
||||||
SplitView {
|
SplitView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
ColumnLayout {
|
Pane {
|
||||||
SplitView.preferredWidth: 240
|
SplitView.preferredWidth: 270
|
||||||
|
|
||||||
CheckBox {
|
ColumnLayout {
|
||||||
id: loadAsyncCheckBox
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: "Load asynchronously"
|
text: "Settings"
|
||||||
}
|
|
||||||
|
|
||||||
CheckBox {
|
onClicked: settingsPopup.open()
|
||||||
id: darkModeCheckBox
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: "Dark mode"
|
|
||||||
|
|
||||||
StatusLightTheme { id: lightTheme }
|
|
||||||
StatusDarkTheme { id: darkTheme }
|
|
||||||
|
|
||||||
Binding {
|
|
||||||
target: Theme
|
|
||||||
property: "palette"
|
|
||||||
value: darkModeCheckBox.checked ? darkTheme : lightTheme
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
HotReloaderControls {
|
CheckBox {
|
||||||
id: hotReloaderControls
|
id: darkModeCheckBox
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
onForceReloadClicked: reloader.forceReload()
|
text: "Dark mode"
|
||||||
}
|
|
||||||
|
|
||||||
Pane {
|
StatusLightTheme { id: lightTheme }
|
||||||
Layout.fillWidth: true
|
StatusDarkTheme { id: darkTheme }
|
||||||
Layout.fillHeight: true
|
|
||||||
|
Binding {
|
||||||
|
target: Theme
|
||||||
|
property: "palette"
|
||||||
|
value: darkModeCheckBox.checked ? darkTheme : lightTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HotReloaderControls {
|
||||||
|
id: hotReloaderControls
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
onForceReloadClicked: reloader.forceReload()
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSeparator {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
FilteredPagesList {
|
FilteredPagesList {
|
||||||
anchors.fill: parent
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
currentPage: root.currentPage
|
currentPage: root.currentPage
|
||||||
model: pagesModel
|
model: pagesModel
|
||||||
|
|
||||||
|
@ -137,7 +182,7 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Page {
|
||||||
SplitView.fillWidth: true
|
SplitView.fillWidth: true
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
@ -147,7 +192,7 @@ ApplicationWindow {
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
source: `pages/${root.currentPage}Page.qml`
|
source: `pages/${root.currentPage}Page.qml`
|
||||||
asynchronous: loadAsyncCheckBox.checked
|
asynchronous: settingsLayout.loadAsynchronously
|
||||||
visible: status === Loader.Ready
|
visible: status === Loader.Ready
|
||||||
|
|
||||||
// force reload when `asynchronous` changes
|
// force reload when `asynchronous` changes
|
||||||
|
@ -167,13 +212,107 @@ ApplicationWindow {
|
||||||
visible: viewLoader.status === Loader.Error
|
visible: viewLoader.status === Loader.Error
|
||||||
text: "Loading page failed"
|
text: "Loading page failed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer: PageToolBar {
|
||||||
|
id: pageToolBar
|
||||||
|
|
||||||
|
title: `pages/${root.currentPage}Page.qml`
|
||||||
|
figmaPagesCount: currentPageModelItem.object
|
||||||
|
? currentPageModelItem.object.figmaCount : 0
|
||||||
|
|
||||||
|
Instantiator {
|
||||||
|
id: currentPageModelItem
|
||||||
|
|
||||||
|
model: SingleItemProxyModel {
|
||||||
|
sourceModel: pagesModel
|
||||||
|
roleName: "title"
|
||||||
|
value: root.currentPage
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: QtObject {
|
||||||
|
readonly property string title: model.title
|
||||||
|
readonly property var figma: model.figma
|
||||||
|
readonly property int figmaCount: figma ? figma.count : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFigmaPreviewClicked: {
|
||||||
|
if (!settingsLayout.figmaToken) {
|
||||||
|
noFigmaTokenDialog.open()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const window = figmaWindow.createObject(root, {
|
||||||
|
figmaModel: currentPageModelItem.object.figma,
|
||||||
|
title: currentPageModelItem.object.title + " - Figma"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: settingsPopup
|
||||||
|
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
width: 420
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
header: Pane {
|
||||||
|
background: null
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Settings"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsLayout {
|
||||||
|
id: settingsLayout
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: noFigmaTokenDialog
|
||||||
|
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
|
||||||
|
title: "Figma token not set"
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Please set Figma personal token in \"Settings\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FigmaLinksCache {
|
||||||
|
id: figmaImageLinksCache
|
||||||
|
|
||||||
|
figmaToken: settingsLayout.figmaToken
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: figmaWindow
|
||||||
|
|
||||||
|
FigmaPreviewWindow {
|
||||||
|
property alias figmaModel: figmaImagesProxyModel.sourceModel
|
||||||
|
|
||||||
|
model: FigmaImagesProxyModel {
|
||||||
|
id: figmaImagesProxyModel
|
||||||
|
|
||||||
|
figmaLinksCache: figmaImageLinksCache
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing: Qt.callLater(destroy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
property alias currentPage: root.currentPage
|
property alias currentPage: root.currentPage
|
||||||
property alias loadAsynchronously: loadAsyncCheckBox.checked
|
property alias loadAsynchronously: settingsLayout.loadAsynchronously
|
||||||
property alias darkMode: darkModeCheckBox.checked
|
property alias darkMode: darkModeCheckBox.checked
|
||||||
property alias hotReloading: hotReloaderControls.enabled
|
property alias hotReloading: hotReloaderControls.enabled
|
||||||
|
property alias figmaToken: settingsLayout.figmaToken
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
/* required */ property FigmaLinksCache figmaLinksCache
|
||||||
|
property alias sourceModel: d.model
|
||||||
|
|
||||||
|
readonly property Instantiator _d: Instantiator {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
model: 0
|
||||||
|
|
||||||
|
delegate: QtObject {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
append({
|
||||||
|
rawLink: model.link,
|
||||||
|
imageLink: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
figmaLinksCache.getImageUrl(model.link, link => {
|
||||||
|
if (delegate)
|
||||||
|
setProperty(model.index, "imageLink", link)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onObjectRemoved: console.warn("FigmaImagesProxyModel: removing items from the source model is not supported!")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
import QtQml 2.14
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string figmaToken
|
||||||
|
|
||||||
|
readonly property QtObject _d: QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property var linksMap: new Map()
|
||||||
|
|
||||||
|
function createKey(file, nodeId) {
|
||||||
|
return file + "/" + nodeId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImageUrl(figmaLink, cb) {
|
||||||
|
const { file, nodeId } = FigmaUtils.decomposeLink(figmaLink)
|
||||||
|
const key = d.createKey(file, nodeId);
|
||||||
|
|
||||||
|
if (d.linksMap.has(key)) {
|
||||||
|
cb(d.linksMap.get(key))
|
||||||
|
} else {
|
||||||
|
FigmaUtils.getLinks(root.figmaToken, file, [nodeId],
|
||||||
|
(err, result) => {
|
||||||
|
if (err)
|
||||||
|
return cb(null)
|
||||||
|
|
||||||
|
for (const value of Object.values(result)) {
|
||||||
|
d.linksMap.set(key, value)
|
||||||
|
return cb(value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: 1024
|
||||||
|
height: 768
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
property var model
|
||||||
|
|
||||||
|
SwipeView {
|
||||||
|
id: topSwipeView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
ImagesGridView {
|
||||||
|
clip: true
|
||||||
|
model: root.model
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
imagesSwipeView.setCurrentIndex(index)
|
||||||
|
topSwipeView.incrementCurrentIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
SwipeView {
|
||||||
|
id: imagesSwipeView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
currentIndex: imageNavigationLayout.currentIndex
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: repeater
|
||||||
|
|
||||||
|
model: root.model
|
||||||
|
|
||||||
|
FlickableImage {
|
||||||
|
source: model.imageLink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagesNavigationLayout {
|
||||||
|
id: imageNavigationLayout
|
||||||
|
|
||||||
|
anchors.bottom: imagesSwipeView.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
count: imagesSwipeView.count
|
||||||
|
currentIndex: imagesSwipeView.currentIndex
|
||||||
|
|
||||||
|
onUp: topSwipeView.decrementCurrentIndex()
|
||||||
|
onLeft: imagesSwipeView.decrementCurrentIndex()
|
||||||
|
onRight: imagesSwipeView.incrementCurrentIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQml 2.14
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
function decomposeLink(link) {
|
||||||
|
const fileRegex = /www\.figma\.com\/file\/([a-zA-Z0-9]+)/
|
||||||
|
const fileMatch = link.match(fileRegex)
|
||||||
|
|
||||||
|
const nodeIdRegex = /node-id=([0-9A-Za-z%]+)/
|
||||||
|
const nodeIdMatch = link.match(nodeIdRegex)
|
||||||
|
|
||||||
|
return {
|
||||||
|
file: fileMatch[1],
|
||||||
|
nodeId: nodeIdMatch[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLinks(token, file, nodeIds, cb) {
|
||||||
|
|
||||||
|
console.assert(nodeIds.length > 0)
|
||||||
|
|
||||||
|
const ids = nodeIds.join()
|
||||||
|
const url = `https://api.figma.com/v1/images/${file}?ids=${ids}`
|
||||||
|
|
||||||
|
const http = new XMLHttpRequest()
|
||||||
|
http.open("GET", url, true)
|
||||||
|
http.setRequestHeader("X-FIGMA-TOKEN", token)
|
||||||
|
|
||||||
|
http.onreadystatechange = () => {
|
||||||
|
if (http.readyState !== 4)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (http.status === 200)
|
||||||
|
cb(null, JSON.parse(http.response).images)
|
||||||
|
else
|
||||||
|
cb(`Failed to fetch figma image links, status: ${http.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.send()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property alias source: image.source
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "lightgray"
|
||||||
|
}
|
||||||
|
|
||||||
|
Flickable {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
contentWidth: image.implicitWidth
|
||||||
|
contentHeight: image.implicitHeight
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ScrollIndicator.vertical: ScrollIndicator {}
|
||||||
|
ScrollIndicator.horizontal: ScrollIndicator {}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
running: image.status !== Image.Ready
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
cellWidth: 400
|
||||||
|
cellHeight: 300
|
||||||
|
|
||||||
|
signal clicked(int index)
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
width: root.cellWidth
|
||||||
|
height: root.cellHeight
|
||||||
|
|
||||||
|
Frame {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: padding / 2
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
mipmap: true
|
||||||
|
|
||||||
|
source: model.imageLink
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
running: image.status !== Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: root.clicked(model.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundButton {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
text: "🔗"
|
||||||
|
|
||||||
|
onClicked: Qt.openUrlExternally(model.rawLink)
|
||||||
|
|
||||||
|
ToolTip.delay: 1500
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: model.rawLink
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias count: indicator.count
|
||||||
|
property alias currentIndex: indicator.currentIndex
|
||||||
|
|
||||||
|
signal up
|
||||||
|
signal left
|
||||||
|
signal right
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
RoundButton {
|
||||||
|
text: "⬅"
|
||||||
|
enabled: root.currentIndex !== 0
|
||||||
|
onClicked: root.left()
|
||||||
|
}
|
||||||
|
RoundButton {
|
||||||
|
text: "⬆"
|
||||||
|
onClicked: root.up()
|
||||||
|
}
|
||||||
|
RoundButton {
|
||||||
|
text: "➡"
|
||||||
|
enabled: root.currentIndex !== root.count - 1
|
||||||
|
onClicked: root.right()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PageIndicator {
|
||||||
|
id: indicator
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
interactive: true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
ToolBar {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string title
|
||||||
|
property int figmaPagesCount: 0
|
||||||
|
|
||||||
|
signal figmaPreviewClicked
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: root.title
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
selectByMouse: true
|
||||||
|
readOnly: true
|
||||||
|
background: null
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolSeparator {}
|
||||||
|
|
||||||
|
ToolButton {
|
||||||
|
id: openFigmaButton
|
||||||
|
|
||||||
|
enabled: root.figmaPagesCount
|
||||||
|
text: `Figma designs (${root.figmaPagesCount})`
|
||||||
|
|
||||||
|
onClicked: root.figmaPreviewClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
property alias loadAsynchronously: loadAsyncCheckBox.checked
|
||||||
|
property alias figmaToken: figmaTokenTextInput.text
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: loadAsyncCheckBox
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: "Load pages asynchronously"
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupBox {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
title: "Figma token"
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: `Figma token can be obtained <a href=\"https://www.figma.com/developers/api#access-tokens\">here</a>
|
||||||
|
by clicking \"Get personal access token\". It's necessary to fetch figma data via Figma API.`
|
||||||
|
|
||||||
|
onLinkActivated: Qt.openUrlExternally(link)
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: figmaTokenTextInput
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
placeholderText: "Figma personal access token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
|
SortFilterProxyModel {
|
||||||
|
property alias roleName: valueFilter.roleName
|
||||||
|
property alias value: valueFilter.value
|
||||||
|
|
||||||
|
filters: ValueFilter {
|
||||||
|
id: valueFilter
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,24 @@
|
||||||
CompilationErrorsBox 1.0 CompilationErrorsBox.qml
|
CompilationErrorsBox 1.0 CompilationErrorsBox.qml
|
||||||
|
FigmaImagesProxyModel 1.0 FigmaImagesProxyModel.qml
|
||||||
|
FigmaLinksCache 1.0 FigmaLinksCache.qml
|
||||||
|
FigmaPreviewWindow 1.0 FigmaPreviewWindow.qml
|
||||||
FilteredPagesList 1.0 FilteredPagesList.qml
|
FilteredPagesList 1.0 FilteredPagesList.qml
|
||||||
|
FlickableImage 1.0 FlickableImage.qml
|
||||||
HotComponentFromSource 1.0 HotComponentFromSource.qml
|
HotComponentFromSource 1.0 HotComponentFromSource.qml
|
||||||
HotLoader 1.0 HotLoader.qml
|
HotLoader 1.0 HotLoader.qml
|
||||||
HotReloader 1.0 HotReloader.qml
|
HotReloader 1.0 HotReloader.qml
|
||||||
HotReloaderControls 1.0 HotReloaderControls.qml
|
HotReloaderControls 1.0 HotReloaderControls.qml
|
||||||
ImageSelectPopup 1.0 ImageSelectPopup.qml
|
ImageSelectPopup 1.0 ImageSelectPopup.qml
|
||||||
|
ImagesGridView 1.0 ImagesGridView.qml
|
||||||
|
ImagesNavigationLayout 1.0 ImagesNavigationLayout.qml
|
||||||
Logs 1.0 Logs.qml
|
Logs 1.0 Logs.qml
|
||||||
LogsAndControlsPanel 1.0 LogsAndControlsPanel.qml
|
LogsAndControlsPanel 1.0 LogsAndControlsPanel.qml
|
||||||
LogsView 1.0 LogsView.qml
|
LogsView 1.0 LogsView.qml
|
||||||
|
PageToolBar 1.0 PageToolBar.qml
|
||||||
PagesList 1.0 PagesList.qml
|
PagesList 1.0 PagesList.qml
|
||||||
PopupBackground 1.0 PopupBackground.qml
|
PopupBackground 1.0 PopupBackground.qml
|
||||||
|
SettingsLayout 1.0 SettingsLayout.qml
|
||||||
|
SingleItemProxyModel 1.0 SingleItemProxyModel.qml
|
||||||
SourceCodeBox 1.0 SourceCodeBox.qml
|
SourceCodeBox 1.0 SourceCodeBox.qml
|
||||||
|
singleton FigmaUtils 1.0 FigmaUtils.qml
|
||||||
singleton StorybookUtils 1.0 StorybookUtils.qml
|
singleton StorybookUtils 1.0 StorybookUtils.qml
|
||||||
|
|
Loading…
Reference in New Issue