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
64 changes: 1 addition & 63 deletions app/Devnull/Display.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace App\Devnull;

use App\Devnull\Data\Commit;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;

Expand Down Expand Up @@ -37,12 +36,10 @@ final class Display

/**
* How far below the top of a reply's row its elbow comes level with the
* middle of the reply's avatar, and the radius of the elbow's corner.
* middle of the reply's avatar.
*/
public const int ElbowLevel = 22;

public const int ElbowRadius = 12;

public static function relativeTime(?CarbonInterface $date, ?CarbonInterface $now = null): string
{
if ($date === null) {
Expand Down Expand Up @@ -146,65 +143,6 @@ public static function maskedKey(string $openSsh): string
return implode(' ', $parts);
}

/**
* Enough 4pt dashes, with 3pt gaps, to run a dashed line down a commit's
* row, which is clipped where the row ends. PHP can't know how tall the
* row is drawn, so this errs long from the text, media and actions in it.
*/
public static function dashesFor(Commit $commit): int
{
$text = $commit->isFolded() ? Commit::PreviewLength : mb_strlen($commit->body);
$lines = (int) ceil($text / 32) + substr_count($commit->isFolded() ? '' : $commit->body, "\n");
$height = 110 + $lines * 26
+ ($commit->images === [] ? 0 : 210)
+ ($commit->poll === null ? 0 : 50 + 46 * count($commit->poll->options))
+ ($commit->isQuote() ? 230 : 0)
+ ($commit->linkPreview === null ? 0 : 80);

return min(250, (int) ceil($height / 7));
}

/**
* The dashes of a thread's elbow, as the web's from #121: down the line at
* $from, round a 12pt corner, and across to the reply's avatar at $to,
* level with its middle. They keep the 4pt dash and 3pt gap all the way
* round, with one on the middle of the bend so the corner reads the same
* from either side, and the ones on the bend turned to follow it. The last
* one may run past 1pt short of the avatar, where the elbow is cut off, as
* a dashed border would be.
*
* @return list<array{x: float, y: float, rotate: float}> each dash's middle, and how far it's turned from upright, in degrees
*/
public static function elbowDashes(float $from, float $to): array
{
$line = $from + 0.5;
$down = self::ElbowLevel - self::ElbowRadius;
$bend = M_PI * self::ElbowRadius / 2;
$length = $down + $bend + ($to - 1) - ($line + self::ElbowRadius);

$dashes = [];

for ($middle = fmod($down + $bend / 2, 7); $middle - 2 < $length; $middle += 7) {
if ($middle < 2) {
continue;
}

$turn = min(M_PI / 2, max(0, ($middle - $down) / self::ElbowRadius));

$dashes[] = match (true) {
$middle <= $down => ['x' => $line, 'y' => round($middle, 2), 'rotate' => 0.0],
$middle >= $down + $bend => ['x' => round($line + self::ElbowRadius + $middle - $down - $bend, 2), 'y' => (float) self::ElbowLevel, 'rotate' => -90.0],
default => [
'x' => round($line + self::ElbowRadius - self::ElbowRadius * cos($turn), 2),
'y' => round($down + self::ElbowRadius * sin($turn), 2),
'rotate' => round(-rad2deg($turn), 2),
],
};
}

return $dashes;
}

/**
* How far a commit page has to scroll past its last reply to clear the
* reply bar. A pushed screen is drawn under its bottom bar and the home
Expand Down
8 changes: 4 additions & 4 deletions composer.lock

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

Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@
'tail' => ($inFeed ? $continuesNext || ! $continuesRun : $withTail) ? $commit->lane() : null,
'endsWithDot' => $endsWithDot,
'replyTail' => $threadBelow && ! ($inFeed && $continuesNext),
'replyDashes' => \App\Devnull\Display::dashesFor($commit),
'node' => $continuesRun ? 'dot' : 'avatar',
'avatarSize' => $muted ? 36 : 48,
'user' => $author,
Expand Down
21 changes: 3 additions & 18 deletions resources/views/native/partials/dashed-box.blade.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
{{--
A 1pt dashed border drawn over the box it's placed last in, standing in for the web's `border-dashed`, since EDGE
has no dashed borders: a row of dashes along the top and bottom, a column down each side. The corners are square
where the web rounds them, as dashes can't follow a curve here without being placed one by one.
A 1pt dashed border, 8pt rounded, drawn over the box it's placed last in, as the web's `border border-dashed`.
--}}
@php($colour ??= 'bg-theme-hairline')
@foreach (['top-0', 'bottom-0'] as $edge)
<native:row class="absolute {{ $edge }} left-0 right-0 h-[1] gap-[3]">
@foreach (range(1, 40) as $dash)
<native:column class="flex-1 h-[1] {{ $colour }}" />
@endforeach
</native:row>
@endforeach
@foreach (['left-0', 'right-0'] as $edge)
<native:column class="absolute top-0 bottom-0 {{ $edge }} w-[1] gap-[3]">
@foreach (range(1, 6) as $dash)
<native:column class="w-[1] flex-1 {{ $colour }}" />
@endforeach
</native:column>
@endforeach
@php($colour ??= 'border-theme-hairline')
<native:column class="absolute top-0 bottom-0 left-0 right-0 rounded-lg border border-dashed {{ $colour }}" />
13 changes: 3 additions & 10 deletions resources/views/native/partials/dashed-line.blade.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
{{--
A 1pt vertical line in dashes, standing in for the web's `border-l border-dashed`, since EDGE has no dashed borders.
$position places it (top, bottom or height classes) and $left is its x in points. Each dash is 4pt with a 3pt gap,
so a line of a height PHP can't know is drawn with $dashes enough for it and clipped to its box: any corner radius
makes EDGE clip a node to its shape, so a hairline radius is enough.
A 1pt vertical line in dashes of $lane's colour, as the web's `border-l border-dashed`: 4pt dashes with 3pt gaps,
starting at its top and running as far as $position (top, bottom or height classes) lets it. $left is its x in points.
--}}
@php($dashes ??= 4)
<native:column class="absolute {{ $position }} left-[{{ $left }}] w-[1] gap-[3] rounded-[0.5]">
@foreach (range(1, max(1, $dashes)) as $dash)
<native:column class="w-[1] h-[4] {{ $colour }}" />
@endforeach
</native:column>
<native:column class="absolute {{ $position }} left-[{{ $left }}] w-[1] border-l border-dashed border-theme-{{ \App\Devnull\Lane::token($lane) }}" />
14 changes: 2 additions & 12 deletions resources/views/native/partials/dashed-ring.blade.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
{{--
A 2pt ring drawn in dashes, standing in for the web's `border-dashed` since EDGE has no dashed borders: each dash
is placed on the circle and turned to follow it.
A 2pt ring in dashes of $lane's colour, as the web's `border-2 border-dashed rounded-full`, $size across.
--}}
@php($segments = 16)
@php($radius = $size / 2 - 1)
<native:column :width="$size" :height="$size" class="absolute top-0 left-0">
@foreach (range(0, $segments - 1) as $index)
@php($angle = 360 / $segments * $index)
@php($x = $size / 2 + $radius * sin(deg2rad($angle)))
@php($y = $size / 2 - $radius * cos(deg2rad($angle)))
<native:column class="absolute top-[{{ round($y - 1, 2) }}] left-[{{ round($x - 2.5, 2) }}] w-[5] h-[2] rounded-full {{ $colour }}" :rotate="$angle" />
@endforeach
</native:column>
<native:column :width="$size" :height="$size" class="absolute top-0 left-0 rounded-full border-2 border-dashed border-theme-{{ \App\Devnull\Lane::token($lane) }}" />
2 changes: 1 addition & 1 deletion resources/views/native/partials/earlier-commits.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<native:column class="w-full h-[1] bg-theme-hairline" />
</native:column>

@include('native.partials.dashed-line', ['position' => 'top-0 h-[13]', 'left' => 31.5, 'colour' => 'bg-theme-rail', 'dashes' => 2])
@include('native.partials.dashed-line', ['position' => 'top-0 h-[13]', 'left' => 31.5, 'lane' => \App\Devnull\Lane::Rail])
<native:column class="absolute top-[31] bottom-0 left-[31] w-[2] {{ $colour }}" />
<native:column ref="earlier-node" class="absolute top-[13] left-[23]">
@include('native.partials.rail-node', ['lane' => $lane, 'filled' => false])
Expand Down
2 changes: 1 addition & 1 deletion resources/views/native/partials/rail-avatar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@php($size ??= 48)
@if ($staged)
<native:column ref="staged-avatar" :width="48" :height="48" class="rounded-full bg-theme-surface">
@include('native.partials.dashed-ring', ['size' => 48, 'colour' => 'bg-theme-'.\App\Devnull\Lane::token($lane)])
@include('native.partials.dashed-ring', ['size' => 48, 'lane' => $lane])
<native:column class="absolute top-[4] left-[4]">
@include('native.partials.avatar', ['user' => $user, 'size' => 40])
</native:column>
Expand Down
8 changes: 3 additions & 5 deletions resources/views/native/partials/rail.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
null no node; a $previous segment then runs the full height of the row
$endsWithDot stops the $tail 20pt above the bottom at a lane dot, as the web ends a commit that's alone in its run.
$replyTail runs a dashed line in the lane on down from the node, or from that dot, to the replies under the row.
It's $replyDashes long when it starts at the node, enough for the row, since PHP can't know its height.
$avatarSize draws the avatar's ring smaller than its 48pt, centred in the same place.
--}}
@php($previous ??= null)
Expand All @@ -22,7 +21,6 @@
@php($tailDashes ??= 3)
@php($endsWithDot ??= false)
@php($replyTail ??= false)
@php($replyDashes ??= 40)
@php($avatarSize ??= 48)
@php($center = 32)
@php($endDot = 20)
Expand All @@ -48,9 +46,9 @@
@endif

@if ($replyTail && $endsWithDot)
@include('native.partials.dashed-line', ['position' => 'bottom-0 h-['.$endDot.']', 'left' => 31.5, 'colour' => $segment($lane), 'dashes' => 3])
@include('native.partials.dashed-line', ['position' => 'bottom-0 h-['.$endDot.']', 'left' => 31.5, 'lane' => $lane])
@elseif ($replyTail)
@include('native.partials.dashed-line', ['position' => 'top-['.($node === 'dot' ? $center - 9 : $center).'] bottom-0', 'left' => 31.5, 'colour' => $segment($lane), 'dashes' => $replyDashes])
@include('native.partials.dashed-line', ['position' => 'top-['.($node === 'dot' ? $center - 9 : $center).'] bottom-0', 'left' => 31.5, 'lane' => $lane])
@endif

@if ($endsWithDot && $tail !== null)
Expand Down Expand Up @@ -81,7 +79,7 @@
@include('native.partials.rail-avatar', ['user' => $user, 'lane' => $lane, 'staged' => $node === 'staged'])
@elseif ($node === 'tombstone')
<native:column :width="48" :height="48" class="rounded-full bg-theme-surface">
@include('native.partials.dashed-ring', ['size' => 48, 'colour' => 'bg-theme-rail'])
@include('native.partials.dashed-ring', ['size' => 48, 'lane' => \App\Devnull\Lane::Rail])
</native:column>
@elseif ($node === 'skeleton')
<native:stack :width="48" :height="48" center class="rounded-full bg-theme-surface">
Expand Down
17 changes: 2 additions & 15 deletions resources/views/native/partials/thread-elbow.blade.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
{{--
Where a thread leaves the rail, as the web's thread elbow from #121: a dashed line in the commit's lane down from
the rail ($from), round a 12pt corner, and across to the first reply's avatar ($to), level with its middle. A
nested reply's elbow leaves the spine of the reply above it the same way. EDGE has no dashed borders, so each dash
is placed along the way (see Display::elbowDashes), and the ones on the corner are turned to follow it, as in
dashed-ring. Any corner radius makes EDGE clip a node to its shape, so the last dash is cut 1pt short of the avatar.
nested reply's elbow leaves the spine of the reply above it the same way. It stops 1pt short of the avatar.
--}}
@php($colour = 'bg-theme-'.\App\Devnull\Lane::token($lane))
@php($from ??= 31.5)
@php($to ??= 64)
<native:column ref="thread-elbow" class="absolute top-0 left-0 w-[{{ $to - 1 }}] h-[{{ \App\Devnull\Display::ElbowLevel + 1 }}] rounded-[0.5]">
@foreach (\App\Devnull\Display::elbowDashes($from, $to) as $dash)
@if ($dash['rotate'] === -90.0)
<native:column class="absolute top-[{{ $dash['y'] - 0.5 }}] left-[{{ round($dash['x'] - 2, 2) }}] w-[4] h-[1] {{ $colour }}" />
@elseif ($dash['rotate'] === 0.0)
<native:column class="absolute top-[{{ round($dash['y'] - 2, 2) }}] left-[{{ $dash['x'] - 0.5 }}] w-[1] h-[4] {{ $colour }}" />
@else
<native:column class="absolute top-[{{ round($dash['y'] - 2, 2) }}] left-[{{ round($dash['x'] - 0.5, 2) }}] w-[1] h-[4] {{ $colour }}" :rotate="$dash['rotate']" />
@endif
@endforeach
</native:column>
<native:column ref="thread-elbow" class="absolute top-0 left-[{{ $from }}] w-[{{ $to - 1 - $from }}] h-[{{ \App\Devnull\Display::ElbowLevel + 0.5 }}] border-l border-b rounded-bl-xl border-dashed border-theme-{{ \App\Devnull\Lane::token($lane) }}" />
6 changes: 3 additions & 3 deletions resources/views/native/partials/thread-links.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
@endif

@if ($spine !== null)
@include('native.partials.dashed-line', ['position' => 'top-0 bottom-0', 'left' => 75.5, 'colour' => $segment($spine), 'dashes' => \App\Devnull\Display::dashesFor($reply)])
@include('native.partials.dashed-line', ['position' => 'top-0 bottom-0', 'left' => 75.5, 'lane' => $spine])
@endif

@if ($previousLane === null)
@include('native.partials.thread-elbow', ['lane' => $lane, 'from' => $indent > 0 ? 75.5 : 31.5, 'to' => 64 + $indent])
@else
@include('native.partials.dashed-line', ['position' => 'top-0 h-[6]', 'left' => $avatarLine - 0.5, 'colour' => $segment($previousLane), 'dashes' => 1])
@include('native.partials.dashed-line', ['position' => 'top-0 h-[6]', 'left' => $avatarLine - 0.5, 'lane' => $previousLane])
@endif

@if ($hasNext)
{{-- Down to the next reply, or to the top of Show more's dot: 12pt under it, its padding and the hairline below. --}}
@include('native.partials.dashed-line', ['position' => 'top-[38] '.($more !== null ? 'bottom-[34]' : 'bottom-0'), 'left' => $avatarLine - 0.5, 'colour' => $segment($reply->lane()), 'dashes' => \App\Devnull\Display::dashesFor($reply)])
@include('native.partials.dashed-line', ['position' => 'top-[38] '.($more !== null ? 'bottom-[34]' : 'bottom-0'), 'left' => $avatarLine - 0.5, 'lane' => $reply->lane()])
@endif
5 changes: 2 additions & 3 deletions resources/views/native/partials/thread-reply.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
@php($spine ??= null)
@php($tombstones ??= false)
@php($more ??= null)
@php($segment = fn (int|string $lane): string => 'bg-theme-'.\App\Devnull\Lane::token($lane))
@php($avatarLine = 76 + $indent)
@if ($reply->isDeleted())
@php($opened = $tombstones && array_key_exists($reply->id, $tombstoneReplies ?? []))
Expand All @@ -32,7 +31,7 @@
<native:column class="flex-1">
<native:row class="w-full pr-4 pt-[10] gap-2 {{ $last && $more === null ? 'pb-3' : 'pb-1' }} {{ $indent > 0 ? 'pl-['.$indent.']' : '' }}">
<native:column :width="24" :height="24" class="rounded-full">
@include('native.partials.dashed-ring', ['size' => 24, 'colour' => 'bg-theme-rail'])
@include('native.partials.dashed-ring', ['size' => 24, 'lane' => \App\Devnull\Lane::Rail])
</native:column>
<native:column class="flex-1 gap-1">
<native:row class="w-full min-h-[24] items-center">
Expand All @@ -58,7 +57,7 @@
@include('native.partials.thread-links')
@if ($opened && ($tombstoneReplies[$reply->id] ?? []) !== [])
{{-- The spine its own replies hang off, down from its ring. --}}
@include('native.partials.dashed-line', ['position' => 'top-[38] bottom-0', 'left' => $avatarLine - 0.5, 'colour' => 'bg-theme-rail', 'dashes' => 6])
@include('native.partials.dashed-line', ['position' => 'top-[38] bottom-0', 'left' => $avatarLine - 0.5, 'lane' => \App\Devnull\Lane::Rail])
@endif
</native:row>
@else
Expand Down
2 changes: 1 addition & 1 deletion resources/views/native/this-device.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<native:stack :width="38" :height="38" center class="rounded-full border-2 {{ $option['chosen'] ? 'border-theme-'.Lane::token($option['lane']) : 'border-transparent' }}">
@if ($option['auto'])
<native:column :width="28" :height="28">
@include('native.partials.dashed-ring', ['size' => 28, 'colour' => 'bg-theme-'.Lane::token($option['lane'])])
@include('native.partials.dashed-ring', ['size' => 28, 'lane' => $option['lane']])
<native:column class="absolute top-[9] left-[9] w-[10] h-[10] rounded-full bg-theme-{{ Lane::token($option['lane']) }}" />
</native:column>
@elseif ($option['lane'] === null)
Expand Down
6 changes: 3 additions & 3 deletions tests/Feature/Screens/CommitDetailTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,10 @@ function fakeThread(array $commit = [], array $replies = [], array $extra = []):

// A dashed Rail Gray ring where the avatar was, as on the web, and a Rail Gray segment running on from it.
$tombstone = nodeByRef($screen, 'tombstone-c1');
$dashes = findNodes($tombstone, fn (array $node): bool => isset($node['props']['rotate']));
$rings = findNodes($tombstone, fn (array $node): bool => ($node['props']['border_style'] ?? null) === 1);

expect($dashes)->toHaveCount(16)
->and(array_unique(array_map(fn (array $dash): ?string => $dash['style']['bg_color'] ?? null, $dashes)))->toBe([$rail])
expect($rings)->toHaveCount(1)
->and($rings[0]['style'])->toMatchArray(['border_width' => 2.0, 'border_color' => $rail, 'border_radius' => 9999.0])
->and(findNode($tombstone, fn (array $node): bool => ($node['type'] ?? null) === 'stack' && ($node['layout']['width'] ?? null) === 40.0))->toBeNull();
});

Expand Down
Loading
Loading