diff --git a/app/views/oer/addfile/choose_file.php b/app/views/oer/addfile/choose_file.php
index 6c896cf8d05c5a4adf8add4dfde83f414376b27a..c651766fa67f57bf794cb83065d4207b7af3f55d 100644
--- a/app/views/oer/addfile/choose_file.php
+++ b/app/views/oer/addfile/choose_file.php
@@ -9,15 +9,14 @@ if ($best_nine_tags && count($best_nine_tags) > 0) {
     }
 }
 ?>
-<form class="oer_search"
-      action="<?= $controller->link_for("oer/market/search") ?>"
-      method="GET"
-      data-searchresults="<?= htmlReady(json_encode($material_data)) ?>"
-      data-filteredtag="<?= htmlReady(Request::get("tag")) ?>"
-      data-filteredcategory="<?= htmlReady(Request::get("category")) ?>"
-      data-tags="<?= htmlReady(json_encode($tags)) ?>"
-      data-material_select_url_template="<?= htmlReady($controller->url_for("oer/addfile/choose_file", ['material_id' => "__material_id__", 'to_plugin' => Request::get("to_plugin"), 'to_folder_id' => Request::get("to_folder_id")])) ?>">
-    <input type="hidden" name="to_plugin" value="<?= htmlReady(Request::get("to_plugin")) ?>">
-    <input type="hidden" name="to_folder_id" value="<?= htmlReady(Request::get("to_folder_id")) ?>">
-    <?= $this->render_partial("oer/market/_searchform") ?>
-</form>
+<?= Studip\VueApp::create('OERSearch')
+    ->withProps([
+        'url' => $controller->url_for('oer/market/search'),
+        'search-results' => $material_data ?? false,
+        'filtered-tag' => Request::get('tag'),
+        'filtered-category' => Request::get('category'),
+        'tags' => $tags,
+        'material-select-url-template' => $controller->url_for('oer/addfile/choose_file', ['material_id' => '__material_id__']),
+        'to-plugin' => Request::get('to_plugin'),
+        'to-folder-id' => Request::get('to_folder_id'),
+    ])  ?>
diff --git a/app/views/oer/market/_searchform.php b/app/views/oer/market/_searchform.php
deleted file mode 100644
index 474042b6d09e10e07457bfad1d47c32bd1a20b5f..0000000000000000000000000000000000000000
--- a/app/views/oer/market/_searchform.php
+++ /dev/null
@@ -1,179 +0,0 @@
-<div class="searchform">
-    <div class="oneliner">
-        <div class="frame">
-            <span v-if="category != null"
-                  class="category activefilter" title="<?= _('Aktiver Filter der Kategorie') ?>">
-                <span>{{ category }}</span>
-                <a href="#"
-                   @click.prevent="clearCategory"
-                   class="erasefilter"
-                   title="<?= _('Filter der Kategorie entfernen') ?>">
-                    <studip-icon shape="decline" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                </a>
-            </span>
-
-            <span v-if="difficulty[0] != 1 || difficulty[1] != 12"
-                  class="niveau activefilter"
-                  title="<?= _('Aktiver Filter für das Niveau') ?>">
-                <?= _('Niveau') ?>: &nbsp;
-                <span>{{ difficulty[0] }}</span>
-                -
-                <span>{{ difficulty[1] }}</span>
-                <a href="#"
-                   @click.prevent="clearDifficulty"
-                   class="erasefilter"
-                   title="<?= _('Filter des Niveaus entfernen') ?>">
-                    <studip-icon shape="decline" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                </a>
-            </span>
-
-            <input type="text"
-                   name="search"
-                   @focus="showFilterPanel"
-                   @keyup="sync_search_text"
-                   @keydown.enter.prevent="search">
-
-            <button v-if="difficulty[0] != 1 || difficulty[1] != 12 || (category != null) || (searchtext.length > 0)"
-                    class="erase"
-                    type="button"
-                    title="<?= _('Suchformular zurücksetzen') ?>"
-                    @click="clearAllFilters">
-                <studip-icon shape="decline" role="clickable"></studip-icon>
-            </button>
-
-            <button @click="triggerFilterPanel"
-                    type="button"
-                    title="<?= _('Suchfilter einstellen') ?>"
-                    :class="activeFilterPanel ? 'active' : ''">
-                <studip-icon shape="filter" :role="activeFilterPanel ? 'info_alt' : 'clickable'"></studip-icon>
-            </button>
-
-            <div v-if="activeFilterPanel" class="filterpanel_shadow"></div>
-
-            <div v-if="activeFilterPanel" class="filterpanel">
-                <div>
-                    <h3><?= _('Kategorien') ?></h3>
-                    <ul class="clean">
-                        <li>
-                            <a href="<?= $controller->link_for("oer/market", ['category' => "audio"]) ?>" @click.prevent="category = 'audio'">
-                                <studip-icon v-if="category != 'audio'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <studip-icon v-if="category == 'audio'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <?= _('Audio') ?>
-                            </a>
-                        </li>
-                        <li>
-                            <a href="<?= $controller->link_for("oer/market", ['category' => "video"]) ?>" @click.prevent="category = 'video'">
-                                <studip-icon v-if="category != 'video'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <studip-icon v-if="category == 'video'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <?= _('Video') ?>
-                            </a>
-                        </li>
-                        <li>
-                            <a href="<?= $controller->link_for("oer/market", ['category' => "presentation"]) ?>" @click.prevent="category = 'presentation'">
-                                <studip-icon v-if="category != 'presentation'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <studip-icon v-if="category == 'presentation'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <?= _('Folien') ?>
-                            </a>
-                        </li>
-                        <li>
-                            <a href="<?= $controller->link_for("oer/market", ['category' => "elearning"]) ?>" @click.prevent="category = 'elearning'">
-                                <studip-icon v-if="category != 'elearning'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <studip-icon v-if="category == 'elearning'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <?= _('Lernmodule') ?>
-                            </a>
-                        </li>
-                        <li>
-                            <a href="<?= $controller->link_for("oer/market", ['get' => "all"]) ?>">
-                                <studip-icon shape="link-intern" role="clickable" :size="16" class="text-bottom"></studip-icon>
-                                <?= _('Alles') ?>
-                            </a>
-                        </li>
-                    </ul>
-                </div>
-                <div class="level_filter">
-                    <h3><?= _('Niveau') ?></h3>
-                    <div class="level_labels">
-                        <div><?= _('Leicht') ?></div>
-                        <div><?= _('Schwer') ?></div>
-                    </div>
-                    <div class="level_numbers">
-                        <? for ($i = 1; $i <= 12; $i++) : ?>
-                            <div><?= ($i < 10 ? "&nbsp;" : "").$i ?></div>
-                        <? endfor ?>
-                    </div>
-                    <div id="difficulty_slider"></div>
-
-                    <input type="hidden" id="difficulty" name="difficulty" value="">
-                </div>
-            </div>
-
-
-            <button title="<?= _('Suche starten') ?>" @click.prevent="search" @focus="hideFilterPanel">
-                <studip-icon shape="search" role="clickable"></studip-icon>
-            </button>
-        </div>
-
-    </div>
-
-
-</div>
-
-<div class="browser">
-
-    <div v-if="browseMode === false" class="intro">
-        <img src="<?= Assets::image_path("oer-keyvisual-negative.svg") ?>" class="illustration responsive-hidden">
-        <div>
-            <h3><?= _('Wertvolle Lernmaterialien entdecken!') ?></h3>
-            <div class="responsive-hidden">
-                <?= _('Neue und spannende Lernmaterialien zu finden, ist ganz einfach. Mit dem Entdeckermodus können Sie nach Schlagwörtern stöbern und durch Themengebiete surfen.') ?>
-            </div>
-
-            <div>
-                <?= \Studip\LinkButton::create(_('Zum Entdeckermodus'), "#", ['@click.prevent' => "browseMode=true"]) ?>
-            </div>
-        </div>
-    </div>
-
-    <div v-if="browseMode === true" class="tagcloud">
-        <div>
-            <h3><?= _('Wertvolle Materialien entdecken!') ?></h3>
-            <?= _('Klicken Sie auf die Schlagwörter und entdecken Sie Lernmaterialien zum Thema.') ?>
-        </div>
-        <a href="" @click.prevent="backInCloud" class="back-button">
-            <studip-icon shape="arr_1left" role="clickable" :size="50"></studip-icon>
-        </a>
-        <ul class="tags clean">
-            <li v-for="tag in tags">
-                <a href="#"
-                   class="button"
-                   :style="getTagStyle(tag.tag_hash)"
-                   :title="tag.name"
-                   @click.prevent="browseTag(tag.tag_hash, tag.name)">{{"#" + tag.name}}</a>
-            </li>
-        </ul>
-    </div>
-
-</div>
-
-<div v-if="results && results.length === 0" class="oer_no_results">
-    <?= MessageBox::info(_('Keine Ergebnisse gefunden.'))?>
-</div>
-
-<ul class="results oer_material_overview" v-if="results && results.length > 0">
-    <li v-for="result in results" :key="result.material_id">
-        <article class="contentbox" :title="result.name">
-            <a :href="getMaterialURL(result.material_id)" target="_blank">
-                <header>
-                    <h1>
-                        <studip-icon :shape="getIconShape(result)"
-                                     role="clickable"
-                                     :size="20"
-                                     class="text-bottom"></studip-icon>
-                        {{ shortenName(result.name) }}
-                    </h1>
-                </header>
-                <div class="image" :style="'background-image: url(' + result.logo_url + ');' + (!result.front_image_content_type ? ' background-size: 60% auto;': '')"></div>
-            </a>
-        </article>
-    </li>
-</ul>
diff --git a/app/views/oer/market/index.php b/app/views/oer/market/index.php
index 66e1f2c47851d32067effa1fe263eb84b1c6287a..d2a1ed67dca84f2963eefed0b0c2ae40fe8f4a59 100644
--- a/app/views/oer/market/index.php
+++ b/app/views/oer/market/index.php
@@ -6,17 +6,15 @@
  * @var OERMaterial[] $new_ones
  */
 ?>
