Initial Commit

This commit is contained in:
Jeremy Ruston 2023-10-26 16:56:15 +01:00
parent 902c7f55ba
commit 497c56d3fa
20 changed files with 615 additions and 129 deletions

View File

@ -0,0 +1,139 @@
/*\
title: $:/core/modules/widgets/data.js
type: application/javascript
module-type: widget
Widget to represent a single item of data
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var DataWidget = function(parseTreeNode,options) {
this.dataWidgetTag = parseTreeNode.type;
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
DataWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
DataWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
};
/*
Compute the internal state of the widget
*/
DataWidget.prototype.execute = function() {
// Construct the child widgets
this.makeChildWidgets();
};
/*
Read the tiddler value(s) from a data widget must be called after the .render() method
*/
DataWidget.prototype.readDataTiddlerValues = function() {
var self = this;
// Start with a blank object
var item = Object.create(null);
// Read any attributes not prefixed with $
$tw.utils.each(this.attributes,function(value,name) {
if(name.charAt(0) !== "$") {
item[name] = value;
}
});
item = new $tw.Tiddler(item);
// Deal with $tiddler, $filter or $compound-tiddler attributes
var tiddlers = [],title;
if(this.hasAttribute("$tiddler")) {
title = this.getAttribute("$tiddler");
if(title) {
tiddlers.push(this.wiki.getTiddler(title));
}
}
if(this.hasAttribute("$filter")) {
var filter = this.getAttribute("$filter");
if(filter) {
var titles = this.wiki.filterTiddlers(filter);
$tw.utils.each(titles,function(title) {
var tiddler = self.wiki.getTiddler(title);
tiddlers.push(tiddler);
});
}
}
if(this.hasAttribute("$compound-tiddler")) {
title = this.getAttribute("$compound-tiddler");
if(title) {
tiddlers.push.apply(tiddlers,this.extractCompoundTiddler(title));
}
}
// Convert the literal item to field strings
item = item.getFieldStrings();
if(tiddlers.length === 0) {
if(Object.keys(item).length > 0 && !!item.title) {
return [item];
} else {
return [];
}
} else {
var results = [];
$tw.utils.each(tiddlers,function(tiddler,index) {
var fields = tiddler.getFieldStrings();
results.push($tw.utils.extend({},fields,item));
});
return results;
}
};
/*
Helper to extract tiddlers from text/vnd.tiddlywiki-multiple tiddlers
*/
DataWidget.prototype.extractCompoundTiddler = function(title) {
var tiddler = this.wiki.getTiddler(title);
if(tiddler && tiddler.fields.type === "text/vnd.tiddlywiki-multiple") {
var text = tiddler.fields.text || "",
rawTiddlers = text.split(/\r?\n\+\r?\n/),
tiddlers = [];
$tw.utils.each(rawTiddlers,function(rawTiddler) {
var fields = Object.create(null),
split = rawTiddler.split(/\r?\n\r?\n/mg);
if(split.length >= 1) {
fields = $tw.utils.parseFields(split[0],fields);
}
if(split.length >= 2) {
fields.text = split.slice(1).join("\n\n");
}
tiddlers.push(new $tw.Tiddler(fields));
});
return tiddlers;
} else {
return [];
}
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DataWidget.prototype.refresh = function(changedTiddlers) {
// Refresh our attributes
var changedAttributes = this.computeAttributes();
// Refresh our children, and indicate that we refreshed if any of our attribute values have changed
return this.refreshChildren(changedTiddlers) || $tw.utils.count(changedAttributes) > 0;
};
exports.data = DataWidget;
})();

View File

