Quiescent with devcards making cards go wonky - reactjs

I'm using the quiescent library as my react wrapper. I was wanting to use devcards, and I was sort of hoping it would just work, even thought there isn't really a macro for quiescent like there is for om (i don't really know much about devcards yet).
Anyway, I got it all setup with figwheel and everything, and it's sort of working, but the cards ui is a little wacky:
First, here's what i think is the relative code:
(ns punt.core
(:require [quiescent.core :as q]
[quiescent.dom :as d])
(:require-macros [devcards.core :refer [defcard]]))
(def div1 (d/div {}
(d/h1 {} "hello")
(d/p {} "paragraph")
(d/h2 {} "second header")
(d/p {} "another paragraph")))
(def div2 (d/div {}
(d/h1 {} "a better hello")
(d/p {} "my favorite pargrauph")))
(q/defcomponent vertical-split [left right percentage]
(d/div {}
(d/div {:style {:float "left"
:width (str percentage "%")
:height "400px"}}
left)
(d/div {:style {:float "right"
:width (str (- 100 percentage) "%")
:height "400px"}}
right)))
(defcard fifty-fifty
"Description"
(vertical-split div1 div2 50))
(defcard fifty-fifty
(vertical-split div1 div2 80))
Now the content of the cards looks how I would expect, but the title bar of each card is extending a little crazy. Actually a picture is more helpful than explaining it, so here you go:
My diagnosis is that somehow devcards doesn't recognize the html that i made with quiescent, so it just doesn't put it in the card. Then it renders html for some reason, and then the next card is rendered, and i guess the title bar is programmed to extend all the way to the previous card, hence overlapping the stuff I made.
So guess my basic question is how to use quiescent with devcards.

The answer is so simple it's astounding, and it shows my lack of html and css knowledge. By making the container divs use overflow: auto they will expand the card to contain the actual content.

Related

Pause in the middle of a Clojure doseq function?

My program allows users to select files to import into a database. Before now, it only allowed them to import one file at a time. Letting them import more than one file at a time is easy. But the problem I have is that if the database already contains a page with the same title, I want to display a warning and get confirmation before overwriting the version in the database with the one being imported.
Here's what I have so far. It largely follows what I was doing to import single files.
;; Handler for the POST "/import" route.
(defn- post-import-page
"Import the file(s) specified in the upload dialog. Checks the page
title of the import file against existing pages in the database. If
a page of the same name already exists, asks for confirmation before
importing."
[{{file-info "file-info"
referer "referer"} :multipart-params :as req}]
(let [file-vec (if (map? file-info)
(conj [] file-info)
file-info)]
(doseq [fm file-vec]
(let [file-name (:filename fm)
import-map (files/load-markdown-from-file (:tempfile fm))
page-title (get-in import-map [:meta :title])
id-exists? (db/title->page-id page-title)]
(if id-exists?
(build-response
(layout/compose-import-existing-page-warning
import-map file-name referer) req)
(do-the-import import-map file-name req))))))
This function imports any files that don't already exist in the database, but doesn't import anything that would overwrite an existing database entry with the same title. It never shows the warning page asking for confirmation either.
The warning page is constructed like this:
(defn compose-import-existing-page-warning
"Return a page stating that a page with the same title already exists
in the wiki. Ask the user to proceed or cancel the import."
[import-map file-name referer]
(short-form-template
[:div {:class "cwiki-form"}
(form-to {:enctype "multipart/form-data"
:autocomplete "off"}
[:post "proceed-with-import"]
(hidden-field "import-map" import-map)
(hidden-field "file-name" file-name)
(hidden-field "referer" referer)
[:p {:class "form-title"} "Page Already Exists"]
[:div {:class "form-group"}
[:p (str "A page with the title \"" (get-in import-map [:meta :title])
"\" already exists in the wiki.")]
[:p (str "Click \"Proceed\" to delete the existing page and "
"replace it with the contents of the imported file.")]
[:div {:class "button-bar-container"}
(submit-button {:id "proceed-with-import-button"
:class "form-button button-bar-item"}
"Proceed")
[:input {:type "button" :name "cancel-button"
:value "Cancel"
:class "form-button button-bar-item"
:autofocus "autofocus"
:onclick "window.history.back();"}]]])]))
How would the program be paused in the middle of the doseq (or other looping function) to display the confirmation page and wait for the user to make a selection?
Just use read-line in the middle of your loop, and then an if to choose the branching you want. Here is a list of other documentation you may find useful, especially the Clojure CheatSheet.

Changing Choregraphe Dialog Confidence Interval for Nao

I am currently working with a Nao robot using Choregraphe and am trying to lower the confidence interval required to act upon a request made through QiChat from the default 50% to 30%.
I have found this solution, https://community.ald.softbankrobotics.com/en/forum/change-speech-engine-confidence-threshold-choregraphe-dialog-8624, but unfortunately the scripting functionality for Dialog boxes is deprecated in Choregraphe v2.1. Does anyone know what the "new" way to do this is?
I have found the solution. Scripting for Dialog boxes is not allowed but you can add a Python script before the Dialog box to change this interval. The code that should go in this box is below.
class MyClass(GeneratedClass):
def __init__(self):
GeneratedClass.__init__(self)
def onLoad(self):
#put initialization code here
pass
def onUnload(self):
#put clean-up code here
pass
def onInput_onStart(self):
# Lower confidence threshold from 50% to 30%
ALDialog = ALProxy('ALDialog')
ALDialog.setASRConfidenceThreshold(0.3)
self.onStopped() #activate the output of the box
def onInput_onStop(self):
self.onUnload() #it is recommended to reuse the clean-up as the box is stopped
self.onStopped() #activate the output of the box
Two solutions to increase recognition rate:
1) Add more variants to your input - for example, if you're listening for "yes", you should also make sure you listen for "yep", "yup", "yeah", "sure", "okay", "fine", etc. - concepts are useful for that, see the qichat doc.
1) as you suggest, set the confidence threshold - for a more compact version (I prefer less boilerplate):
class MyClass(GeneratedClass):
def onInput_onStart(self):
# Lower confidence threshold from 50% to 30%
ALProxy('ALDialog').setASRConfidenceThreshold(0.3)
self.onStopped() # activate the output of the box
HOWEVER, note that this is not very elegant; you will need to reset it, and it greatly increases the risk of false positives, so you should only use this if you can't solve it just by adding more variants.
setASRConfidenceThreshold is for Nao V5; in Pepper and Nao V6 you should use setConfidenceThreshold:
class MyClass(GeneratedClass):
def onInput_onStart(self):
# Lower confidence threshold from 50% to 30%
ALProxy('ALDialog').setConfidenceThreshold("BNF", 0.3)
self.onStopped() # activate the output of the box

