Skip to content

Commit

Permalink
overhaul display of Tutorial pane tutorials
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinushey committed Feb 19, 2020
1 parent 45d96c7 commit 8bcf988
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 42 deletions.
54 changes: 26 additions & 28 deletions src/cpp/session/modules/SessionTutorial.cpp
Expand Up @@ -166,28 +166,6 @@ FilePath resourcesPath()
return options().rResourcesPath().completePath("tutorial_resources");
}

std::string htmlFormatTutorialName(const std::string& packageName,
const TutorialInfo& tutorial)
{
using namespace string_utils;

// NOTE: because these URLs will be displayed in a page served from
// a '/tutorial' endpoint (e.g. '/tutorial/home'), it's sufficient to
// use a relative link to the URL. (this is also required on RSP,
// where absolute URIs will not work due to how URLs are proxied)
std::stringstream href;
href << "./run"
<< "?package=" + htmlEscape(packageName)
<< "&name=" + htmlEscape(tutorial.name);

std::stringstream ss;
ss << "<a class=\"rstudio-tutorials-link\" href=\"" << href.str() << "\">"
<< "<code>" << htmlEscape(tutorial.name) << "</code>"
<< "</a>";

return ss.str();
}

void handleTutorialRunRequest(const http::Request& request,
http::Response* pResponse)
{
Expand Down Expand Up @@ -236,9 +214,6 @@ void handleTutorialHomeRequest(const http::Request& request,
if (tutorials.empty())
continue;

ss << "<h2 class=\"rstudio-tutorials-package\">" << htmlEscape(pkgName) << "</h2>";
ss << "<hr class=\"rstudio-tutorials-separator\">";

for (auto tutorial : tutorials)
{
ss << "<div>";
Expand All @@ -249,8 +224,11 @@ void handleTutorialHomeRequest(const http::Request& request,
<< htmlEscape(tutorial.title)
<< "</span>";

ss << "<span class=\"rstudio-tutorials-name\">"
<< htmlFormatTutorialName(pkgName, tutorial)
ss << "<span class=\"rstudio-tutorials-run-container\">"
<< "<button class=\"rstudio-tutorials-run-button\" onclick=\"window.parent.tutorialRun('" << htmlEscape(tutorial.name) << "', '" << htmlEscape(pkgName) << "')\">"
<< "<span class=\"rstudio-tutorials-run-button-label\">Start Tutorial</span>"
<< "<span class=\"rstudio-tutorials-run-button-icon\">\u25b6</span>"
<< "</button>"
<< "</span>";

ss << "</div>";
Expand All @@ -267,10 +245,12 @@ void handleTutorialHomeRequest(const http::Request& request,
<< tutorial.description
<< "</div>";
}

ss << "</div>";
ss << "<hr class=\"rstudio-tutorials-separator\">";

}

}

std::map<std::string, std::string> vars;
Expand All @@ -282,6 +262,22 @@ void handleTutorialHomeRequest(const http::Request& request,
pResponse->setFile(homePath, request, text::TemplateFilter(vars));
}

void handleTutorialFileRequest(const http::Request& request,
http::Response* pResponse)
{
FilePath resourcesPath =
options().rResourcesPath().completePath("tutorial_resources");

std::string path = http::util::pathAfterPrefix(request, "/tutorial/");
if (path.empty())
{
pResponse->setStatusCode(http::status::NotFound);
return;
}

pResponse->setCacheableFile(resourcesPath.completePath(path), request);
}

void handleTutorialRequest(const http::Request& request,
http::Response* pResponse)
{
Expand All @@ -290,6 +286,8 @@ void handleTutorialRequest(const http::Request& request,
handleTutorialRunRequest(request, pResponse);
else if (path == "/home")
handleTutorialHomeRequest(request, pResponse);
else if (boost::algorithm::ends_with(path, ".png"))
handleTutorialFileRequest(request, pResponse);
else
{
LOG_ERROR_MESSAGE("Unhandled tutorial URI '" + path + "'");
Expand Down
14 changes: 14 additions & 0 deletions src/cpp/session/resources/tutorial_resources/index.html
Expand Up @@ -7,9 +7,23 @@
</head>

<body class="rstudio-tutorials" style="visibility: hidden;">

<div class="rstudio-tutorials-container">
#!tutorials#
</div>

<div class="rstudio-tutorials-footer">

<img class="rstudio-tutorials-logo" alt="RStudio Icon" src="./rstudio-logo.png">
<span class="rstudio-tutorials-footer-text">
<a href="https://rstudio.org/links/rstudio-tutorials">RStudio Tutorials</a>
powered by the
<code><a href="https://rstudio.org/links/learnr">learnr</a></code>
package.
</span>

</div>

</body>

</html>
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -18,9 +18,16 @@
@external rstudio-tutorials-package;
@external rstudio-tutorials-label-container;
@external rstudio-tutorials-label;
@external rstudio-tutorials-name;
@external rstudio-tutorials-logo;
@external rstudio-tutorials-run-container;
@external rstudio-tutorials-run-button;
@external rstudio-tutorials-run-button-label;
@external rstudio-tutorials-run-button-icon;
@external rstudio-tutorials-description;
@external rstudio-tutorials-description-empty;
@external rstudio-tutorials-sublabel;
@external rstudio-tutorials-footer;
@external rstudio-tutorials-footer-text;
@external rstudio-tutorials-separator;

/* Scrollbars */
Expand Down Expand Up @@ -64,11 +71,12 @@
/* Common styles */

.rstudio-tutorials {
margin: 8px;
padding: 4px;
font-family: "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

.rstudio-tutorials-container {
margin: 10px;
}

.rstudio-tutorials-package {
Expand All @@ -79,23 +87,15 @@
display: inline-block;
}

.rstudio-tutorials-name {
.rstudio-tutorials-run-container {
float: right;
font-size: large;
}

.rstudio-tutorials-name::before {
content: "[ ";
}

.rstudio-tutorials-name::after {
content: " ]";
}

.rstudio-tutorials-label-container {
overflow: auto;
width: 100%;
margin-bottom: 16px;
padding: 4px;
margin-bottom: 8px;
}

.rstudio-tutorials-label {
Expand All @@ -104,6 +104,10 @@
font-weight: bold;
}

.rstudio-tutorials-description {
padding: 4px;
}

.rstudio-tutorials-description-empty {
font-style: italic;
}
Expand All @@ -114,6 +118,36 @@
margin-bottom: 24px;
}

.rstudio-tutorials-run-button {

border-radius: 4px;
padding: 2px 6px;
font-size: 0.8em;
margin-right: 2px;
}

.rstudio-tutorials-logo {
width: 24px;
height: 24px;
vertical-align: middle;
}

.rstudio-tutorials-footer-text {
font-size: 12px;
}

a.rstudio-tutorials-run-button:active {
margin-top: 2px;
}

.rstudio-tutorials-run-button-icon {
color: rgb(2, 164, 79);
padding-left: 4px;
font-size: 0.9em;
}

.rstudio-tutorials-sublabel {
}

/* Light styles */

Expand All @@ -122,6 +156,15 @@
color: black;
}

.rstudio-themes-light-menus .rstudio-tutorials-run-button {
background-color: white;
color: black;
border-top: 1px solid rgb(216, 216, 216);
border-left: 1px solid rgb(210, 210, 210);
border-right: 1px solid rgb(210, 210, 210);
border-bottom: 1px solid rgb(186, 186, 186);
}

/* Dark styles */

.rstudio-themes-dark-menus.rstudio-tutorials {
Expand All @@ -142,5 +185,12 @@
}

.rstudio-themes-dark-menus .rstudio-tutorials-separator {
border: 1px solid rgb(81, 92, 103);
border: none;
border-top: 1px solid rgb(81, 92, 103);
}

.rstudio-themes-dark-menus .rstudio-tutorials-run-button {
color: rgb(232, 232, 232);
background-color: rgb(78, 92, 104);
border: 1px solid rgb(108, 121, 131);
}
Expand Up @@ -68,6 +68,7 @@ protected TutorialPane(GlobalDisplay globalDisplay,

events.addHandler(ThemeChangedEvent.TYPE, this);

initTutorialJsCallbacks();
ensureWidget();
}

Expand Down Expand Up @@ -214,6 +215,13 @@ public String getName()
return frame_.getWindowName();
}

private void runTutorial(String tutorialName,
String packageName)
{
Tutorial tutorial = new Tutorial(tutorialName, packageName);
launchTutorial(tutorial);
}

private void navigate(String url, boolean replaceUrl)
{
if (URIUtils.isLocalUrl(url))
Expand Down Expand Up @@ -316,6 +324,16 @@ public HandlerRegistration addTutorialNavigateHandler(Handler handler)
return frame_.addHandler(handler, TutorialNavigateEvent.TYPE);
}

private final native void initTutorialJsCallbacks()
/*-{
var self = this;
$wnd.tutorialRun = $entry(function(tutorialName, tutorialPackage) {
self.@org.rstudio.studio.client.workbench.views.tutorial.TutorialPane::runTutorial(*)(tutorialName, tutorialPackage);
});
}-*/;

// Resources ----
public interface Resources extends ClientBundle
{
Expand Down

0 comments on commit 8bcf988

Please sign in to comment.