Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions app/Support/CommonMark/AlertBlockQuoteRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace App\Support\CommonMark;

use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Node\Block\Paragraph;
use League\CommonMark\Node\Inline\Newline;
use League\CommonMark\Node\Inline\Text;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;
use League\CommonMark\Util\HtmlElement;

class AlertBlockQuoteRenderer implements NodeRendererInterface
{
/**
* @var array<string, array{label: string, icon: string}>
*/
protected const ALERT_TYPES = [
'NOTE' => [
'label' => 'Note',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>',
],
'TIP' => [
'label' => 'Tip',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>',
],
'IMPORTANT' => [
'label' => 'Important',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>',
],
'WARNING' => [
'label' => 'Warning',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>',
],
'CAUTION' => [
'label' => 'Caution',
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>',
],
];

public function render(Node $node, ChildNodeRendererInterface $childRenderer): ?HtmlElement
{
BlockQuote::assertInstanceOf($node);

$firstChild = $node->firstChild();

if (! $firstChild instanceof Paragraph) {
return null;
}

$firstInline = $firstChild->firstChild();

if (! $firstInline instanceof Text) {
return null;
}

$literal = $firstInline->getLiteral();

if (! preg_match('/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]/', $literal, $matches)) {
return null;
}

$type = $matches[1];
$alertConfig = self::ALERT_TYPES[$type];

$remaining = ltrim(substr($literal, strlen($matches[0])));

if ($remaining !== '') {
$firstInline->setLiteral($remaining);
} else {
$nextSibling = $firstInline->next();

$firstInline->detach();

if ($nextSibling instanceof Newline) {
$nextSibling->detach();
}
}

if (! $firstChild->hasChildren()) {
$firstChild->detach();
}

$innerHtml = $childRenderer->renderNodes($node->children());

$titleHtml = new HtmlElement(
'p',
['class' => 'markdown-alert-title'],
$alertConfig['icon'].' '.$alertConfig['label'],
);

$typeSlug = strtolower($type);

return new HtmlElement(
'div',
['class' => "markdown-alert markdown-alert-{$typeSlug}"],
$titleHtml.$innerHtml,
);
}
}
2 changes: 2 additions & 0 deletions app/Support/CommonMark/CommonMark.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use App\Extensions\TorchlightWithCopyExtension;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
use League\CommonMark\Extension\Embed\Bridge\OscaroteroEmbedAdapter;
use League\CommonMark\Extension\Embed\Embed as EmbedNode;
Expand Down Expand Up @@ -53,6 +54,7 @@ protected static function getConverter(): MarkdownConverter
$environment->addExtension(new GithubFlavoredMarkdownExtension);
static::$headingRenderer = new HeadingRenderer;
$environment->addRenderer(Heading::class, static::$headingRenderer);
$environment->addRenderer(BlockQuote::class, new AlertBlockQuoteRenderer, 10);
$environment->addExtension(new TableExtension);

$environment->addExtension(new EmbedExtension);
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

102 changes: 102 additions & 0 deletions resources/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,108 @@ nav.docs-navigation li:has(.third-tier .exact-active) > .subsection-header {
@apply relative z-0 mt-5 overflow-hidden rounded-2xl bg-gradient-to-tl from-transparent to-violet-100/75 px-5 ring-1 ring-black/5 dark:from-slate-900/30 dark:to-indigo-900/35;
}

/* GitHub-style markdown alerts */
.prose .markdown-alert {
@apply relative z-0 my-4 overflow-hidden rounded-2xl border-l-4 px-5 py-3 ring-1 ring-black/5;
}

.prose .markdown-alert > :first-child {
@apply mt-0;
}

.prose .markdown-alert > :last-child {
@apply mb-0;
}

.prose .markdown-alert-title {
@apply flex items-center gap-2 font-semibold;
}

.prose .markdown-alert-title svg {
@apply shrink-0;
}

.prose .markdown-alert-note {
@apply border-blue-400 bg-gradient-to-tl from-transparent to-blue-100/75 text-blue-900;
}

.prose .markdown-alert-note .markdown-alert-title {
@apply text-blue-700;
}

.prose .markdown-alert-tip {
@apply border-green-400 bg-gradient-to-tl from-transparent to-green-100/75 text-green-900;
}

