mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Add connection notes
This commit is contained in:
parent
ef22578d71
commit
7de6a51d73
24 changed files with 542 additions and 28 deletions
|
@ -0,0 +1,80 @@
|
|||
package io.xpipe.app.comp.base;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
public class MarkdownEditorComp extends Comp<MarkdownEditorComp.Structure> {
|
||||
|
||||
private final Property<String> value;
|
||||
private final String identifier;
|
||||
|
||||
public MarkdownEditorComp(
|
||||
Property<String> value, String identifier) {
|
||||
this.value = value;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
private Button createOpenButton() {
|
||||
return new IconButtonComp(
|
||||
"mdal-edit",
|
||||
() -> FileOpener.openString(
|
||||
identifier + ".md",
|
||||
this,
|
||||
value.getValue(),
|
||||
(s) -> {
|
||||
Platform.runLater(() -> value.setValue(s));
|
||||
}))
|
||||
.styleClass("edit-button")
|
||||
.apply(struc -> struc.get().getStyleClass().remove(Styles.FLAT))
|
||||
.createStructure()
|
||||
.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Structure createBase() {
|
||||
var markdown = new MarkdownComp(value, s -> s).createRegion();
|
||||
var editButton = createOpenButton();
|
||||
var pane = new AnchorPane(markdown, editButton);
|
||||
pane.setPickOnBounds(false);
|
||||
AnchorPane.setTopAnchor(editButton, 10.0);
|
||||
AnchorPane.setRightAnchor(editButton, 10.0);
|
||||
return new Structure(pane, markdown, editButton);
|
||||
}
|
||||
|
||||
@Value
|
||||
@Builder
|
||||
public static class TextAreaStructure implements CompStructure<StackPane> {
|
||||
StackPane pane;
|
||||
TextArea textArea;
|
||||
|
||||
@Override
|
||||
public StackPane get() {
|
||||
return pane;
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
@Builder
|
||||
public static class Structure implements CompStructure<AnchorPane> {
|
||||
AnchorPane pane;
|
||||
Region markdown;
|
||||
Button editButton;
|
||||
|
||||
@Override
|
||||
public AnchorPane get() {
|
||||
return pane;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -72,6 +72,7 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
|||
return grid.getWidth() / 2.5;
|
||||
},
|
||||
grid.widthProperty()));
|
||||
var notes = new StoreNotesComp(wrapper).createRegion();
|
||||
|
||||
if (showIcon) {
|
||||
var storeIcon = createIcon(30, 24);
|
||||
|
@ -92,7 +93,8 @@ public class DenseStoreEntryComp extends StoreEntryComp {
|
|||
nameCC.setMinWidth(100);
|
||||
nameCC.setHgrow(Priority.ALWAYS);
|
||||
grid.getColumnConstraints().addAll(nameCC);
|
||||
var nameBox = new HBox(name);
|
||||
var nameBox = new HBox(name, notes);
|
||||
nameBox.setSpacing(8);
|
||||
nameBox.setAlignment(Pos.CENTER_LEFT);
|
||||
grid.addRow(0, nameBox);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ public class StandardStoreEntryComp extends StoreEntryComp {
|
|||
|
||||
protected Region createContent() {
|
||||
var name = createName().createRegion();
|
||||
var notes = new StoreNotesComp(wrapper).createRegion();
|
||||
|
||||
var grid = new GridPane();
|
||||
grid.setHgap(7);
|
||||
|
@ -29,7 +30,10 @@ public class StandardStoreEntryComp extends StoreEntryComp {
|
|||
grid.add(storeIcon, 0, 0, 1, 2);
|
||||
grid.getColumnConstraints().add(new ColumnConstraints(66));
|
||||
|
||||
grid.add(name, 1, 0);
|
||||
var nameAndNotes = new HBox(name, notes);
|
||||
nameAndNotes.setSpacing(8);
|
||||
nameAndNotes.setAlignment(Pos.CENTER_LEFT);
|
||||
grid.add(nameAndNotes, 1, 0);
|
||||
grid.add(createSummary(), 1, 1);
|
||||
var nameCC = new ColumnConstraints();
|
||||
nameCC.setMinWidth(100);
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package io.xpipe.app.comp.store;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
||||
import io.xpipe.app.core.App;
|
||||
import io.xpipe.app.core.AppActionLinkDetector;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.*;
|
||||
import io.xpipe.app.ext.ActionProvider;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
|
@ -12,13 +10,13 @@ import io.xpipe.app.fxcomps.SimpleCompStructure;
|
|||
import io.xpipe.app.fxcomps.augment.ContextMenuAugment;
|
||||
import io.xpipe.app.fxcomps.augment.GrowAugment;
|
||||
import io.xpipe.app.fxcomps.impl.*;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreColor;
|
||||
import io.xpipe.app.update.XPipeDistributionType;
|
||||
import io.xpipe.app.util.*;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableDoubleValue;
|
||||
|
@ -29,13 +27,11 @@ import javafx.scene.Node;
|
|||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
import atlantafx.base.theme.Styles;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -422,6 +418,14 @@ public abstract class StoreEntryComp extends SimpleComp {
|
|||
contextMenu.getItems().add(color);
|
||||
}
|
||||
|
||||
var notes = new MenuItem(AppI18n.get("addNotes"), new FontIcon("mdi2n-note-text"));
|
||||
notes.setOnAction(event -> {
|
||||
wrapper.getNotes().setValue(new StoreNotes(null, getDefaultNotes()));
|
||||
event.consume();
|
||||
});
|
||||
notes.visibleProperty().bind(BindingsHelper.map(wrapper.getNotes(), s -> s.getCommited() == null));
|
||||
contextMenu.getItems().add(notes);
|
||||
|
||||
var del = new MenuItem(AppI18n.get("remove"), new FontIcon("mdal-delete_outline"));
|
||||
del.disableProperty()
|
||||
.bind(Bindings.createBooleanBinding(
|
||||
|
@ -439,9 +443,15 @@ public abstract class StoreEntryComp extends SimpleComp {
|
|||
return contextMenu;
|
||||
}
|
||||
|
||||
protected ColumnConstraints createShareConstraint(Region r, double share) {
|
||||
var cc = new ColumnConstraints();
|
||||
cc.prefWidthProperty().bind(Bindings.createDoubleBinding(() -> r.getWidth() * share, r.widthProperty()));
|
||||
return cc;
|
||||
|
||||
private static String DEFAULT_NOTES = null;
|
||||
|
||||
private static String getDefaultNotes() {
|
||||
if (DEFAULT_NOTES == null) {
|
||||
AppResources.with(AppResources.XPIPE_MODULE, "misc/notes_default.md", f -> {
|
||||
DEFAULT_NOTES = Files.readString(f);
|
||||
});
|
||||
}
|
||||
return DEFAULT_NOTES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public class StoreEntryWrapper {
|
|||
private final Property<DataStoreColor> color = new SimpleObjectProperty<>();
|
||||
private final Property<StoreCategoryWrapper> category = new SimpleObjectProperty<>();
|
||||
private final Property<String> summary = new SimpleObjectProperty<>();
|
||||
private final Property<StoreNotes> notes;
|
||||
|
||||
public StoreEntryWrapper(DataStoreEntry entry) {
|
||||
this.entry = entry;
|
||||
|
@ -60,6 +61,7 @@ public class StoreEntryWrapper {
|
|||
actionProviders.put(dataStoreActionProvider, new SimpleBooleanProperty(true));
|
||||
});
|
||||
this.defaultActionProvider = new SimpleObjectProperty<>();
|
||||
this.notes = new SimpleObjectProperty<>(new StoreNotes(entry.getNotes(), entry.getNotes()));
|
||||
setupListeners();
|
||||
}
|
||||
|
||||
|
@ -96,6 +98,12 @@ public class StoreEntryWrapper {
|
|||
entry.addListener(() -> PlatformThread.runLaterIfNeeded(() -> {
|
||||
update();
|
||||
}));
|
||||
|
||||
notes.addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue.isCommited()) {
|
||||
entry.setNotes(newValue.getCurrent());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
@ -120,6 +128,7 @@ public class StoreEntryWrapper {
|
|||
cache.setValue(new HashMap<>(entry.getStoreCache()));
|
||||
}
|
||||
color.setValue(entry.getColor());
|
||||
notes.setValue(new StoreNotes(entry.getNotes(), entry.getNotes()));
|
||||
|
||||
busy.setValue(entry.isInRefresh());
|
||||
deletable.setValue(entry.getConfiguration().isDeletable()
|
||||
|
|
16
app/src/main/java/io/xpipe/app/comp/store/StoreNotes.java
Normal file
16
app/src/main/java/io/xpipe/app/comp/store/StoreNotes.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package io.xpipe.app.comp.store;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Value
|
||||
public class StoreNotes {
|
||||
|
||||
String commited;
|
||||
String current;
|
||||
|
||||
public boolean isCommited() {
|
||||
return Objects.equals(commited, current);
|
||||
}
|
||||
}
|
146
app/src/main/java/io/xpipe/app/comp/store/StoreNotesComp.java
Normal file
146
app/src/main/java/io/xpipe/app/comp/store/StoreNotesComp.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
package io.xpipe.app.comp.store;
|
||||
|
||||
import atlantafx.base.controls.Popover;
|
||||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.comp.base.DialogComp;
|
||||
import io.xpipe.app.comp.base.MarkdownEditorComp;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class StoreNotesComp extends Comp<StoreNotesComp.Structure> {
|
||||
|
||||
private final StoreEntryWrapper wrapper;
|
||||
|
||||
public StoreNotesComp(StoreEntryWrapper wrapper) {this.wrapper = wrapper;}
|
||||
|
||||
@Override
|
||||
public Structure createBase() {
|
||||
var n = wrapper.getNotes();
|
||||
var button = new IconButtonComp("mdi2n-note-text")
|
||||
.apply(struc -> AppFont.small(struc.get()))
|
||||
.focusTraversableForAccessibility()
|
||||
.tooltipKey("notes")
|
||||
.styleClass("notes-button")
|
||||
.grow(false, true)
|
||||
.hide(BindingsHelper.map(n, s -> s.getCommited() == null && s.getCurrent() == null))
|
||||
.padding(new Insets(5))
|
||||
.createStructure().get();
|
||||
button.prefWidthProperty().bind(button.heightProperty());
|
||||
|
||||
var prop = new SimpleStringProperty(n.getValue().getCurrent());
|
||||
var md = new MarkdownEditorComp(prop,"notes-" + wrapper.getName().getValue()).createStructure();
|
||||
|
||||
var popover = new AtomicReference<Popover>();
|
||||
var dialog = new DialogComp() {
|
||||
|
||||
@Override
|
||||
protected void finish() {
|
||||
n.setValue(new StoreNotes(n.getValue().getCurrent(), n.getValue().getCurrent()));
|
||||
popover.get().hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String finishKey() {
|
||||
return "apply";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> bottom() {
|
||||
return new ButtonComp(AppI18n.observable("delete"), () -> {
|
||||
n.setValue(new StoreNotes(null, null));
|
||||
}).hide(BindingsHelper.map(n, v -> v.getCommited() == null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Comp<?>> customButtons() {
|
||||
return List.of(new ButtonComp(AppI18n.observable("cancel"), () -> {
|
||||
popover.get().hide();
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comp<?> content() {
|
||||
return Comp.of(() -> md.get());
|
||||
}
|
||||
}.createRegion();
|
||||
|
||||
popover.set(createPopover(dialog));
|
||||
button.setOnAction(e -> {
|
||||
if (n.getValue().getCurrent() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (popover.get().isShowing()) {
|
||||
e.consume();
|
||||
return;
|
||||
}
|
||||
|
||||
popover.get().show(button);
|
||||
e.consume();
|
||||
});
|
||||
md.getEditButton().addEventFilter(ActionEvent.ANY, event -> {
|
||||
if (!popover.get().isDetached()) {
|
||||
popover.get().setDetached(true);
|
||||
event.consume();
|
||||
Platform.runLater(() -> {
|
||||
Platform.runLater(() -> {
|
||||
md.getEditButton().fire();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
popover.get().showingProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
n.setValue(new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited()));
|
||||
DataStorage.get().saveAsync();
|
||||
}
|
||||
});
|
||||
prop.addListener((observable, oldValue, newValue) -> {
|
||||
n.setValue(new StoreNotes(n.getValue().getCommited(), newValue));
|
||||
});
|
||||
n.addListener((observable, oldValue, s) -> {
|
||||
prop.set(s.getCurrent());
|
||||
if (s.getCurrent() != null && oldValue.getCommited() == null && oldValue.isCommited()) {
|
||||
Platform.runLater(() -> {
|
||||
popover.get().show(button);
|
||||
});
|
||||
}
|
||||
});
|
||||
return new Structure(popover.get(), button);
|
||||
}
|
||||
|
||||
private Popover createPopover(Region content) {
|
||||
var popover = new Popover(content);
|
||||
popover.setCloseButtonEnabled(true);
|
||||
popover.setHeaderAlwaysVisible(true);
|
||||
popover.setDetachable(true);
|
||||
popover.setTitle(wrapper.getName().getValue());
|
||||
popover.setMaxWidth(400);
|
||||
popover.setHeight(600);
|
||||
AppFont.small(popover.getContentNode());
|
||||
return popover;
|
||||
}
|
||||
|
||||
|
||||
public record Structure(Popover popover, Button button) implements CompStructure<Button> {
|
||||
|
||||
@Override
|
||||
public Button get() {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ public class ContextualFileReferenceChoiceComp extends Comp<CompStructure<HBox>>
|
|||
this.fileSystem.setValue(val);
|
||||
});
|
||||
this.fileSystem.addListener((observable, oldValue, newValue) -> {
|
||||
fileSystem.setValue(newValue.get() != null ? newValue.get().ref() : null);
|
||||
fileSystem.setValue(newValue != null ? newValue.get().ref() : null);
|
||||
});
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,9 @@ public class DataStoreEntry extends StorageElement {
|
|||
@Setter
|
||||
Set<DataStoreEntry> childrenCache = null;
|
||||
|
||||
@NonFinal
|
||||
String notes;
|
||||
|
||||
private DataStoreEntry(
|
||||
Path directory,
|
||||
UUID uuid,
|
||||
|
@ -81,7 +84,8 @@ public class DataStoreEntry extends StorageElement {
|
|||
Configuration configuration,
|
||||
JsonNode storePersistentState,
|
||||
boolean expanded,
|
||||
DataStoreColor color) {
|
||||
DataStoreColor color,
|
||||
String notes) {
|
||||
super(directory, uuid, name, lastUsed, lastModified, dirty);
|
||||
this.categoryUuid = categoryUuid;
|
||||
this.store = DataStorageParser.storeFromNode(storeNode);
|
||||
|
@ -94,6 +98,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
? DataStoreProviders.byStoreClass(store.getClass()).orElse(null)
|
||||
: null;
|
||||
this.storePersistentStateNode = storePersistentState;
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
private DataStoreEntry(
|
||||
|
@ -152,6 +157,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
Configuration.defaultConfiguration(),
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null);
|
||||
return entry;
|
||||
}
|
||||
|
@ -168,7 +174,8 @@ public class DataStoreEntry extends StorageElement {
|
|||
Configuration configuration,
|
||||
JsonNode storePersistentState,
|
||||
boolean expanded,
|
||||
DataStoreColor color) {
|
||||
DataStoreColor color,
|
||||
String notes) {
|
||||
return new DataStoreEntry(
|
||||
directory,
|
||||
uuid,
|
||||
|
@ -182,7 +189,8 @@ public class DataStoreEntry extends StorageElement {
|
|||
configuration,
|
||||
storePersistentState,
|
||||
expanded,
|
||||
color);
|
||||
color,
|
||||
notes);
|
||||
}
|
||||
|
||||
public static Optional<DataStoreEntry> fromDirectory(Path dir) throws Exception {
|
||||
|
@ -191,6 +199,7 @@ public class DataStoreEntry extends StorageElement {
|
|||
var entryFile = dir.resolve("entry.json");
|
||||
var storeFile = dir.resolve("store.json");
|
||||
var stateFile = dir.resolve("state.json");
|
||||
var notesFile = dir.resolve("notes.md");
|
||||
if (!Files.exists(entryFile) || !Files.exists(storeFile)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -238,6 +247,14 @@ public class DataStoreEntry extends StorageElement {
|
|||
})
|
||||
.orElse(null);
|
||||
|
||||
String notes = null;
|
||||
if (Files.exists(notesFile)) {
|
||||
notes = Files.readString(notesFile);
|
||||
}
|
||||
if (notes != null && notes.isBlank()) {
|
||||
notes = null;
|
||||
}
|
||||
|
||||
// Store loading is prone to errors.
|
||||
JsonNode storeNode = null;
|
||||
try {
|
||||
|
@ -256,7 +273,9 @@ public class DataStoreEntry extends StorageElement {
|
|||
configuration,
|
||||
persistentState,
|
||||
expanded,
|
||||
color));
|
||||
color,
|
||||
notes
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -363,6 +382,12 @@ public class DataStoreEntry extends StorageElement {
|
|||
Files.writeString(directory.resolve("state.json"), stateString);
|
||||
Files.writeString(directory.resolve("entry.json"), entryString);
|
||||
Files.writeString(directory.resolve("store.json"), storeString);
|
||||
var notesFile = directory.resolve("notes.md");
|
||||
if (Files.exists(notesFile) && notes == null) {
|
||||
Files.delete(notesFile);
|
||||
} else {
|
||||
Files.writeString(notesFile, notes);
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
|
@ -374,6 +399,14 @@ public class DataStoreEntry extends StorageElement {
|
|||
}
|
||||
}
|
||||
|
||||
public void setNotes(String newNotes) {
|
||||
var changed = !Objects.equals(notes, newNotes);
|
||||
this.notes = newNotes;
|
||||
if (changed) {
|
||||
notifyUpdate(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor(DataStoreColor newColor) {
|
||||
var changed = !Objects.equals(color, newColor);
|
||||
this.color = newColor;
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
An h1 header
|
||||
============
|
||||
|
||||
Paragraphs are separated by a blank line.
|
||||
|
||||
2nd paragraph. *Italic*, **bold**, and `monospace`. Itemized lists
|
||||
look like:
|
||||
|
||||
* this one
|
||||
* that one
|
||||
* the other one
|
||||
|
||||
Note that --- not considering the asterisk --- the actual text
|
||||
content starts at 4-columns in.
|
||||
|
||||
> Block quotes are
|
||||
> written like so.
|
||||
>
|
||||
> They can span multiple paragraphs,
|
||||
> if you like.
|
||||
|
||||
Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., "it's all
|
||||
in chapters 12--14"). Three dots ... will be converted to an ellipsis.
|
||||
Unicode is supported. ☺
|
||||
|
||||
|
||||
|
||||
An h2 header
|
||||
------------
|
||||
|
||||
Here's a numbered list:
|
||||
|
||||
1. first item
|
||||
2. second item
|
||||
3. third item
|
||||
|
||||
Note again how the actual text starts at 4 columns in (4 characters
|
||||
from the left side). Here's a code sample:
|
||||
|
||||
# Let me re-iterate ...
|
||||
for i in 1 .. 10 { do-something(i) }
|
||||
|
||||
As you probably guessed, indented 4 spaces. By the way, instead of
|
||||
indenting the block, you can use delimited blocks, if you like:
|
||||
|
||||
~~~
|
||||
define foobar() {
|
||||
print "Welcome to flavor country!";
|
||||
}
|
||||
~~~
|
||||
|
||||
(which makes copying & pasting easier). You can optionally mark the
|
||||
delimited block for Pandoc to syntax highlight it:
|
||||
|
||||
~~~python
|
||||
import time
|
||||
# Quick, count to ten!
|
||||
for i in range(10):
|
||||
# (but not *too* quick)
|
||||
time.sleep(0.5)
|
||||
print i
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
### An h3 header ###
|
||||
|
||||
Now a nested list:
|
||||
|
||||
1. First, get these ingredients:
|
||||
|
||||
* carrots
|
||||
* celery
|
||||
* lentils
|
||||
|
||||
2. Boil some water.
|
||||
|
||||
3. Dump everything in the pot and follow
|
||||
this algorithm:
|
||||
|
||||
find wooden spoon
|
||||
uncover pot
|
||||
stir
|
||||
cover pot
|
||||
balance wooden spoon precariously on pot handle
|
||||
wait 10 minutes
|
||||
goto first step (or shut off burner when done)
|
||||
|
||||
Do not bump wooden spoon or it will fall.
|
||||
|
||||
Notice again how text always lines up on 4-space indents (including
|
||||
that last line which continues item 3 above).
|
||||
|
||||
Here's a link to [a website](http://foo.bar), to a [local
|
||||
doc](local-doc.html), and to a [section heading in the current
|
||||
doc](#an-h2-header). Here's a footnote [^1].
|
||||
|
||||
[^1]: Footnote text goes here.
|
||||
|
||||
Tables can look like this:
|
||||
|
||||
size material color
|
||||
---- ------------ ------------
|
||||
9 leather brown
|
||||
10 hemp canvas natural
|
||||
11 glass transparent
|
||||
|
||||
Table: Shoes, their sizes, and what they're made of
|
||||
|
||||
(The above is the caption for the table.) Pandoc also supports
|
||||
multi-line tables:
|
||||
|
||||
-------- -----------------------
|
||||
keyword text
|
||||
-------- -----------------------
|
||||
red Sunsets, apples, and
|
||||
other red or reddish
|
||||
things.
|
||||
|
||||
green Leaves, grass, frogs
|
||||
and other things it's
|
||||
not easy being.
|
||||
-------- -----------------------
|
||||
|
||||
A horizontal rule follows.
|
||||
|
||||
***
|
||||
|
||||
Here's a definition list:
|
||||
|
||||
apples
|
||||
: Good for making applesauce.
|
||||
oranges
|
||||
: Citrus!
|
||||
tomatoes
|
||||
: There's no "e" in tomatoe.
|
||||
|
||||
Again, text is indented 4 spaces. (Put a blank line between each
|
||||
term/definition pair to spread things out more.)
|
||||
|
||||
Here's a "line block":
|
||||
|
||||
| Line one
|
||||
| Line too
|
||||
| Line tree
|
||||
|
||||
and images can be specified like so:
|
||||
|
||||
![example image](example-image.jpg "An exemplary image")
|
||||
|
||||
Inline math equations go in like so: $\omega = d\phi / dt$. Display
|
||||
math should get its own line and be put in in double-dollarsigns:
|
||||
|
||||
$$I = \int \rho R^{2} dV$$
|
||||
|
||||
And note that you can backslash-escape any punctuation characters
|
||||
which you wish to be displayed literally, ex.: \`foo\`, \*bar\*, etc.
|
|
@ -0,0 +1,31 @@
|
|||
.popover {
|
||||
-fx-background-radius: 5;
|
||||
}
|
||||
|
||||
.popover > .content {
|
||||
-fx-padding: 1;
|
||||
-fx-background-radius: 5px;
|
||||
}
|
||||
|
||||
.popover > .content > .title > .icon {
|
||||
-fx-padding: 10 10 0 0;
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.popover > .content > .title > .text {
|
||||
}
|
||||
|
||||
.popover > .content > .title > .icon:hover > .graphics * {
|
||||
-fx-fill: -color-neutral-muted;
|
||||
}
|
||||
|
||||
.popover > .content > .title {
|
||||
-fx-background-color: -color-bg-subtle;
|
||||
-fx-background-radius: 5 5 0 0;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
-fx-border-color: -color-border-default;
|
||||
}
|
||||
|
||||
.popover > .content > .title > .text {
|
||||
-fx-padding: 10 0 0 0;
|
||||
}
|
|
@ -1,12 +1,3 @@
|
|||
.popover {
|
||||
-fx-background-radius: 0;
|
||||
}
|
||||
|
||||
.popover > .content {
|
||||
-fx-padding: 10px 0 0 0;
|
||||
-fx-background-radius: 4px;
|
||||
}
|
||||
|
||||
.store-mini-list-comp > * > * > .content {
|
||||
-fx-spacing: 0.5em;
|
||||
}
|
||||
|
|
|
@ -454,3 +454,6 @@ lockVaultOnHibernationDescription=Når denne funktion er aktiveret, låses Vault
|
|||
#custom
|
||||
overview=Oversigt
|
||||
history=Browsing-historik
|
||||
skipAll=Spring alle over
|
||||
notes=Bemærkninger
|
||||
addNotes=Tilføj noter
|
||||
|
|
|
@ -448,3 +448,6 @@ lockVaultOnHibernation=Tresor im Ruhezustand des Computers sperren
|
|||
lockVaultOnHibernationDescription=Wenn diese Funktion aktiviert ist, wird der Tresor automatisch gesperrt, sobald dein Computer in den Ruhezustand versetzt wird. Nach dem Aufwachen musst du deine Tresor-Passphrase erneut eingeben.
|
||||
overview=Übersicht
|
||||
history=Browsing-Verlauf
|
||||
skipAll=Alles überspringen
|
||||
notes=Anmerkungen
|
||||
addNotes=Notizen hinzufügen
|
||||
|
|
|
@ -452,3 +452,5 @@ lockVaultOnHibernationDescription=When enabled, the vault will automatically be
|
|||
overview=Overview
|
||||
history=Browsing history
|
||||
skipAll=Skip all
|
||||
notes=Notes
|
||||
addNotes=Add notes
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=Bloquear la bóveda al hibernar el ordenador
|
|||
lockVaultOnHibernationDescription=Si está activada, el almacén se bloqueará automáticamente cuando tu ordenador entre en hibernación/reposo. Al despertarte, tendrás que volver a introducir la contraseña de tu bóveda.
|
||||
overview=Visión general
|
||||
history=Historial de navegación
|
||||
skipAll=Saltar todo
|
||||
notes=Notas
|
||||
addNotes=Añadir notas
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=Verrouille le coffre-fort lors de l'hibernation de l'ordi
|
|||
lockVaultOnHibernationDescription=Lorsque cette option est activée, le coffre-fort sera automatiquement verrouillé une fois que ton ordinateur sera mis en hibernation/en veille. Au réveil, tu devras saisir à nouveau la phrase de passe de ton coffre-fort.
|
||||
overview=Vue d'ensemble
|
||||
history=Historique de navigation
|
||||
skipAll=Sauter tout
|
||||
notes=Notes
|
||||
addNotes=Ajouter des notes
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=Blocca il caveau durante l'ibernazione del computer
|
|||
lockVaultOnHibernationDescription=Se abilitato, il vault si blocca automaticamente quando il computer viene messo in ibernazione o a riposo. Al risveglio, dovrai inserire nuovamente la passphrase del vault.
|
||||
overview=Panoramica
|
||||
history=Cronologia di navigazione
|
||||
skipAll=Salta tutto
|
||||
notes=Note
|
||||
addNotes=Aggiungi note
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=コンピュータのハイバネーション時に保管
|
|||
lockVaultOnHibernationDescription=有効にすると、コンピュータが休止状態/スリープ状態になると、保管庫は自動的にロックされる。スリープ解除後、保管庫のパスフレーズを再度入力する必要がある。
|
||||
overview=概要
|
||||
history=閲覧履歴
|
||||
skipAll=すべてスキップする
|
||||
notes=備考
|
||||
addNotes=メモを追加する
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=Kluis op computer in slaapstand
|
|||
lockVaultOnHibernationDescription=Als deze optie is ingeschakeld, wordt de kluis automatisch vergrendeld zodra je computer in de slaapstand wordt gezet. Als je wakker wordt, moet je je wachtwoordzin voor de kluis opnieuw invoeren.
|
||||
overview=Overzicht
|
||||
history=Browsegeschiedenis
|
||||
skipAll=Alles overslaan
|
||||
notes=Opmerkingen
|
||||
addNotes=Opmerkingen toevoegen
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=Bloqueia o cofre na hibernação do computador
|
|||
lockVaultOnHibernationDescription=Quando ativado, a abóbada é automaticamente bloqueada quando o computador é colocado em hibernação/sono. Quando acordares, terás de introduzir novamente a frase-chave do cofre.
|
||||
overview=Resumo
|
||||
history=Histórico de navegação
|
||||
skipAll=Salta tudo
|
||||
notes=Nota
|
||||
addNotes=Adiciona notas
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=Блокировка хранилища при спяще
|
|||
lockVaultOnHibernationDescription=Если эта функция включена, хранилище будет автоматически блокироваться, как только компьютер перейдет в спящий режим. После пробуждения тебе придется снова ввести кодовую фразу хранилища.
|
||||
overview=Обзор
|
||||
history=История просмотров
|
||||
skipAll=Пропустить все
|
||||
notes=Заметки
|
||||
addNotes=Добавляй заметки
|
||||
|
|
|
@ -436,3 +436,6 @@ lockVaultOnHibernation=Bilgisayar hazırda bekletme modunda kasayı kilitleme
|
|||
lockVaultOnHibernationDescription=Etkinleştirildiğinde, bilgisayarınız hazırda bekletme/uyku moduna geçtiğinde kasa otomatik olarak kilitlenecektir. Uyandığınızda, kasa parolanızı tekrar girmeniz gerekecektir.
|
||||
overview=Genel Bakış
|
||||
history=Tarama geçmişi
|
||||
skipAll=Tümünü atla
|
||||
notes=Notlar
|
||||
addNotes=Notlar ekleyin
|
||||
|
|
|
@ -435,3 +435,6 @@ lockVaultOnHibernation=电脑休眠时锁定保险库
|
|||
lockVaultOnHibernationDescription=启用后,一旦电脑进入休眠/睡眠状态,保管库就会自动锁定。唤醒后,您必须再次输入保险库密码。
|
||||
overview=概述
|
||||
history=浏览历史
|
||||
skipAll=全部跳过
|
||||
notes=说明
|
||||
addNotes=添加注释
|
||||
|
|
Loading…
Reference in a new issue