-<form class="oer_search"
-      action="<?= $controller->search() ?>"
-      method="GET" aria-live="polite"
-      data-searchresults="<?= htmlReady(json_encode($material_data)) ?>"
-      data-filteredtag="<?= htmlReady(Request::get('tag')) ?>"
-      data-filteredcategory="<?= htmlReady(Request::get('category')) ?>"
-      data-tags="<?= htmlReady(json_encode($tags)) ?>"
-      data-material_select_url_template="<?= htmlReady($controller->detailsURL('__material_id__')) ?>">
-    <?= $this->render_partial('oer/market/_searchform') ?>
-</form>
-
+<?= Studip\VueApp::create('OERSearch')
+        ->withProps([
+            'url' => $controller->link_for('oer/market/search'),
+            'search-results' => $material_data,
+            'filtered-tag' => Request::get('tag'),
+            'filtered-category' => Request::get('category'),
+            'tags' => $tags,
+            'material-select-url-template' => $controller->detailsURL('__material_id__'),
+        ])  ?>
 
 <? if (!empty($new_ones)) : ?>
     <div id="new_ones">
@@ -26,10 +24,3 @@
         </ul>
     </div>
 <? endif ?>
-
-
-
-
-
-
-<?
diff --git a/resources/assets/javascripts/bootstrap/oer.js b/resources/assets/javascripts/bootstrap/oer.js
index 2b471496a64a13ba051119b69d50593b4c974831..3adecbc8482a3c798ff6a1788ad583a2bd42eba2 100644
--- a/resources/assets/javascripts/bootstrap/oer.js
+++ b/resources/assets/javascripts/bootstrap/oer.js
@@ -1,9 +1,6 @@
 import Quicksearch from '../../../vue/components/Quicksearch.vue';
 
 STUDIP.domReady(() => {
-    if (jQuery(".oer_search").length) {
-        STUDIP.OER.initSearch();
-    }
     jQuery(".serversettings .index_server a").on("click", function () {
         var host_id = jQuery(this).closest("tr").data("host_id");
         var active = jQuery(this).is(".checked") ? 0 : 1;
diff --git a/resources/assets/javascripts/lib/oer.js b/resources/assets/javascripts/lib/oer.js
index 17f0186ad114c1d9b8ab050ff0a7ea0f249a636c..f9e175e5b84ad1f30127857799608c1f2a5e777f 100644
--- a/resources/assets/javascripts/lib/oer.js
+++ b/resources/assets/javascripts/lib/oer.js
@@ -32,212 +32,7 @@ const OER = {
         } else if (player.webkitRequestFullscreen) {
             player.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
         }
-    },
-    initSearch: function () {
-        STUDIP.Vue.load().then(({createApp}) => {
-            STUDIP.OER.Search = createApp({
-                el: ".oer_search",
-                data() {
-                    return {
-                        browseMode: false,
-                        tags: $(".oer_search").data("tags"),
-                        tagHistory: [],
-                        searchtext: "",
-                        activeFilterPanel: false,
-                        difficulty: [1, 12],
-                        category: null,
-                        results: false,
-                        material_select_url_template: $(".oer_search").data("material_select_url_template")
-                    };
-                },
-                methods: {
-                    sync_search_text: function () {
-                        this.searchtext = $(".oer_search input[name=search]").val();
-                    },
-                    triggerFilterPanel: function () {
-                        this.activeFilterPanel = !this.activeFilterPanel;
-                    },
-                    showFilterPanel: function () {
-                        this.activeFilterPanel = true;
-                    },
-                    hideFilterPanel: function () {
-                        this.activeFilterPanel = false;
-                    },
-                    clearAllFilters: function (keep_results) {
-                        this.clearCategory();
-                        this.clearDifficulty();
-                        if (this.searchtext != '') {
-                            this.searchtext = '';
-                        }
-                        $(".oer_search input[name=search]").val('');
-                        if (keep_results !== true) {
-                            this.results = false;
-                        }
-                    },
-                    clearDifficulty: function () {
-                        if ((this.difficulty[0] != 1) && (this.difficulty[1] != 12)) {
-                            this.difficulty = [1, 12];
-                        }
-                        jQuery("#difficulty_slider").slider("values", this.difficulty);
-                    },
-                    clearCategory: function () {
-                        if (this.category != null) {
-                            this.category = null;
-                        }
-                    },
-                    getIconShape: function (result) {
-                        if (result.category === "video") {
-                            return "video";
-                        }
-                        if (result.category === "audio") {
-                            return "file-audio";
-                        }
-                        if (result.category === "presentation") {
-                            return "file-pdf";
-                        }
-                        if (result.category === "elearning") {
-                            return "learnmodule";
-                        }
-                        if (result.content_type === "application/zip") {
-                            return "archive3";
-                        }
-                        return "file";
-                    },
-                    search: function () {
-                        let v = this;
-                        this.browseMode = false;
-                        $.ajax({
-                            url: STUDIP.URLHelper.getURL("dispatch.php/oer/market/search"),
-                            data: {
-                                type: this.category,
-                                difficulty: this.difficulty.join(","),
-                                search: this.searchtext
-                            },
-                            dataType: "json",
-                            success: function (output) {
-                                $("#new_ones").hide();
-                                v.results = output.materials;
-                                v.activeFilterPanel = false;
-                                $(".material_navigation").toggle(v.results.length == 0);
-                                $(".mainlist").toggle(v.results.length == 0);
-                                $(".new_ones").toggle(v.results.length == 0);
-                            }
-                        });
-                        return false;
-                    },
-                    browseTag: function (tag_hash, name) {
-                        let v = this;
-                        this.clearAllFilters(true);
-                        let tags = [];
-                        for (let i in this.tagHistory) {
-                            tags.push(this.tagHistory[i].tag_hash);
-                        }
-                        if (tag_hash && (tags.indexOf(tag_hash) === -1)) {
-                            tags.push(tag_hash);
-                        }
-                        let p = new Promise(function (resolve, reject) {
-                            $.ajax({
-                                url: STUDIP.URLHelper.getURL("dispatch.php/oer/market/get_tags"),
-                                data: {
-                                    tags: tags
-                                },
-                                dataType: "json",
-                                success: function (output) {
-                                    v.results = output.results.materials;
-                                    v.tags = output.tags;
-                                    if (tag_hash) {
-                                        v.tagHistory.push({
-                                            tag_hash: tag_hash,
-                                            name: name
-                                        });
-                                    }
-                                    if (v.tagHistory.length > 0) {
-                                        $("#new_ones").hide();
-                                    }
-                                    resolve();
-                                },
-                                error: function (jqXHR, textStatus, errorThrown) {
-                                    reject(new Error(errorThrown));
-                                }
-                            });
-                        });
-                        return p;
-                    },
-                    backInCloud: function () {
-                        if (this.tagHistory.length === 0) {
-                            this.browseMode = false;
-                            return;
-                        }
-                        this.tagHistory.pop();
-                        let tag_hash = null;
-                        let tag_name = null;
-                        if (this.tagHistory.length > 0) {
-                            tag_hash = this.tagHistory[this.tagHistory.length - 1].tag_hash;
-                            tag_name = this.tagHistory[this.tagHistory.length - 1].name;
-                        }
-                        let v = this;
-                        this.tagHistory.pop();
-                        this.browseTag(tag_hash, tag_name).then(function () {
-                            if (v.tagHistory.length === 0) {
-                                $("#new_ones").show();
-                            }
-                        });
-
-                    },
-                    getTagStyle: function (tag_hash) {
-                        return "position: relative; top: " + Math.floor(Math.random() * 15 - 15) + "px";
-                    },
-                    capitalizeFirstLetter: function (string) {
-                        return string.charAt(0).toUpperCase() + string.slice(1);
-                    },
-                    getMaterialURL: function (material_id) {
-                        return this.material_select_url_template.replace("__material_id__", material_id);
-                    },
-                    shortenName: function (name) {
-                        if (name.length > 55) {
-                            return name.substring(0, 50) + ' ...';
-                        } else {
-                            return name;
-                        }
-                    }
-                },
-                mounted: function () {
-                    this.results = $(this.$el).data('searchresults');
-                    if (this.results !== false) {
-                        $("#new_ones").hide();
-                    }
-                    if ($(this.$el).data('filteredcategory')) {
-                        this.category = $(this.$el).data('filteredcategory');
-                    }
-                },
-                updated: function () {
-                    this.$nextTick(function () {
-                        if (!jQuery("#difficulty_slider.ui-slider").length) { //to prevent an endless loop
-                            let v = this;
-                            jQuery("#difficulty_slider").slider({
-                                range: true,
-                                min: 1,
-                                max: 12,
-                                values: [v.difficulty[0], v.difficulty[1]],
-                                change: function (event, ui) {
-                                    v.difficulty = ui.values;
-                                }
-                            });
-                        }
-                    });
-                }
-            });
-        });
-
-
-        jQuery(document).on("click", function (evnt) {
-            if (!jQuery(evnt.target).is(".searchform *") && STUDIP.OER.Search) {
-                STUDIP.OER.Search.hideFilterPanel();
-            }
-        });
-
     }
 };
 
-
 export default OER;
diff --git a/resources/assets/stylesheets/scss/oer.scss b/resources/assets/stylesheets/scss/oer.scss
index 4fcb1801f1a240b7c81571d3028fea77f9d55ff4..45c9361e1607200a8ef04f4a244c9b1e5c08b363 100644
--- a/resources/assets/stylesheets/scss/oer.scss
+++ b/resources/assets/stylesheets/scss/oer.scss
@@ -275,7 +275,7 @@ ul.reviews, ol.reviews {
                 margin-left: 5px;
             }
 
-            button {
+            button[type="button"] {
                 border-right: none;
                 border-bottom: none;
                 border-top: none;
@@ -296,7 +296,7 @@ ul.reviews, ol.reviews {
             }
         }
 
-        button {
+        button[type="button"] {
             border: thin solid var(--content-color-40);
             background-color: var(--content-color-20);
             display: flex;
@@ -304,10 +304,6 @@ ul.reviews, ol.reviews {
             justify-content: center;
             width: 35px;
         }
-
-        > button {
-            margin-left: 10px;
-        }
     }
 
     .filterpanel {
diff --git a/resources/vue/components/OERSearch.vue b/resources/vue/components/OERSearch.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e3975f33179d471b5ea51c51fb7852205445f7b0
--- /dev/null
+++ b/resources/vue/components/OERSearch.vue
@@ -0,0 +1,385 @@
+<template>
+    <form class="oer_search" :action="url">
+        <div class="searchform">
+            <div class="oneliner">
+                <div class="frame">
+                    <span v-if="category != null"
+                          class="category activefilter" :title="$gettext('Aktiver Filter der Kategorie')">
+                        <span>{{ category }}</span>
+                        <a href="#"
+                           @click.prevent="clearCategory()"
+                           class="erasefilter"
+                           :title="$gettext('Filter der Kategorie entfernen')">
+                            <studip-icon shape="decline" class="text-bottom"></studip-icon>
+                        </a>
+                    </span>
+
+                    <span v-if="difficulty[0] != 1 || difficulty[1] != 12"
+                          class="niveau activefilter"
+                          title="$gettext('Aktiver Filter für das Niveau')"
+                    >
+                        {{ $gettext('Niveau') }}:
+                        <span>{{ difficulty[0] }}</span>
+                        -
+                        <span>{{ difficulty[1] }}</span>
+                        <a href="#"
+                           @click.prevent="clearDifficulty()"
+                           class="erasefilter"
+                           :title="$gettext('Filter des Niveaus entfernen')">
+                            <studip-icon shape="decline" class="text-bottom"></studip-icon>
+                        </a>
+                    </span>
+
+                    <input type="text"
+                           name="search"
+                           v-model.trim="searchtext"
+                           @focus="toggleFilterPanel(true)"
+                           @keydown.enter.prevent="search()">
+
+                    <button v-if="difficulty[0] != 1 || difficulty[1] != 12 || (category != null) || (searchtext.length > 0)"
+                            class="erase"
+                            type="button"
+                            :title="$gettext('Suchformular zurücksetzen')"
+                            @click="clearAllFilters">
+                        <studip-icon shape="decline"></studip-icon>
+                    </button>
+
+                    <button @click="toggleFilterPanel()"
+                            type="button"
+                            :title="$gettext('Suchfilter einstellen')"
+                            :class="activeFilterPanel ? 'active' : ''">
+                        <studip-icon shape="filter" :role="activeFilterPanel ? 'info_alt' : 'clickable'"></studip-icon>
+                    </button>
+
+                    <div v-if="activeFilterPanel" class="filterpanel_shadow"></div>
+
+                    <div v-if="activeFilterPanel" class="filterpanel">
+                        <div>
+                            <h3>{{ $gettext('Kategorien') }}</h3>
+                            <ul class="clean">
+                                <li>
+                                    <button class="as-link" @click.prevent="category = 'audio'">
+                                        <studip-icon :shape="category === 'audio' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon>
+                                        {{ $gettext('Audio') }}
+                                    </button>
+                                </li>
+                                <li>
+                                    <button class="as-link" @click.prevent="category = 'video'">
+                                        <studip-icon :shape="category === 'video' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon>
+                                        {{ $gettext('Video') }}
+                                    </button>
+                                </li>
+                                <li>
+                                    <button class="as-link" @click.prevent="category = 'presentation'">
+                                        <studip-icon :shape="category === 'presentation' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon>
+                                        {{ $gettext('Folien') }}
+                                    </button>
+                                </li>
+                                <li>
+                                    <button class="as-link" @click.prevent="category = 'elearning'">
+                                        <studip-icon :shape="category === 'elearning' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon>
+                                        {{ $gettext('Lernmodule') }}
+                                    </button>
+                                </li>
+                                <li>
+                                    <button class="as-link" @click.prevent="category = null">
+                                        <studip-icon shape="link-intern" class="text-bottom"></studip-icon>
+                                        {{ $gettext('Alles') }}
+                                    </button>
+                                </li>
+                            </ul>
+                        </div>
+                        <div class="level_filter">
+                            <h3>{{ $gettext('Niveau') }}</h3>
+                            <div class="level_labels">
+                                <div>{{ $gettext('Leicht') }}</div>
+                                <div>{{ $gettext('Schwer') }}</div>
+                            </div>
+                            <div class="level_numbers">
+                                <div v-for="i in 12" :key="i" style="text-align: right">
+                                    {{ i }}
+                                </div>
+                            </div>
+                            <div id="difficulty_slider"></div>
+
+                            <input type="hidden" id="difficulty" name="difficulty" value="">
+                        </div>
+                    </div>
+
+
+                    <button :title="$gettext('Suche starten')"
+                            @click.prevent="search()"
+                            @focus="toggleFilterPanel(false)"
+                            type="button"
+                    >
+                        <studip-icon shape="search"></studip-icon>
+                    </button>
+                </div>
+
+            </div>
+
+
+        </div>
+
+        <div class="browser">
+
+            <div v-if="browseMode === false" class="intro">
+                <StudipAssetImg file="oer-keyvisual-negative.svg" class="illustration responsive-hidden"></StudipAssetImg>
+                <div>
+                    <h3>{{ $gettext('Wertvolle Lernmaterialien entdecken!') }}</h3>
+                    <div class="responsive-hidden">
+                        {{ $gettext('Neue und spannende Lernmaterialien zu finden, ist ganz einfach. Mit dem Entdeckermodus können Sie nach Schlagwörtern stöbern und durch Themengebiete surfen.') }}
+                    </div>
+
+                    <div>
+                        <button class="button" @click.prevent="browseMode = true">
+                            {{ $gettext('Zum Entdeckermodus') }}
+                        </button>
+                    </div>
+                </div>
+            </div>
+
+            <div v-if="browseMode === true" class="tagcloud">
+                <div>
+                    <h3>{{ $gettext('Wertvolle Materialien entdecken!') }}</h3>
+                    {{ $gettext('Klicken Sie auf die Schlagwörter und entdecken Sie Lernmaterialien zum Thema.') }}
+                </div>
+                <a href="" @click.prevent="backInCloud" class="back-button">
+                    <studip-icon shape="arr_1left" :size="50"></studip-icon>
+                </a>
+                <ul class="tags clean">
+                    <li v-for="tag in tagCloud">
+                        <a href="#"
+                           class="button"
+                           :style="getTagStyle(tag.tag_hash)"
+                           :title="tag.name"
+                           @click.prevent="browseTag(tag.tag_hash, tag.name)"
+                        >
+                            #{{ tag.name }}
+                        </a>
+                    </li>
+                </ul>
+            </div>
+
+        </div>
+
+        <div v-if="browseMode && results && results.length === 0" class="oer_no_results">
+            <StudipMessageBox type="info" :hide-close="true">
+                {{ $gettext('Keine Ergebnisse gefunden.') }}
+            </StudipMessageBox>
+        </div>
+
+        <ul class="results oer_material_overview" v-if="results && results.length > 0">
+            <li v-for="result in results" :key="result.material_id">
+                <article class="contentbox" :title="result.name">
+                    <a :href="getMaterialURL(result.material_id)" target="_blank">
+                        <header>
+                            <h1>
+                                <studip-icon :shape="getIconShape(result)"
+                                             class="text-bottom"></studip-icon>
+                                {{ shortenName(result.name) }}
+                            </h1>
+                        </header>
+                        <div class="image" :style="`background-image: url(${result.logo_url});${!result.front_image_content_type ? ' background-size: 60% auto;' : ''}`"></div>
+                    </a>
+                </article>
+            </li>
+        </ul>
+
+    </form>
+</template>
+<script>
+import StudipMessageBox from './StudipMessageBox.vue';
+import StudipAssetImg from './StudipAssetImg.vue';
+
+export default {
+    name: 'OERSearch',
+    components: {StudipAssetImg, StudipMessageBox},
+    props: {
+        searchResults: [Array, Boolean],
+        filteredTag: String,
+        filteredCategory: String,
+        tags: Array,
+        materialSelectUrlTemplate: String,
+        toPlugin: String,
+        toFolderId: String,
+        url: {
+            type: String,
+            required: true,
+        }
+    },
+    data() {
+        return {
+            browseMode: false,
+            tagHistory: [],
+            searchtext: '',
+            activeFilterPanel: false,
+            difficulty: [1, 12],
+            category: null,
+            results: this.searchResults || false,
+        };
+    },
+    computed: {
+        tagCloud() {
+            const history = this.tagHistory.map(tag => tag.tag_hash);
+            return this.tags.filter(tag => !history.includes(tag.tag_hash));
+        }
+    },
+    methods: {
+        toggleFilterPanel(state = null) {
+            this.activeFilterPanel = state ?? !this.activeFilterPanel;
+        },
+        clearAllFilters(keep_results) {
+            this.clearCategory();
+            this.clearDifficulty();
+            this.searchtext = '';
+            if (!keep_results) {
+                this.results = false;
+            }
+        },
+        clearDifficulty() {
+            if (this.difficulty[0] != 1 && this.difficulty[1] != 12) {
+                this.difficulty = [1, 12];
+            }
+            jQuery("#difficulty_slider").slider("values", this.difficulty);
+        },
+        clearCategory() {
+            if (this.category != null) {
+                this.category = null;
+            }
+        },
+        getIconShape(result) {
+            if (result.category === 'video') {
+                return 'video';
+            }
+            if (result.category === 'audio') {
+                return 'file-audio';
+            }
+            if (result.category === 'presentation') {
+                return 'file-pdf';
+            }
+            if (result.category === 'elearning') {
+                return 'learnmodule';
+            }
+            if (result.content_type === 'application/zip') {
+                return 'archive3';
+            }
+            return 'file';
+        },
+        search() {
+            this.browseMode = false;
+            $.getJSON(STUDIP.URLHelper.getURL('dispatch.php/oer/market/search', {
+                type: this.category,
+                difficulty: this.difficulty.join(','),
+                search: this.searchtext
+            })).done(output => {
+                this.results = output.materials.length;
+                this.activeFilterPanel = false;
+
+                this.toggleElements(
+                    this.results.length === 0,
+                    '.material_navigation',
+                    '.mainlist',
+                    '#new_ones'
+                );
+            });
+        },
+        browseTag(tag_hash, name) {
+            this.clearAllFilters(true);
+            let tags = this.tagHistory.map(i => i.tag_hash);
+            if (tag_hash && !tags.includes(tag_hash)) {
+                tags.push(tag_hash);
+            }
+            return $.getJSON(STUDIP.URLHelper.getURL('dispatch.php/oer/market/get_tags', { tags })).done(output => {
+                this.results = output.results.materials;
+
+                this.$emit('update:tags', output.tags);
+
+                if (tag_hash) {
+                    this.tagHistory.push({ tag_hash, name });
+                }
+                if (this.tagHistory.length > 0) {
+                    this.toggleElements(false, '#new_ones');
+                }
+            });
+        },
+        backInCloud() {
+            if (this.tagHistory.length === 0) {
+                this.browseMode = false;
+                return;
+            }
+            this.tagHistory.pop();
+            let tag_hash = null;
+            let tag_name = null;
+            if (this.tagHistory.length > 0) {
+                tag_hash = this.tagHistory.at(-1).tag_hash;
+                tag_name = this.tagHistory.at(-1).name;
+            }
+
+            this.tagHistory.pop();
+            this.browseTag(tag_hash, tag_name).done(() =>  {
+                if (this.tagHistory.length === 0) {
+                    this.toggleElements(true, '#new_ones');
+                }
+            });
+
+        },
+        getTagStyle(tag_hash) {
+            return {
+                position: 'relative',
+                top: Math.floor(Math.random() * 15 - 15) + 'px'
+            };
+        },
+        capitalizeFirstLetter(string) {
+            return string.charAt(0).toUpperCase() + string.slice(1);
+        },
+        getMaterialURL(material_id) {
+            return STUDIP.URLHelper.getURL(
+                this.materialSelectUrlTemplate.replace('__material_id__', material_id),
+                {
+                    to_plugin: this.toPlugin,
+                    to_folder_id: this.toFolderId
+                }
+            );
+        },
+        shortenName(name, maxLength = 55) {
+            if (name.length > maxLength) {
+                return name.substring(0, maxLength - 3) + ' ...';
+            }
+
+            return name;
+        },
+        hideFilterPanelListener(event) {
+            if (!event.target.closest('.oer_search .searchform')) {
+                this.toggleFilterPanel(false);
+            }
+        },
+        toggleElements(state, ...selectors) {
+            document.querySelectorAll(selectors.join(',')).forEach(node => {
+                node.style.display = state ? '' : 'none';
+            });
+        }
+    },
+    mounted() {
+        this.toggleElements(this.results === false, '#new_ones');
+
+        document.body.addEventListener('click', this.hideFilterPanelListener);
+    },
+    beforeDestroy() {
+        document.body.removeEventListener('click', this.hideFilterPanelListener)
+    },
+    updated() {
+        this.$nextTick(() => {
+            jQuery("#difficulty_slider:not(.ui-slider)").slider({
+                range: true,
+                min: 1,
+                max: 12,
+                values: [this.difficulty[0], this.difficulty[1]],
+                change: (event, ui) => {
+                    this.difficulty = ui.values;
+                }
+            });
+        });
+    }
+};
+</script>