@ -0,0 +1,113 @@
/*\
title: $:/core/modules/widgets/testcase.js
type: application/javascript
module-type: widget
Widget to display a test case
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var TestCaseWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
TestCaseWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
TestCaseWidget.prototype.render = function(parent,nextSibling) {
var self = this;
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
// Create container DOM node
var domNode = this.document.createElement("div");
this.domNodes.push(domNode);
parent.insertBefore(domNode,nextSibling);
// Render the children into a hidden DOM node
var parser = {
tree: [{
type: "widget",
attributes: {},
orderedAttributes: [],
children: this.parseTreeNode.children || []
}]
};
this.contentRoot = this.wiki.makeWidget(parser,{
document: $tw.fakeDocument,
parentWidget: this
});
this.contentContainer = $tw.fakeDocument.createElement("div");
this.contentRoot.render(this.contentContainer,null);
// Create a wiki
this.testcaseWiki = new $tw.Wiki();
// Always load the core plugin
var loadTiddler = function(title) {
var tiddler = self.wiki.getTiddler(title);
if(tiddler) {
self.testcaseWiki.addTiddler(tiddler);
}
}
loadTiddler("$:/core");
loadTiddler("$:/plugins/tiddlywiki/codemirror");
// Load the test case template
// loadTiddler(this.testcaseTemplate);
// Load tiddlers from child data widgets
var tiddlers = [];
this.findChildrenDataWidgets(this.contentRoot.children,"data",function(widget) {
Array.prototype.push.apply(tiddlers,widget.readDataTiddlerValues());
});
var jsonPayload = JSON.stringify(tiddlers);
this.testcaseWiki.addTiddlers(tiddlers);
// Unpack plugin tiddlers
this.testcaseWiki.readPluginInfo();
this.testcaseWiki.registerPluginTiddlers("plugin");
this.testcaseWiki.unpackPluginTiddlers();
this.testcaseWiki.addIndexersToWiki();
// Generate a `transclusion` variable that depends on the values of the payload tiddlers so that the template can easily make unique state tiddlers
this.setVariable("transclusion",$tw.utils.hashString(jsonPayload));
// Generate a `payloadTiddlers` variable that contains the payload in JSON format
this.setVariable("payloadTiddlers",jsonPayload);
// Render the page root template of the subwiki
var rootWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTemplate,{document: this.document, parseAsInline: false, parentWidget: this});
rootWidget.render(domNode);
// Trap changes in the wiki and refresh the rendering
this.testcaseWiki.addEventListener("change",function(changes) {
rootWidget.refresh(changes,domNode);
});
};
/*
Compute the internal state of the widget
*/
TestCaseWidget.prototype.execute = function() {
this.testcaseTemplate = this.getAttribute("template","$:/core/ui/testcases/DefaultTemplate");
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
TestCaseWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if($tw.utils.count(changedAttributes) > 0) {
this.refreshSelf();
return true;
} else {
return this.contentRoot.refresh(changedTiddlers);
}
};
exports["testcase"] = TestCaseWidget;
})();

View File

@ -797,6 +797,21 @@ Widget.prototype.allowActionPropagation = function() {
return true;
};
/*
Find child <$data> widgets recursively. The tag name allows aliased versions of the widget to be found too
*/
Widget.prototype.findChildrenDataWidgets = function(children,tag,callback) {
var self = this;
$tw.utils.each(children,function(child) {
if(child.dataWidgetTag === tag) {
callback(child);
}
if(child.children) {
self.findChildrenDataWidgets(child.children,tag,callback);
}
});
};
/*
Evaluate a variable with parameters. This is a static convenience method that attempts to evaluate a variable as a function, returning an array of strings
*/

View File

@ -0,0 +1,22 @@
title: $:/core/ui/testcases/DefaultTemplate
\whitespace trim
<$let
state={{{ [<qualify "$:/state/testcase">] }}}
>
<div class="tc-testcase-wrapper">
<div class="tc-testcase-header">
<h2><$transclude tiddler="Description" mode="inline"/></h2>
</div>
<div class="tc-testcase-panes">
<div class="tc-testcase-source">
<$macrocall $name="tabs" tabsList="[all[tiddlers]sort[]] -[prefix<state>] -Description -ExpectedResult -Output Output +[putfirst[]] -[has[plugin-type]]" state=<<state>> default="Output" template="$:/core/ui/testcases/DefaultTemplate/Source"/>
</div>
<div class="tc-testcase-divider">
</div>
<div class="tc-testcase-output">
<$transclude tiddler="Output"/>
</div>
</div>
</div>
</$let>