Importing a native React Component

I am trying to use a React component from React Bootstrap in my rum app.
In my macros namespace I have some code that I found on the rum gitter :
(defn ->kebab [s]
(str/join "-" (map str/lower-case (re-seq #"\w[a-z]+" s))))
(defn gen-wrapper [component]
`(defmacro ~(symbol (->kebab (str component))) [& args#]
(let [[opts# & [children#]] (if (-> args# first map?)
[(first args#) (rest args#)]
[nil args#])]
`(js/React.createElement
~(symbol "js" (str "window.ReactBootstrap." (name '~component)))
(cljs.core/clj->js ~opts#)
~#children#))))
(def components '[Button
])
(defmacro gen-wrappers []
`(do
~#(clojure.core/map gen-wrapper components)))
Then in my devcard namespace I have:
(pm/gen-wrappers)
(rum/defc foo []
[:div (button nil "bggg")])
(defcard foo "" (foo))
The error is:
react.inc.js:18342 Uncaught Error: Invariant Violation: Objects are
not valid as a React child (found: js/React.createElement). If you
meant to render a collection of children, use an array instead or wrap
the object using createFragment(object) from the React add-ons. Check
the render method of foo.
This turned out to be an issue with clojurescript macros. Note that the macro gen-wrappers itself expands to a series of macros -- in this case the button macro. But in clojurescript, you can't call a macro that was defined in the same compilation stage, which I unfortunately tried to do by calling button right away.
The solution was to move the gen-wrappers call into the macros file along with the other macros:
(defmacro gen-wrappers []
`(do
~#(clojure.core/map gen-wrapper components)))
(gen-wrappers)
And then call the fully qualified pm/button from my devcard namespace.
(rum/defc foo []
[:div (pm/button nil "bggg")])
"But wait!" you say. "Aren't you making the same mistake here of calling one macro (gen-wrappers) from the same compilation stage it was defined in? Actually no, because in clojurescript, macros are defined in clojure files, in which that restriction does not apply.

How to propagate text in input onChange with React/Om

As a React/Om newbie I am not sure if this issue is Om-specific.
I want to build a date entry component based on free text entry. It includes an <input> field where they can type, and a <p> displaying the parsed date (if it's valid).
I implemented it as:
(defn parse-date [e owner]
(let [text (.. e -target -value)]
(om/set-state! owner :parsed-date text)))
(defn date-entry [app owner]
(reify
om/IInitState
(init-state [_] {:parsed-date ""})
om/IRenderState
(render-state [this state]
(dom/div nil
(dom/input #js {:type "text"
:ref "date"
:id "new-date"
:onChange #(parse-date % owner)})
(dom/p nil (:parsed-date state))))))
Unfortunately, as soon as I plug this change handler in, it doesn't behave as expected. When I type a digit in the input field, I can see it appear in the input and the <p> next to it, but then it disappears from the input immediately.
I am able to work it around by putting the text on state:
(defn parse-date [e owner]
(let [text (.. e -target -value)]
(om/set-state! owner :parsed-date text)
(om/set-state! owner :text text)))
(defn date-entry [app owner]
(reify
om/IInitState
(init-state [_] {:parsed-date "" :text ""})
om/IRenderState
(render-state [this state]
(dom/div nil
(dom/input #js {:type "text"
:ref "date"
:id "new-date"
:onChange #(parse-date % owner)
:value (:text state)})
(dom/p nil (:parsed-date state))))))
However, I am surprised I had to do it. Is it really necessary? Can someone please explain what's going on here or point me to relevant docs? Why does plugging in a change handler calling set-state! swallow the event?
Yes it's necessary. Every time the state changes, DOM re-renders and clears your input's value. So if you have no :value in your :input's attributes, it will be cleared.
The reason for this is that when React.js starts diffing the real DOM, with the virtual one, it finds that there's some value in the real attribute, while there is none in the virtual DOM, and therefore it clears it, assuming that's what you want. You should always be explicit about what the DOM should look like (eg. your 2nd snippet).

hexagon buttons in GTK+

I am trying to create a button in GTK+ that has the shape of a Hexagon.
How can I do it without using CSS?
And more general, how can I create my button in any shape I want?
Is it possible to do such things in Glade(User interface edior for GTK+)?
When I put my comment I was bluffing because I never did the circular button.. I just did an example of an Hexagonal button using my original idea.. I got surprised that it was simpler than I thought!
( and by the way, no, it is not possible to do it in glade! )
# sorry but the example is in Python! :/
from gi.repository import Gtk
def hexagon(coord_x, coord_y):
# because of the symetry I take only the absolute value
coord_x, coord_y= abs(coord_x), abs(coord_y)
# I got the constants by clicling in the image and printing the coord_x and coord_y values
if coord_x <= 13 and coord_y <= 25: # define a rectangle
return True
else:
# I cut the coord x to define a triangle
coord_x=coord_x-13/2
# line equation
ymax=(-25/31)*coord_x+25
if coord_y < ymax:
return True
else:
return False
class GUI(Gtk.Window):
def __init__(self):
self.window_root=Gtk.Window()
# Create an event box to handle the click's
self.eventbox=Gtk.EventBox()
self.eventbox.connect('button-press-event' , self.on_eventbox_pressed)
self.eventbox.connect('button-release-event' , self.on_eventbox_released)
# Load the images
self.hexagon1=Gtk.Image.new_from_file('./3uSFN.png')
self.hexagon2=Gtk.Image.new_from_file('./cWmUA.png')
# init the event box
self.eventbox.add(self.hexagon1)
self.window_root.add(self.eventbox)
self.window_root.show_all()
# a variable to store the state of the button
self.state=False
def on_eventbox_pressed(self, widget , event):
if 'GDK_BUTTON_PRESS' in str(event.type): # If the user made a "single click"
if event.button == 1: # if it is a left click
# get the x,y of the mouse from the center of the image
pos_x, pos_y=self.window_root.get_position()
siz_x, siz_y=self.window_root.get_size()
mouse_x,mouse_y=event.x-siz_x/2, siz_y/2-event.y
if hexagon(mouse_x, mouse_y):
self.eventbox.remove(self.hexagon1)
self.eventbox.add(self.hexagon2)
self.eventbox.show_all()
self.state=True
def on_eventbox_released(self, widget , event):
if self.state:
self.eventbox.remove(self.hexagon2)
self.eventbox.add(self.hexagon1)
self.state=False
main=GUI()
Gtk.main()
I think that the only inconvenient of using this to solve your problem is that the theme of the user is not respected. If that is a problem, instead of using an image you could draw your button by using a DrawingArea and by getting the theme colors as I suggested here!
I hope it be useful :)

Resources