.prose .markdown-alert-tip .markdown-alert-title {
@apply text-green-700;
}

.prose .markdown-alert-important {
@apply border-purple-400 bg-gradient-to-tl from-transparent to-purple-100/75 text-purple-900;
}

.prose .markdown-alert-important .markdown-alert-title {
@apply text-purple-700;
}

.prose .markdown-alert-warning {
@apply border-amber-400 bg-gradient-to-tl from-transparent to-amber-100/75 text-amber-900;
}

.prose .markdown-alert-warning .markdown-alert-title {
@apply text-amber-700;
}

.prose .markdown-alert-caution {
@apply border-red-400 bg-gradient-to-tl from-transparent to-red-100/75 text-red-900;
}

.prose .markdown-alert-caution .markdown-alert-title {
@apply text-red-700;
}

/* Dark mode markdown alerts */
.dark .prose .markdown-alert-note {
@apply border-blue-500 from-slate-900/30 to-blue-900/35 text-blue-200;
}

.dark .prose .markdown-alert-note .markdown-alert-title {
@apply text-blue-400;
}

.dark .prose .markdown-alert-tip {
@apply border-green-500 from-slate-900/30 to-green-900/35 text-green-200;
}

.dark .prose .markdown-alert-tip .markdown-alert-title {
@apply text-green-400;
}

.dark .prose .markdown-alert-important {
@apply border-purple-500 from-slate-900/30 to-purple-900/35 text-purple-200;
}

.dark .prose .markdown-alert-important .markdown-alert-title {
@apply text-purple-400;
}

.dark .prose .markdown-alert-warning {
@apply border-amber-500 from-slate-900/30 to-amber-900/35 text-amber-200;
}

.dark .prose .markdown-alert-warning .markdown-alert-title {
@apply text-amber-400;
}

.dark .prose .markdown-alert-caution {
@apply border-red-500 from-slate-900/30 to-red-900/35 text-red-200;
}

.dark .prose .markdown-alert-caution .markdown-alert-title {
@apply text-red-400;
}

.images-two-up {
@apply grid gap-8 mt-0 items-center;

Expand Down
33 changes: 12 additions & 21 deletions resources/views/docs/mobile/3/concepts/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,9 @@ This data is only accessible by your app and is persisted beyond the lifetime of
the next time your app is opened.


<aside>

Secure Storage is only meant for small amounts of text data, usually no more than a few KBs. If you need to store
larger amounts of data or files, you should store this in a database or as a file.

</aside>
> [!NOTE]
> Secure Storage is only meant for small amounts of text data, usually no more than a few KBs. If you need to store
> larger amounts of data or files, you should store this in a database or as a file.

### When to use the Laravel `Crypt` facade

Expand All @@ -58,11 +55,8 @@ stored on the device.
NativePHP securely reads the `APP_KEY` from secure storage and makes it available to Laravel. So you can safely use the
`Crypt` facade to encrypt and decrypt data!

<aside>

Make sure you do not leak the `APP_KEY` or decrypted data inadvertently through error tracking or debug logging tools.

</aside>
> [!WARNING]
> Make sure you do not leak the `APP_KEY` or decrypted data inadvertently through error tracking or debug logging tools.

This is great for encrypting larger amounts of data that wouldn't easily fit in secure storage. You can encrypt values
and store them in the file system or in the SQLite database, knowing that they are safe at rest:
Expand All @@ -85,14 +79,11 @@ $decryptedContents = Crypt::decryptString(
);
```

<aside>

Data encrypted with the `Crypt` facade should stay on the user's device with your app. Placing it encrypted anywhere
else risks the chance that it will be unrecoverable. If the user loses their device or deletes your app,
they will lose the encryption key and the data will be encrypted forever.

If you wish to share data, decrypt it first, transmit securely (e.g. over HTTPS) and re-encrypt it with a different key
that is safely managed elsewhere.

</aside>
> [!CAUTION]
> Data encrypted with the `Crypt` facade should stay on the user's device with your app. Placing it encrypted anywhere
> else risks the chance that it will be unrecoverable. If the user loses their device or deletes your app,
> they will lose the encryption key and the data will be encrypted forever.
>
> If you wish to share data, decrypt it first, transmit securely (e.g. over HTTPS) and re-encrypt it with a different key
> that is safely managed elsewhere.

Loading
Loading