View File

@ -0,0 +1,19 @@
title: $:/core/ui/testcases/DefaultTemplate/Source
<$list filter="[<currentTab>fields[]] -text +[limit[1]]" variable="ignore">
<table class="tc-field-table">
<tbody>
<$list filter="[<currentTab>fields[]sort[]] -text -title title +[putfirst[]]" variable="fieldName">
<tr>
<td>
<$text text=<<fieldName>>/>
</td>
<td>
<$view tiddler=<<currentTab>> field=<<fieldName>>/>
</td>
</tr>
</$list>
</tbody>
</table>
</$list>
<$edit class="tc-edit-texteditor" tiddler=<<currentTab>>/>

View File

@ -0,0 +1,4 @@
title: $:/core/ui/testcases/RawJSONTemplate
\whitespace trim
<$text text=<<payloadTiddlers>>/>

View File

@ -14,7 +14,8 @@
"tiddlywiki/dynannotate",
"tiddlywiki/codemirror",
"tiddlywiki/menubar",
"tiddlywiki/jszip"
"tiddlywiki/jszip",
"tiddlywiki/innerwiki"
],
"themes": [
"tiddlywiki/vanilla",

View File

@ -0,0 +1,27 @@
title: Data/ImportCompound
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
description: Importing a compound payload tiddler and adding custom fields
title: Description
text: Importing a compound payload tiddler and adding custom fields
+
title: Output
\whitespace trim
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
<$data $compound-tiddler="Compound" custom="Alpha"/>
</$testcase>
+
title: Compound
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Payload Tiddler
tags: Alpha Beta Gamma
This is a payload tiddler from a compound tiddler
+
title: ExpectedResult
<p><div><div>[{"title":"Payload Tiddler","tags":"Alpha Beta Gamma","text":"This is a payload tiddler from a compound tiddler","custom":"Alpha"}]</div></div></p>

View File

@ -0,0 +1,28 @@
title: Data/ImportFilter
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
description: Importing a payload filter and adding custom fields
title: Description
text: Importing a payload filter and adding custom fields
+
title: Output
\whitespace trim
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
<$data $filter="[tag[Definitions]]" custom="Alpha"/>
</$testcase>
+
title: HelloThere
tags: Definitions
This is the tiddler HelloThere
+
title: AnotherDefinition
tags: Definitions
This is the tiddler AnotherDefinition
+
title: ExpectedResult
<p><div><div>[{"title":"AnotherDefinition","tags":"Definitions","text":"This is the tiddler AnotherDefinition","custom":"Alpha"},{"title":"HelloThere","tags":"Definitions","text":"This is the tiddler HelloThere","custom":"Alpha"}]</div></div></p>

View File

@ -0,0 +1,23 @@
title: Data/ImportTiddler
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
description: Importing a payload tiddler and adding custom fields
title: Description
text: Importing a payload tiddler and adding custom fields
+
title: Output
\whitespace trim
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
<$data $tiddler="HelloThere" custom="Alpha"/>
</$testcase>
+
title: HelloThere
tags: Definitions
This is the tiddler HelloThere
+
title: ExpectedResult
<p><div><div>[{"title":"HelloThere","tags":"Definitions","text":"This is the tiddler HelloThere","custom":"Alpha"}]</div></div></p>

View File

@ -0,0 +1,18 @@
title: Data/Simple
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
description: Standalone data widget to create individual tiddlers
title: Description
text: Standalone data widget to create individual tiddlers
+
title: Output
\whitespace trim
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
<$data title="Epsilon" text="Theta"/>
</$testcase>
+
title: ExpectedResult
<p><div><div>[{"title":"Epsilon","text":"Theta"}]</div></div></p>

View File

@ -1,7 +1,8 @@
{
"description": "TiddlyWiki core tests",
"plugins": [
"tiddlywiki/jasmine"
"tiddlywiki/jasmine",
"tiddlywiki/geospatial"
],
"themes": [
"tiddlywiki/vanilla",

View File

@ -0,0 +1,65 @@
caption: data
created: 20230406161341763
modified: 20230406161341763
tags: Widgets
title: DataWidget
type: text/vnd.tiddlywiki
! Introduction
The data widget is used with the <<.wlink TestCaseWidget>> widget and the [[Innerwiki Plugin]] to specify payload tiddlers that are to be included in the test case or innerwiki.
! Content and Attributes
The content of the data widget is rendered as if the data widget were not present. It supports the following attributes:
|!Attribute |!Description |
|<<.attr $tiddler>> |Optional title of a tiddler to be used as a payload tiddler (optional) |
|<<.attr $filter>> |Optional filter string identifying tiddlers to be used as payload tiddlers (optional) |
|<<.attr $compound-tiddler>> |Optional title of a tiddler containing payload tiddlers in `text/vnd.tiddlywiki-multiple` format (see below) |
|//any attribute<br>not starting<br>with $// |Field values to be assigned to the payload tiddler(s) |
The data widget is not rendered when used within the <<.wlink TestCaseWidget>> widget or the [[Innerwiki Plugin]] but for ease of testing, when used elsewhere it renders a JSON representation of the payload tiddlers.
Without any of the attributes <<.attr $tiddler>>, <<.attr $filter>> or <<.attr $compound-tiddler>>, any attributes whose name does not start with $ are used as the field values for creating a single new tiddler. For example, here a tiddler with the title "Epsilon" and the text "Theta" is created:
```
<$data title="Epsilon" text="Theta"/>
```
If any of the attributes <<.attr $tiddler>>, <<.attr $filter>> or <<.attr $compound-tiddler>> are specified then they are used to generate base tiddlers that are then modified with the addition of fields derived from any attributes whose name does not start with $.
This example, here we specify a copy of the "HelloThere" tiddler with the addition of the field "custom" set to "Alpha":
```
<$data $tiddler="HelloThere" custom="Alpha"/>
```
This example injects all image tiddlers with the addition of the field "custom" set to "Beta":
```
<$data $filter="[is[image]]" custom="Beta"/>
```
! Compound Tiddlers
Compound tiddlers provide a way to easily create multiple tiddlers from within a single tiddler. They are contained in tiddlers of type `text/vnd.tiddlywiki-multiple`. The text field consists of a series of tiddlers in the same format as `.tid` files, each separated by a line containing a single `+` character.
For example:
```
title: First
tags: one two
This is the first tiddler
+
title: Second
tags: three four
This is the second tiddler
+
title: third
tags: five six
This is the third tiddler
```

View File

@ -0,0 +1,46 @@
caption: testcase
created: 20230406161341763
modified: 20230406161341763
tags: Widgets
title: TestCaseWidget
type: text/vnd.tiddlywiki
! Introduction
The testcase widget creates an independent subwiki loaded with the specified payload tiddlers and then renders a specified template from within the subwiki.The default template displays a split view with the source tiddlers on the left and the rendered tiddler titled `Output` on the right. It also displays the tiddler titled `Description` as the heading. This makes it possible to run independent tests that also serve as documentation examples.
! Content and Attributes
The content of the `<$testcase>` widget is not displayed but instead is scanned for <<.wlink DataWidget>> widgets that define the payload tiddlers to be included in the test case. The `$:/core` plugin is automatically included in the payload.
|!Attribute |!Description |
|<<.attr template>> |Optional title of the template used to display the testcase (defaults to $:/core/ui/testcases/DefaultTemplate). Note that custom templates will need to be explicitly added to the payload |
! Payload Tiddlers
The payload tiddlers are the tiddler values that are loaded into the subwiki that is created to run the tests. They are created via <<.wlink DataWidget>> widgets within the body of the `<$testcase>` widget.
! State Handling
The `<$testcase>` widget sets the variable `transclusion` to a hash that reflects the names and values of all the payload tiddlers. This makes it easier for test case templates to create unique state tiddler titles using the [[qualify Macro]] or QualifyWidget.
! Test Case Conventions
The following conventions are used for test case tiddlers:
* `Description` contains a brief description of the test (rendered in inline mode)
* `Output` contains the tiddler text to be rendered. It can also reference other tiddlers
* `ExpectedResult` contains the HTML that should match the rendering of the tiddler `Output`
! Example
<$testcase>
<$data $tiddler="$:/core/ui/testcases/DefaultTemplate"/>
<$data $tiddler="$:/core/ui/testcases/DefaultTemplate/Source"/>
<$data title="Description" text="Simple example of a test case"/>
<$data title="Output" text="""<$testcase>
<$data title="Description" text="How to calculate 2 plus 2"/>
<$data title="Output" text="<$text text={{{ [[2]add[2]] }}}/>"/>
</$testcase>
"""/>
</$testcase>

View File

@ -7,7 +7,8 @@
"tiddlywiki/evernote",
"tiddlywiki/internals",
"tiddlywiki/menubar",
"tiddlywiki/qrcode"
"tiddlywiki/qrcode",
"tiddlywiki/innerwiki"
],
"themes": [
"tiddlywiki/vanilla",

View File

@ -0,0 +1,17 @@
/*\
title: $:/plugins/tiddlywiki/innerwiki/anchor.js
type: application/javascript
module-type: widget
Anchor widget to represent an innerwiki graphical anchor. Clone of the data widget
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.anchor = require("$:/core/modules/widgets/data.js").data;
})();

View File

@ -1,58 +0,0 @@
/*\
title: $:/plugins/tiddlywiki/innerwiki/data.js
type: application/javascript
module-type: widget
Widget to represent a single item of data
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var DataWidget = function(parseTreeNode,options) {
this.dataWidgetTag = parseTreeNode.type;
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
DataWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
DataWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
};
/*
Compute the internal state of the widget
*/
DataWidget.prototype.execute = function() {
// Construct the child widgets
this.makeChildWidgets();
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
DataWidget.prototype.refresh = function(changedTiddlers) {
// Refresh our attributes
var changedAttributes = this.computeAttributes();
// Refresh our children
return this.refreshChildren(changedTiddlers);
};
exports.data = DataWidget;
exports.anchor = DataWidget;
})();

View File

@ -15,7 +15,7 @@ Widget to display an innerwiki in an iframe
var DEFAULT_INNERWIKI_TEMPLATE = "$:/plugins/tiddlywiki/innerwiki/template";
var Widget = require("$:/core/modules/widgets/widget.js").widget,
DataWidget = require("$:/plugins/tiddlywiki/innerwiki/data.js").data,
DataWidget = require("$:/core/modules/widgets/data.js").data,
dm = $tw.utils.domMaker;
var InnerWikiWidget = function(parseTreeNode,options) {
@ -143,7 +143,7 @@ Create the anchors
*/
InnerWikiWidget.prototype.createAnchors = function() {
var self = this;
this.findDataWidgets(this.children,"anchor",function(widget) {
this.findChildrenDataWidgets(this.children,"anchor",function(widget) {
var anchorWidth = 40,
anchorHeight = 40,
getAnchorCoordinate = function(name) {
@ -233,76 +233,16 @@ InnerWikiWidget.prototype.createInnerHTML = function() {
IMPLANT_PREFIX = "<" + "script>\n$tw.preloadTiddlerArray(",
IMPLANT_SUFFIX = ");\n</" + "script>\n",
parts = html.split(SPLIT_MARKER),
tiddlers = this.readTiddlerDataWidgets(this.children);
tiddlers = [];
this.findChildrenDataWidgets(this.children,"data",function(widget) {
Array.prototype.push.apply(tiddlers,widget.readDataTiddlerValues());
});
if(parts.length === 2) {
html = parts[0] + IMPLANT_PREFIX + JSON.stringify(tiddlers) + IMPLANT_SUFFIX + SPLIT_MARKER + parts[1];
}
return html;
};
/*
Find child data widgets
*/
InnerWikiWidget.prototype.findDataWidgets = function(children,tag,callback) {
var self = this;
$tw.utils.each(children,function(child) {
if(child.dataWidgetTag === tag) {
callback(child);
}
if(child.children) {
self.findDataWidgets(child.children,tag,callback);
}
});
};
/*
Find the child data widgets
*/
InnerWikiWidget.prototype.readTiddlerDataWidgets = function(children) {
var self = this,
results = [];
this.findDataWidgets(children,"data",function(widget) {
Array.prototype.push.apply(results,self.readTiddlerDataWidget(widget));
});
return results;
};
/*
Read the value(s) from a data widget
*/
InnerWikiWidget.prototype.readTiddlerDataWidget = function(dataWidget) {
// Start with a blank object
var item = Object.create(null);
// Read any attributes not prefixed with $
$tw.utils.each(dataWidget.attributes,function(value,name) {
if(name.charAt(0) !== "$") {
item[name] = value;
}
});
// Deal with $tiddler or $filter attributes
var titles;
if(dataWidget.hasAttribute("$tiddler")) {
titles = [dataWidget.getAttribute("$tiddler")];
} else if(dataWidget.hasAttribute("$filter")) {
titles = this.wiki.filterTiddlers(dataWidget.getAttribute("$filter"));
}
if(titles) {
var self = this;
var results = [];
$tw.utils.each(titles,function(title,index) {
var tiddler = self.wiki.getTiddler(title),
fields;
if(tiddler) {
fields = tiddler.getFieldStrings();
}
results.push($tw.utils.extend({},fields,item));
})
return results;
} else {
return [item];
}
};
/*
Compute the internal state of the widget
*/

View File

@ -12,7 +12,7 @@ Tests the wiki based tests
/*global $tw: false */
"use strict";
var TEST_WIKI_TIDDLER_FILTER = "[type[text/vnd.tiddlywiki-multiple]tag[$:/tags/wiki-test-spec]]";
var TEST_WIKI_TIDDLER_FILTER = "[all[tiddlers+shadows]type[text/vnd.tiddlywiki-multiple]tag[$:/tags/wiki-test-spec]]";
var widget = require("$:/core/modules/widgets/widget.js");
@ -24,7 +24,11 @@ describe("Wiki-based tests", function() {
var tiddler = $tw.wiki.getTiddler(title);
it(tiddler.fields.title + ": " + tiddler.fields.description, function() {
// Add our tiddlers
var wiki = new $tw.Wiki();
var wiki = new $tw.Wiki(),
coreTiddler = $tw.wiki.getTiddler("$:/core");
if(coreTiddler) {
wiki.addTiddler(coreTiddler);
}
wiki.addTiddlers(readMultipleTiddlersTiddler(title));
// Complain if we don't have the ouput and expected results
if(!wiki.tiddlerExists("Output")) {

View File

@ -3219,6 +3219,67 @@ span.tc-translink > a:first-child {
fill: <<colour network-activity-foreground>>;
}
/*
** Test Cases
*/
.tc-testcase-wrapper {
border: 1px solid <<colour foreground>>;
background-color: <<colour muted-foreground>>;
border-radius: 6px;
}
.tc-testcase-header {
font-weight: normal;
margin: 0.5em 0;
padding: 0 0.5em;
}
.tc-testcase-header > h2,
.tc-testcase-source > pre {
margin: 0;
}
.tc-testcase-source > pre {
height: 100%;
}
.tc-testcase-panes {
background: <<colour background>>;
display: flex;
align-items: stretch;
flex-wrap: wrap;
padding: 0.5em;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
.tc-testcase-source {
flex: 1 0 49%;
min-width: 250px;
}
.tc-testcase-source .tc-field-table {
width: 100%;
}
.tc-testcase-divider {
flex: 0 0 2%;
}
.tc-testcase-source .tc-tab-buttons {
padding-top: 0;
}
.tc-testcase-output {
border-radius: 3px;
border: 1px solid <<colour muted-foreground>>;
flex: 1 0 49%;
min-width: 250px;
padding: 0.25em;
}
/*
** Flexbox utility classes
*/