mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-20 18:36:31 +08:00
Beautify match file selector results
- Makes the file selector results to have a "box"/"container" of its own - Seperates the filtred files from rest of the files with a border - Optimize path selector to only traverse the filesystem if the directory changes
This commit is contained in:
parent
193050cae5
commit
d41f3a73fe
1 changed files with 56 additions and 24 deletions
|
@ -17,7 +17,23 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
@impl true
|
@impl true
|
||||||
def mount(socket) do
|
def mount(socket) do
|
||||||
inner_block = Map.get(socket.assigns, :inner_block, nil)
|
inner_block = Map.get(socket.assigns, :inner_block, nil)
|
||||||
{:ok, assign(socket, inner_block: inner_block)}
|
{:ok, assign(socket, inner_block: inner_block, current_dir: nil)}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def update(assigns, socket) do
|
||||||
|
%{assigns: assigns} = socket = assign(socket, assigns)
|
||||||
|
{dir, basename} = split_path(assigns.path)
|
||||||
|
dir = Path.expand(dir)
|
||||||
|
|
||||||
|
files =
|
||||||
|
if assigns.current_dir != dir do
|
||||||
|
list_files(dir, assigns.extnames, assigns.running_paths)
|
||||||
|
else
|
||||||
|
assigns.files
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, assign(socket, files: annotate_matching(files, basename), current_dir: dir)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -50,8 +66,16 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow -m-1 p-1 overflow-y-auto tiny-scrollbar">
|
<div class="flex-grow -m-1 p-1 overflow-y-auto tiny-scrollbar">
|
||||||
|
<%= if highlighting?(@files) do %>
|
||||||
|
<div class="grid grid-cols-4 gap-2 border-b border-dashed border-grey-200 mb-2 pb-2">
|
||||||
|
<%= for file <- @files, file.highlighted != "" do %>
|
||||||
|
<%= render_file(file, @phx_target) %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<div class="grid grid-cols-4 gap-2">
|
<div class="grid grid-cols-4 gap-2">
|
||||||
<%= for file <- list_matching_files(@path, @extnames, @running_paths) do %>
|
<%= for file <- @files, file.highlighted == "" do %>
|
||||||
<%= render_file(file, @phx_target) %>
|
<%= render_file(file, @phx_target) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -60,6 +84,10 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp highlighting?(files) do
|
||||||
|
Enum.any?(files, & &1.highlighted != "")
|
||||||
|
end
|
||||||
|
|
||||||
defp render_file(file, phx_target) do
|
defp render_file(file, phx_target) do
|
||||||
icon =
|
icon =
|
||||||
case file do
|
case file do
|
||||||
|
@ -92,18 +120,17 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp list_matching_files(path, extnames, running_paths) do
|
defp annotate_matching(files, prefix) do
|
||||||
# Note: to provide an intuitive behavior when typing the path
|
for %{name: name} = file <- files do
|
||||||
# we enter a new directory when it has a trailing slash,
|
if String.starts_with?(name, prefix) do
|
||||||
# so given "/foo/bar" we list files in "foo" and given "/foo/bar/
|
%{file | highlighted: prefix, unhighlighted: String.replace_prefix(name, prefix, "")}
|
||||||
# we list files in "bar".
|
else
|
||||||
#
|
%{file | highlighted: "", unhighlighted: name}
|
||||||
# The basename is kinda like search within the current directory,
|
end
|
||||||
# so we highlight files starting with that string.
|
end
|
||||||
|
end
|
||||||
{dir, basename} = split_path(path)
|
|
||||||
dir = Path.expand(dir)
|
|
||||||
|
|
||||||
|
defp list_files(dir, extnames, running_paths) do
|
||||||
if File.exists?(dir) do
|
if File.exists?(dir) do
|
||||||
file_names =
|
file_names =
|
||||||
case File.ls(dir) do
|
case File.ls(dir) do
|
||||||
|
@ -114,36 +141,34 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
file_infos =
|
file_infos =
|
||||||
file_names
|
file_names
|
||||||
|> Enum.map(fn name ->
|
|> Enum.map(fn name ->
|
||||||
file_info(dir, name, basename, running_paths)
|
file_info(name, Path.join(dir, name), running_paths)
|
||||||
end)
|
end)
|
||||||
|> Enum.filter(fn file ->
|
|> Enum.filter(fn file ->
|
||||||
not hidden?(file.name) and (file.is_dir or valid_extension?(file.name, extnames))
|
not hidden?(file.name) and (file.is_dir or valid_extension?(file.name, extnames))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
parent = Path.dirname(dir)
|
||||||
|
|
||||||
file_infos =
|
file_infos =
|
||||||
if Path.dirname(dir) == dir do
|
if parent == dir do
|
||||||
file_infos
|
file_infos
|
||||||
else
|
else
|
||||||
parent_dir = file_info(dir, "..", basename, running_paths)
|
[file_info("..", parent, running_paths) | file_infos]
|
||||||
[parent_dir | file_infos]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Enum.sort_by(file_infos, fn file ->
|
Enum.sort_by(file_infos, fn file -> {!file.is_dir, file.name} end)
|
||||||
{-String.length(file.highlighted), !file.is_dir, file.name}
|
|
||||||
end)
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp file_info(dir, name, filter, running_paths) do
|
defp file_info(name, path, running_paths) do
|
||||||
path = Path.join(dir, name) |> Path.expand()
|
|
||||||
is_dir = File.dir?(path)
|
is_dir = File.dir?(path)
|
||||||
|
|
||||||
%{
|
%{
|
||||||
name: name,
|
name: name,
|
||||||
highlighted: if(String.starts_with?(name, filter), do: filter, else: ""),
|
highlighted: "",
|
||||||
unhighlighted: String.replace_prefix(name, filter, ""),
|
unhighlighted: name,
|
||||||
path: if(is_dir, do: ensure_trailing_slash(path), else: path),
|
path: if(is_dir, do: ensure_trailing_slash(path), else: path),
|
||||||
is_dir: is_dir,
|
is_dir: is_dir,
|
||||||
is_running: path in running_paths
|
is_running: path in running_paths
|
||||||
|
@ -158,6 +183,13 @@ defmodule LivebookWeb.PathSelectComponent do
|
||||||
Path.extname(filename) in extnames
|
Path.extname(filename) in extnames
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Note: to provide an intuitive behavior when typing the path
|
||||||
|
# we enter a new directory when it has a trailing slash,
|
||||||
|
# so given "/foo/bar" we list files in "foo" and given "/foo/bar/
|
||||||
|
# we list files in "bar".
|
||||||
|
#
|
||||||
|
# The basename is kinda like search within the current directory,
|
||||||
|
# so we highlight files starting with that string.
|
||||||
defp split_path(path) do
|
defp split_path(path) do
|
||||||
if String.ends_with?(path, "/") do
|
if String.ends_with?(path, "/") do
|
||||||
{path, ""}
|
{path, ""}
|
||||||
|
|
Loading…
Add table
Reference in a new issue