How to theme menus in a custom twig
I just did a lot of this with Menu Block. I prefer Menu Block as it is a little more flexible and offers more template suggestions and hooks than the core menu module. It kind of looks like you are building your own block above, I can't tell, but you can save time by using Menu Block in that case.

In one of my menus, this is the twig file that handles the output. I did not do any preprocess or extra stuff, just built around the macro concept used in menu.html.twig. Every parent item has children, and if those children items exceed 7, it will start a new list. For example, if the menu link has 14 children, then my code will have a drop down consisting of 2 unordered lists with 7 links each. Our style then makes them into columns. This is a little different from your use case, but should get you on the right track.

{#
/**
 * @file
 * Theme override to display a menu.
 *
 * Available variables:
 * - menu_name: The machine name of the menu.
 * - items: A nested list of menu items. Each menu item contains:
 *   - attributes: HTML attributes for the menu item.
 *   - below: The menu item child items.
 *   - title: The menu link title.
 *   - url: The menu link url, instance of \Drupal\Core\Url
 *   - localized_options: Menu link localized options.
 *   - is_expanded: TRUE if the link has visible children within the current
 *     menu tree.
 *   - is_collapsed: TRUE if the link has children within the current menu tree
 *     that are not currently visible.
 *   - in_active_trail: TRUE if the link is in the active trail.
 */
#}
{% import _self as menus %}

{#
  We call a macro which calls itself to render the full tree.
  @see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.menu_links(items, attributes, 0) }}

{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    &lt;ul&gt;
      {% for item in items %}
        {%
          set classes = [
            'global-top__utility-item',
            'js-utility-item',
            item.in_active_trail ? 'active-trail',
            item.below ? 'has-submenu'
          ]
        %}

        &lt;li{{ item.attributes.addClass(classes) }}&gt;
          {{ link(item.title, item.url) }}
          {% if item.below %}
            {{ menus.submenu_links(item.below, attributes, menu_level + 1) }}
          {% endif %}
        &lt;/li&gt;
      {% endfor %}
    &lt;/ul&gt;
  {% endif %}
{% endmacro %}

{% macro submenu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  &lt;div class="global-top__submenu"&gt;
    {% for chunk in items|batch(7) %}
      &lt;ul class="global-top__submenu-col"&gt;
        {% for item in chunk %}
          &lt;li{{ item.attributes }}&gt;
            {{ link(item.title, item.url) }}
          &lt;/li&gt;
        {% endfor %}
      &lt;/ul&gt;
    {% endfor %}
  &lt;/div&gt;
{% endmacro %}